Priority
3 to 1のセレクタを考える。
セレクト信号は2bit必要だが、値は2'b00から2'b10までしか入力されないことが仕様上保障されているとする。
この場合、セレクト信号が2'b11の時の動作はドントケアとすることで、論理合成後の回路を最適化することが可能となる。
従来のVerilogでこの合成時のドントケアを表現するには、xを代入するか、//synthesis full_caseのような論理合成ツールへのディレクティブをコメントで挿入していた(本サイトは論理合成ツールにQuartus IIを使用するので、そのディレクティブであるsynthesis full_caseを例に挙げるが、デファクトスタンダードはDesignCompiler用のsynopsys full_case)。
以下がxを代入する時のコード例。
module multiplexer3to1_1(
output logic [1:0] out,
input logic [3:0] in0, in1, in2,
input logic [1:0] sel //This signal never takes 2'b11
);
always_comb begin
case (sel)
2'b00 : out = in0;
2'b01 : out = in1;
2'b10 : out = in2;
default : out = 'x;
endcase
end
endmodule
以下がディレクティブでのコード例。ディレクティブがない場合、条件が足りないのでラッチを生成する記述になっている点に注意。
module multiplexer3to1_2(
output logic [1:0] out,
input logic [3:0] in0, in1, in2,
input logic [1:0] sel //This signal never takes 2'b11
);
always_comb begin
case (sel) //synthesis full_case
2'b00 : out = in0;
2'b01 : out = in1;
2'b10 : out = in2;
endcase
end
endmodule
xを代入する場合は、通常のシミュレーションではその行は実行されることがないため、検証時のコードカバレッジが下がってしまう。
ディレクティブで指定する場合は、あくまでコメントであるため、スペルミスにきづきにく、確認は論理合成のレポートを見なければならない。
また、どちらにしても周辺回路の仕様を誤って、万が一2'b11が入ってきた場合の検出用コードはユーザが別途記述しなければならないという使いにくさがあった。
SystemVerilogでは、priorityにより、上記動作を言語仕様レベルでサポートしている。priority caseでは、その後ろに記述された以外の条件は発生しないことを意味する。
以下にpriorityの使用例をテストコード付きで示す。
module test3();
wire [3:0] out;
reg [1:0] sel;
multiplexer3to1_3 mux(.out(out),
.in0(4'h7), .in1(4'h8), .in2(4'h9), .sel(sel));
initial begin
sel = 2'b00; #5 $display("out = %b", out);
#5 sel = 2'b01; #5 $display("out = %b", out);
#5 sel = 2'b10; #5 $display("out = %b", out);
#5 sel = 2'b11; #5 $display("out = %b", out);
#5 $finish();
end
endmodule
module multiplexer3to1_3(
output logic [3:0] out,
input logic [3:0] in0, in1, in2,
input logic [1:0] sel //This signal never takes 2'b11
);
always_comb begin
priority case (sel)
2'b00 : out = in0;
2'b01 : out = in1;
2'b10 : out = in2;
endcase
end
endmodule
このマルチプレクサに2'b11を入力すると、以下のようにシミュレータがランタイム時にWarningを通知する。
# 6.5e
# vsim -do {run -all; quit} -c test3
# Loading sv_std.std
# Loading work.test3
# Loading work.multiplexer3to1_3
# run -all
# out = 0111
# out = 1000
# out = 1001
# ** Warning: (vsim-8315) test3.sv(27): No condition is true in the unique/priority if/case statement.
# out = 1001
priorityはifとの組み合わせも同様に使用できる。上記例をifに書き直すと、以下のようになる。ただし、残念ながら現在のところQuartus IIではサポートされていない。
module multiplexer3to1_4(
output logic [3:0] out,
input logic [3:0] in0, in1, in2,
input logic [1:0] sel //This signal never takes 2'b11
);
always_comb begin
priority if (sel == 2'b00)
out = in0;
else if (sel == 2'b01)
out = in1;
else if (sel == 2'b10)
out = in2;
end
endmodule
なお、なぜかpriorityという名前がついているが、その動作は、上述したように、記述した条件式が実使用上のすべての条件を満たすことを示している。ifにしてもcaseにしても、verilogでは、もともと上の行に記述されるほど優先順位が高い仕様となっている(蛇足だが、この点でcaseの仕様はC言語のそれと異なるのに注意が必要)。