Unique
Verilogでは、ifやcaseでは、最初に記述された条件のほうの優先度が高い。
以下のコードでは、selの複数ビットが同時に1'b1になった場合は、上に記述されている条件が優先される。これは、合成時にもそのような優先付けをするようなロジックが挿入されることを意味する。
module test1();
wire [3:0] out;
reg [3:0] sel;
multiplexer4to1_1 mux(.out(out),
.in0(2'd0), .in1(2'd1), .in2(2'd2), .in3(2'd3),
.sel(sel));
initial begin
for (sel = 0;; sel++) begin
#5 $display("sel = %4b, out = %x",sel, out);
#5 if (sel == 4'b1111) break;
end
$finish();
end
endmodule
module multiplexer4to1_1(
output logic [3:0] out,
input logic [1:0] in0, in1, in2, in3,
input logic [3:0] sel
);
always_comb begin
case (1'b1)
sel[0] : out = in0;
sel[1] : out = in1;
sel[2] : out = in2;
sel[3] : out = in3;
endcase
end
endmodule
# 6.5e
# vsim -do {run -all; quit} -c test1
# Loading sv_std.std
# Loading work.test1
# Loading work.multiplexer4to1_1
# run -all
# sel = 0000, out = x
# sel = 0001, out = 0
# sel = 0010, out = 1
# sel = 0011, out = 0
# sel = 0100, out = 2
# sel = 0101, out = 0
# sel = 0110, out = 1
# sel = 0111, out = 0
# sel = 1000, out = 3
# sel = 1001, out = 0
# sel = 1010, out = 1
# sel = 1011, out = 0
# sel = 1100, out = 2
# sel = 1101, out = 0
# sel = 1110, out = 1
# sel = 1111, out = 0
設計上selは常にどこか1bitだけが1で、他は0であることが保障されている場合は、優先付けロジックは必要ない。Verilogではこれに対する言語としてのサポートは無く、//syntheris parallel_case full_caseというディレクティブをコメントとしてつけていた(本サイトは論理合成ツールにQuartus IIを使用するので、そのディレクティブであるsynthesis parallel_case full_caseを例に挙げるが、デファクトスタンダードはDesignCompiler用のsynopsys parallel_case full_case)。
module multiplexer4to1_2(
output logic [3:0] out,
input logic [1:0] in0, in1, in2, in3,
input logic [3:0] sel
);
always_comb begin
unique case (1'b1) //synthesis parallel_case full_case
sel[0] : out = in0;
sel[1] : out = in1;
sel[2] : out = in2;
sel[3] : out = in3;
endcase
end
endmodule
このディレクティブは、シミュレータとしてはあくまでコメントになるため、複数のビットが立った場合の動作が、RTLと合成後のネットリストで異なったものになってしまうという問題があった。また、このため、RTLとネットリストの等価性検証にも注意が必要となる。
SystemVerilogでは、uniqueにより、ディレクティブに頼らずにワンホットのcaseを記述することができる。
uniqueにより、caseの条件は常にいずれか一つのみに一致することを意味する。
module test3();
wire [3:0] out;
reg [3:0] sel;
reg clk;
multiplexer4to1_3 mux(.out(out),
.in0(2'd0), .in1(2'd1), .in2(2'd2), .in3(2'd3),
.sel(sel));
initial begin
sel = 4'b0001; #5 $display("out = %x", out);
#5 sel = 4'b0010; #5 $display("out = %x", out);
#5 sel = 4'b0100; #5 $display("out = %x", out);
#5 sel = 4'b1000; #5 $display("out = %x", out);
#5 sel = 4'b0000; #5 $display("out = %x", out);
#5 sel = 4'b1001; #5 $display("out = %x", out);
$finish();
end
endmodule
module multiplexer4to1_3(
output logic [3:0] out,
input logic [1:0] in0, in1, in2, in3,
input logic [3:0] sel
);
always_comb begin
unique case (1'b1)
sel[0] : out = in0;
sel[1] : out = in1;
sel[2] : out = in2;
sel[3] : out = in3;
endcase
end
endmodule
複数の条件に一致した場合や、いずれの条件にも一致しなかった場合は、以下のようにシミュレーション実行時にWarningが出力される。
# 6.5e
# vsim -do {run -all; quit} -c test3
# Loading sv_std.std
# Loading work.test3
# Loading work.multiplexer4to1_3
# run -all
# out = 0
# out = 1
# out = 2
# out = 3
# ** Warning: (vsim-8315) test3.sv(28): No condition is true in the unique/priority if/case statement.
# out = 3
# ** Warning: (vsim-8360) test3.sv(28): The if/case statement is not unique.
# out = 0
uniquieはifと組み合わせても使用できる。以下に、ifを使用した上記と等価なコードを示す。ただし、今のところ、残念ながらQuartus IIではサポートされていない。
module multiplexer4to1_4(
output logic [3:0] out,
input logic [1:0] in0, in1, in2, in3,
input logic [3:0] sel
);
always_comb begin
unique if (sel[0]) out = in0;
else if (sel[1]) out = in1;
else if (sel[2]) out = in2;
else if (sel[3]) out = in3;
end
endmodule
caseにしても、ifにしても、実際の設計ではいずれか一つの条件にしか一致しないもののことが多いと思う。そのような場合にはuniqueを使用することで、効率の良い論理合成結果と、シミュレータによる違反の自動チェックの恩恵が得られる。使える場所では積極的に使っていきたい機能だ。