web-dev-qa-db-ja.com

Verilogでブロッキングと非ブロッキングの割り当てを解釈するにはどうすればよいですか?

ハードウェアダイアグラムの描画に関して、ブロッキング割り当てと非ブロッキング割り当てがどのように解釈されるかについて少し混乱しています。非ブロッキング割り当てがレジスターを提供すると推測する必要がありますか?次に、このステートメントc <= a+b、cはレジスタ権ですが、aとbではありませんか?

module add (input logic clock,  
output logic[7:0] f);   

logic[7:0] a, b, c;  

always_ff @(posedge clock)  
begin   
  a = b + c;   
  b = c + a;   
  c <= a + b;  
end   

assign f = c;  

endmodule
26
infinitloop

最初にブロック割り当てと非ブロック割り当ての違いを理解するのは間違いなく少し注意が必要です。しかし、恐れることはありません。便利な経験則があります。

alwaysブロックを使用してコンボロジックを推測する場合は、ブロック割り当て(=)を使用します。シーケンシャルロジックが必要な場合は、クロックなしのalwaysブロックと非ブロック割り当て(<=)を使用します。そして、2つを混ぜないようにしてください。

上記のコードはおそらく最良の例ではありません。構築しようとした加算器/フリップフロップの構造がわからない場合、コンボフィードバックパス(悪い)が存在する危険があります。また、入力バスがないため、基本的にはabcを空中で構築しようとしています!

ただし、質問に答えるために、クロック付きalwaysブロック内で割り当てられた変数は、ブロック演算子(=)を使用して割り当てられ、一種のローカル変数として使用されない限り、フリップフロップを推測します。

module add
  (
   input clock,
   input [7:0] in1,
   input [7:0] in2,
   output logic [7:0] f1, f2, f3, f4, f5
   );   


   // f1 will be a flipflop
   always_ff @(posedge clock) begin
      f1 = in1 + in2;
   end


   // f2 will be a flipflop
   always_ff @(posedge clock) begin
      f2 <= in1 + in2;
   end


   // f3 will be a flipflop
   // c1 will be a flipflop
   logic [7:0] c1;
   always_ff @(posedge clock) begin
      c1 <= in1 + in2;
      f3 <= c1 + in1;
   end


   // f4 will be a flipflop
   // c2 is used only within the always block and so is treated
   // as a tmp variable and won't be inferred as a flipflop
   logic [7:0] c2;
   always_ff @(posedge clock) begin
      c2 = in1 + in2;
      f4 = c2 + in1;
   end


   // c3 will be a flipflop, as it's used outside the always block
   logic [7:0] c3;
   always_ff @(posedge clock) begin
      c3 = in1 + in2;
   end

   assign f5 = c3 + in1;

endmodule

経験則に従い、alwaysブロック内でブロック割り当てと非ブロック割り当てを混在させないことの大きな理由は、割り当てを混在させると、RTLシムとゲートシム/実際のハードウェア操作の間でシミュレーションの不一致が深刻になる可能性があるためです。 Verilogシミュレータでは、=<=の扱いがまったく異なります。割り当てのブロックとは、「この瞬間に変数に値をすぐに割り当てる」ことを意味します。ノンブロッキング割り当てとは、「この変数に何を割り当てるかを考え出し、それを保存して将来のある時点で割り当てる」ことを意味します。これをよりよく理解するために読むのに適した紙は次のとおりです。また、以下を参照してください: http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf

28
Marty

従来のVerilogの知恵には、すべての誤りがあります。 local変数にブロック割り当てを使用しても問題はありません。ただし、同期通信ではブロッキング割り当てを使用しないでください。これは非決定的であるためです。

クロックされたalwaysブロック内の非ブロッキング割り当ては、セマンティクスで規定されているように、常にフリップフロップを推論します。

クロックされた常にブロック内のブロッキング割り当てがフリップフロップを推測するかどうかは、それがどのように使用されるかに完全に依存します。変数が割り当てられる前に読み取られる可能の場合、フリップフロップが推定されます。それ以外の場合、これは一時変数のようなものであり、いくつかの組み合わせロジックが発生します。

43
Jan Decaluwe

Jan Decaluweの回答に追加したいだけです。実際、Jan Decaluweの説明を実際に使用しているコードは、完全に正しいにもかかわらず、実際にはごくわずかしか存在しないようです。カミングス氏のおかげで、ブロックと非ブロックのステートメントを混在させることはタブーになりました。

問題は、ほとんどの場所でローカル変数のブロッキングステートメントの使用が回避されており、Googleの直接の検索スペースに、それがどのように行われるかの例を示すコードがほとんどないことです。 Janが述べたコーディングスタイルを見つけた唯一の場所は この記事で優勝したコード です。そして、これは偶然出会った

2
Akaberto

これも苦労しました。

ただし、最初に、ノンブロッキングまたはブロッキングは、実際にはラッチ/ ffが作成されるかどうかとは関係がないことを理解する必要があります。

それらの違いについては、この時点でそれを簡単に(最初から)理解できます。ブロッキングを使用する場合、LHSに割り当てられた値をブロックするまで、それ以降のセンテンスは実行できませんでした。変数が使用される場合、LHSに変更されたものが更新されて使用される可能性があるためです。ただし、非ブロックの場合は、次の文と並行するように次の文をブロックしません(実際にはRHS計算を最初に行う必要がありますが、問題ではないので、混乱した場合は無視してください)。 LHSは、今回の実行では変更/更新されません(常に再度トリガーされたブロック時に次回更新されます)。次の文は、実行サイクルの最後に更新された古い値を使用しています。

_a = 0; b= 0;
a = 1;
b = a;
--> output a = 1, b = 1;
a = 0; b= 0;
a <= 1;
b = a;
--> output a = 1, b = 0;
_

重要なポイントの1つは、コード(常にブロック)で、値が割り当てられていないが発生する可能性があるケース変数があるかどうかを見つけることです。値を渡さずにその場合は、値を保持するためにラッチ/ FFが作成されます。

例えば、

_always @(*) begin
    if(in) out = 1;
    else out = 0;
end
--> this end without latch/ff
always @(*) begin
    if(in) out = 1;
end
--> this end with one latch/ff to keep value when in = 0, as it might happen and you didn't assign value to out as in=1 do. 
_

以下もラッチ/ ffを作成する可能性があります:

_always @(*) begin
    if(in) a = 1;
    else b = 1;
end
_

->ラッチ/ ffsは、in = 1、b割り当てなし、in = 0 a割り当てなしで作成されます。

さらに、clk always @(posedge clk)のポージングを感知すると、ラッチ/ FFで終了するようにバインドされます。 clkの場合、負のエッジが存在する必要があり、何もしないため、古い値をすべて保持するためにラッチ/ ffが作成されます。

1
Steve

私はあなたの質問に答えることができますが、これには1つの論文が最適だと思うので、クリフォードカミングスのこの論文を読むことをお勧めします。それはあなたのすべての疑問をクリアし、それに加えてあなたのベリログの理解を強化します。

http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA_rev1_2.pdf

0
Karan Shah

あなたが書いた同じコードがゲートレベルで変換される場合に何が起こるかを理解する必要があるだけで、デジタルドメインで常にverilogを解釈できます、私はseqでノンブロッキングを使用するか、組み合わせてブロッキングを使用するというルールに個人的に従わないでください、これはあなたの思考を制限します。コードのデジタル側にこだわるのはここだけです。コードがゲートレベルに変換されるとどうなるかは、これだけが必要かどうかを確認してください。

  1. 最初に全加算器が作成されます-入力aおよびb
    1. 出力はフリップフロップに行き、clkと同期する出力を作成します
    2. 割り当てがブロックされているので、新しいaは次にこの新しいaとcをinputとして持つ次のフルに適用され、その出力はdffcsyncに移動してclkで新しいbを作成します
    3. 今、b = c + a;ブロック文があるので、bはこの新しいbに更新されます
    4. ここで、c <= a + bとなると、aとbを入力として使用して全加算器が作成され、clkへのdff同期が行われます。
    5. 次に、非ブロッキングステートメントで作成された新しいものではなく、古いcを持つdffが作成され、このdff同期のclkへの出力がaに送られ、aが更新されます。

ラフル・ジャインよろしくお願いします

0
Rahul Jain