ハードウェアダイアグラムの描画に関して、ブロッキング割り当てと非ブロッキング割り当てがどのように解釈されるかについて少し混乱しています。非ブロッキング割り当てがレジスターを提供すると推測する必要がありますか?次に、このステートメント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
最初にブロック割り当てと非ブロック割り当ての違いを理解するのは間違いなく少し注意が必要です。しかし、恐れることはありません。便利な経験則があります。
always
ブロックを使用してコンボロジックを推測する場合は、ブロック割り当て(=
)を使用します。シーケンシャルロジックが必要な場合は、クロックなしのalways
ブロックと非ブロック割り当て(<=
)を使用します。そして、2つを混ぜないようにしてください。
上記のコードはおそらく最良の例ではありません。構築しようとした加算器/フリップフロップの構造がわからない場合、コンボフィードバックパス(悪い)が存在する危険があります。また、入力バスがないため、基本的にはa
、b
&c
を空中で構築しようとしています!
ただし、質問に答えるために、クロック付き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
従来のVerilogの知恵には、すべての誤りがあります。 local変数にブロック割り当てを使用しても問題はありません。ただし、同期通信ではブロッキング割り当てを使用しないでください。これは非決定的であるためです。
クロックされたalwaysブロック内の非ブロッキング割り当ては、セマンティクスで規定されているように、常にフリップフロップを推論します。
クロックされた常にブロック内のブロッキング割り当てがフリップフロップを推測するかどうかは、それがどのように使用されるかに完全に依存します。変数が割り当てられる前に読み取られる可能の場合、フリップフロップが推定されます。それ以外の場合、これは一時変数のようなものであり、いくつかの組み合わせロジックが発生します。
Jan Decaluweの回答に追加したいだけです。実際、Jan Decaluweの説明を実際に使用しているコードは、完全に正しいにもかかわらず、実際にはごくわずかしか存在しないようです。カミングス氏のおかげで、ブロックと非ブロックのステートメントを混在させることはタブーになりました。
問題は、ほとんどの場所でローカル変数のブロッキングステートメントの使用が回避されており、Googleの直接の検索スペースに、それがどのように行われるかの例を示すコードがほとんどないことです。 Janが述べたコーディングスタイルを見つけた唯一の場所は この記事で優勝したコード です。そして、これは偶然出会った
これも苦労しました。
ただし、最初に、ノンブロッキングまたはブロッキングは、実際にはラッチ/ 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つの論文が最適だと思うので、クリフォードカミングスのこの論文を読むことをお勧めします。それはあなたのすべての疑問をクリアし、それに加えてあなたのベリログの理解を強化します。
http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA_rev1_2.pdf
あなたが書いた同じコードがゲートレベルで変換される場合に何が起こるかを理解する必要があるだけで、デジタルドメインで常にverilogを解釈できます、私はseqでノンブロッキングを使用するか、組み合わせてブロッキングを使用するというルールに個人的に従わないでください、これはあなたの思考を制限します。コードのデジタル側にこだわるのはここだけです。コードがゲートレベルに変換されるとどうなるかは、これだけが必要かどうかを確認してください。
ラフル・ジャインよろしくお願いします