4

データパス回路にFSMコントローラーを実装しています。コントローラは内部でカウンタをインクリメントします。以下のプログラムをシミュレートしたとき、カウンターは更新されませんでした。

reg[3:0] counter;

//incrementing counter in combinational block
counter = counter + 4'b1;

ただし、 Verilogのベストプラクティス-変数をインクリメントし、シーケンシャルブロックでのみカウンターをインクリメントするで説明されているように、追加の変数counter_nextを作成すると、カウンターがインクリメントされます。

reg[3:0] counter, counter_next;

//sequential block
always @(posedge clk) 
   counter <= counter_next;

//combinational block
counter_next = counter + 4'b1;

前のケースでカウンターがインクリメントされないのはなぜですか?足りないものはありますか?

4

1 に答える 1

9

Ok。コンパイルすらすべきではないので、最初の例からいくつかのコードを除外したと思います。しかし、とにかく問題を解明できると思います。

次のようなブロックで:

always @(*) begin // or always @(counter)
    counter = counter + 4'b1;
end

2つの問題があります。

1)カウンタは初期化されません。すべての「reg」型変数はシミュレーション時間の開始時にXであるため、Xに1を加算するとXになります。

2)これは組み合わせループと見なされるものです。ブロックは「counter」の変化に敏感であるため、「counter」が0に初期化されたとしても、シミュレーターは「counter」を更新して永久ループし、シミュレーション時間は決して進みません。すなわち

always block executes -> counter = 1
counter has changed
always block executes -> counter = 2
counter has changed
and so on...

そこに$displayステートメントを入れると、このループが発生していることがわかります。それ以外の場合は、シミュレーターがハングしているように見え、ウェーブは書き込まれません。

2番目の例が機能する理由は、組み合わせループを壊すフリップフロップがあるためです。各クロックエッジで、「counter」は「counter_next」の現在の値で更新されます。次に、組み合わせブロックが1回(そして1回だけ)実行されて、「counter_next」の新しいバージョンが計算されます。

完全を期すために、reset句または初期ステートメントによる「counter」の初期化がまだ不足しています。

reg [3:0] counter;
reg [3:0] counter_next;

always @(*) begin
   counter_next = counter + 1;
end

always @(posedge clk or negedge rst_l) begin
   if (!rst_l)
      counter <= 4'b0;
   else
      counter <= counter_next;
end
于 2012-12-29T21:12:25.003 に答える