12 |
BSV(Bluespec SystemVerilog) |
BSV(Bluespec SystemVerilog)の注意点
Verilogコードで以下のような回路を設計することを考えます。
reg [31:0] burst_count, dest_burst_size ; reg burst_in_progress ; ... always @(posedge clk) // burst_in_progress_stop begin if (burst_in_progress && (burst_count==dest_burst_size)) burst_in_progress <= False; ... end always @(posedge clk) // burst_count; begin burst_count <= burst_in_progress ? burst_count+1 : 0; ... end
2個の同期FFグループがあり、最初のFFでは、バースト転送中信号を作成しています。初期状態が不定ですが、なんらかの信号によりburst_in_progressがtrue(=バースト転送中)を示した後は、基本的にバーストを継続します。バーストカウントが規定されたサイズだけ転送したら、バースト転送中をfalseにしてバースト転送を停止させます。
次のFFグループはバーストカウントを計算するFFであり、バースト転送中がtrueの時は1クロック毎に+1だけカウントし、バースト転送中がfalseになったらカウントを0にします。
図220.1に、このverilogコードを図示します。
このコードはBSVでは以下のようになりそうです。
Reg#(Data_t) dest_burst_size <- mkReg (32'h0) ; Reg#(Data_t) burst_count <- mkReg (0) ; Reg#(Bool) burst_in_progress <- mkReg (False) ; rule burst_in_progress_stop (burst_in_progress && (burst_count==dest_burst_size)); burst_in_progress <= False; ... endrule rule burst_counting ; burst_count <= burst_in_progress ? burst_count + 1 : 0; ... endrule
ところが、これは最初のruleにおいてburst_countがreadされ、burst_in_progressがwriteされます。一方、2番目のruleにおいて、burst_in_progressがreadされ、burst_countがwriteされます。ruleをスキャンする順番により競合が起きます。
これは、ルールが同時に発火するのではないため、順番によって結果が異なるためです。これを避けるには、一つのruleの中に入れれば良いとのことです。このようにすれば変更の同時性が保証されるため、正しく直前のデータを参照することになります。
Reg#(Data_t) dest_burst_size <- mkReg (32'h0) ; Reg#(Data_t) burst_count <- mkReg (0) ; Reg#(Bool) burst_in_progress <- mkReg (False) ; rule burst_in_progress_stop (burst_in_progress) ; burst_in_progress <= burst_count != dest_burst_size ; burst_count <= (burst_count != dest_burst_size) ? burst_count+1 : 0; ... endrule