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