module for_loop_test;
initial begin
for (int i=0;i< 3;i++) $display("i=%d",i);
end
endmodule
module top;
parameterint N=3;
for (genvar g=0; g< N; g++) for_loop_test dut();
endmodule
module for_loop_test;
initial begin
$display("%m");
for (int i=0;i< 3;i++) $display("i=%d ",i);
end
endmodule
ですから、
func(a++) + func(a++);
は、a=4だった場合、 func(4) + func(5) か、func(5)+ func(4)、あるいは、func(4)+func(4)かは、実装依存です。この場合の副作用完了点は、;です。
賢いコンパイラは、警告を出してくれますが、現状、VeritakSV含め、警告しないコンパイラの方が多いと思います。
前置インクリメント 後置インクリメント
i++; ++i; のように、 単項=statement である場合は、動作の違いはありません。
j=++i ;の場合、インクリメントした値が評価値として代入されます。インクリメント動作は、式が完了する;前に行われます。
j=i++;の場合、インクリメントする前の値が評価値として代入されます。インクリメント動作は、式が完了する;前に行われます。
$display("\nundefined result: i=%d i=%d",i++,i++);
は、結果は、実装依存になりますが、C言語仕様上は、未定義動作なので、同一Versionの最適化有りなしで値が変わったとしても、文句を言えません。(SV LRMには、この辺に関する詳しい記述は、ありません。SystemVerilog
includes the C increment and decrement assignment operators ++i, --i, i++,
and i--. )
module incremental_test;
int i,j;
initial begin
i++;//単項Statementの場合
++i;//ポスト・プリの 違いはありません
j=++i;
$display("pre-inc result: j=%d i=%d",j,i);
j=i++;
$display("post-inc result: j=%d i=%d",j,i);
$display("\nundefined result: i=%d i=%d",i++,i++);//未定義
$display("undefined result: i=%d i=%d",i,i);//未定義結果
i=2;
$display("\npre increment");
while (++i <4) begin
$display("i=%d",i);
end
i=2;
$display("post increment");
while (i ++<4) begin
$display("i=%d",i);
end
end
endmodule
SystemVerilog上での注意点
++ の動作としては、ブロッキングアサイン=になります。
ここで、問題です。次の4つの記述スタイルで、推奨されるスタイルは、何でしょうか?
module incremental_test; int i,j; bit [31:0] c1,c2,c3,c4; bit clock=0; always @(posedge clock) begin c1<=c1+1; end always @(posedge clock) begin c2<=++c2; end always @(posedge clock) begin c3<=c3++; end always @(posedge clock) begin c4++; end initial begin repeat(10) begin #10; clock=~clock; end $display("c1=%2d c2=%2d c3=%2d c4=%2d",c1,c2,c3,c4); $finish; end endmodule
c3 が0になったのを除いて、すべて同じ値になりましたが、推奨される記述スタイルは、結局、従来通りのc1
だけでしょう。
c4は、ブロッキングアサインなので、ノンブロッキング動作<=ではありません。レースを生む可能性があります。
c2<=++c2 は、よくよく検討すると問題なさそうですが、そんなことで悩むよりは、HW記述では使わないと決めておいたほうがよさそうです。
次の例は、やってしまいそうな記述です。注意しましょう。
always_ff @(posedge clock) begin if (!reset) counter<=0; else counter++; end
速度の差異
前置演算と後置演算で、シミュレーション速度の差異は、あるのでしょうか? VeritakSV実装の話になりますが、++i;
--i; 等の単項演算では、最適化が容易で違いはありません。そうでない場合は、後置演算の方が遅くなります。後置演算では、値のコピー作業が必要になるため、その分遅くなります。