verilog: 入力信号に同期してカウントアップ

先日、入力信号xが何個入ったのかを数える必要があった。
1.
reg cnt;
always @(posedge clk) begin
    cnt <= x ? cnt+1 : cnt;
end

このようであってもよいのだが、cntが増えるのはxがhighになってから1クロック後だ。ずれてしまう。

x:    0001000
cnt: 0000111

このようになる。ちなみに、初期化を書いていないので、最初はcntが不定値xになっていることに注意されたい。実際にソースコードを実行するときは、
initial cnt = 0;
のようなシミュレーションレベルでの初期可が要る (initial文は論理合成の対象にはならないことに注意)。

2. 
カウンターの遅延が許されない場合、このように書くと遅延がなくなってよい

always @(posedge clk or posedge x) begin
    cnt <= x ? cnt+1 : cnt;
end

でも、何だか違和感がある。ダサい。非同期型の信号が入ってくるみたいだ。wireをassignすれば遅延はないけど、値を保持できない。うーん。

3.
別の変数を持ち出すことで、@内をクロックのみにできる。先ほどまでのcntをcnt_supportという変数名に変える。

reg cnt_support
wire cnt

always @(posedge clk) begin
    cnt_support <= x ? cnt_support + 1 : cnt_support;
end

assign cnt = x + cnt_support;

若干わかりにくくなったが、cnt_supportが1クロック遅れているので、そこにxを足すことで遅延を補っている。伝わるかな。やはり、苦肉の策だ。でも、他にいい方法がないので、今はこれを使っている。

x cnt_support cnt
0 0 0
1 0 1
0 1 1
0 1 1
1 1 2
0 2 2
0 2 2

このように動く。真ん中、左の2列を足せば、右の列が出来上がるのがわかるだろう。

コメント