Always_comb
allways_combは、その動作が常に組み合わせ回路のを意図していることを表す。
従来のalwaysで組み合わせ回路を表現する時との違いは以下の通り。
センシティビティーリストが無い
常に組み合わせ回路の動作をし、ラッチやFFの動作にならないことをシミュレータ/コンパイラに知らせる
特に、面倒なセンシティビティーリストを書かなく良いのはうれしい(同様なことはVerilog2001のalways @(*)でも実現できるが)。
always_combは、既存のalwaysとの違いは上記の通りなので、記述方法に迷うことはないだろう。
ところで、本機能への対応は、シミュレータや合成ツールでかなりばらついているので注意が必要だ。
以下の例を見てみよう。コメントアウトされた不完全なifにより、組み合わせ回路としては不適切な記述となっている。
module test();
reg [1:0] sel;
wire [7:0] out;
initial begin
sel = 2'b11;
do begin
sel = sel + 1;
#10 $display("sel = %2b, out = %x", sel, out);
end while (sel != 2'b11);
$finish();
end
duv duvIns(.out(out), .sel(sel));
endmodule // test
module duv(
output reg [7:0] out,
input [1:0] sel);
always_comb begin
if (sel == 2'b00) out = 8'h55;
else if (sel == 2'b01) out = 8'haa;
else if (sel == 2'b10) out = 8'hff;
// else out = 8'h00;
end
endmodule // duv
ModelSim上ではラッチの動作をし、エラーメッセージ等も表示されない。
# 6.5e
# vsim -do {run -all; quit} -c test
# Loading sv_std.std
# Loading work.test
# Loading work.duv
# run -all
# sel = 00, out = 55
# sel = 01, out = aa
# sel = 10, out = ff
# sel = 11, out = ff
一方、Quartus IIでは、合成時に以下のようなエラーが表示される。
Error (10166): SystemVerilog RTL Coding error at test.sv(23): always_comb construct does not infer purely combinational logic
次に、先ほどのalways_combを以下のように書き換えてみよう。今度は、全ての条件を網羅しているので、エラーは出ないはずだ。
always_comb begin
if (sel == 2'b00) out = 8'h55;
else if (sel == 2'b01) out = 8'haa;
else if (sel == 2'b10) out = 8'hff;
else if (sel == 2'b11) out = 8'h00;
end
ModelSimでは、期待通りの動作をする。
# 6.5e
# vsim -do {run -all; quit} -c test2
# Loading sv_std.std
# Loading work.test2
# Loading work.duv
# run -all
# sel = 00, out = 55
# sel = 01, out = aa
# sel = 10, out = ff
# sel = 11, out = 00
ところがQuartus IIでは、この記述でも同じようにエラーを出力する。おそらく、selにxやzが代入されている時の条件が網羅されていないせいなのだろうが、合成には無関係なので、ここは組み合わせ回路を合成してほしいところだ。事実そのように動作する合成ツールも存在する。
この他にも、最初の記述例でWarningを出すもののラッチを生成する合成ツールや、同様にWarningを出すのみで、ラッチの動作を行うシミュレータ等、ツール毎に対応が分かれているのが現状のようだ。
将来これらの動作に一貫性がとられることを期待するが、当面のところ、一番安全側に振って、以下のような対応をお勧めする。
always_combを使ったからといって、ラッチが生成されないことを期待しない。常に合成後のレポートでラッチがないことを確認する
always_comb内でifを使う場合はelse ifではなく、elseで終わらせる。同様にcaseにもdefaultを必ず指定する