The words unique, unique0 and priority prefix case or if with a checked claim. The simulator verifies it on every evaluation, and synthesis uses it to pick cheaper hardware.
One keyword drives both tools, so the claim cannot drift the way comment pragmas did.
Qualifier | Claim | Violation when |
|---|---|---|
| Exactly one branch matches | Zero match or more than one |
| At most one branch matches | More than one (no-match is fine) |
| At least one matches; order decides overlaps | Zero match |
Synthesis: | Branches are exclusive | Builds a parallel mux |
Synthesis: | Coverage holds | Keeps the priority chain, no latch |
unique needs exactly one match. unique0 drops the coverage half for cases with a default assignment before them. priority needs coverage and lets order decide overlaps.
full_case and parallel_case were synthesis-only comments. Simulation modeled priority while gates assumed exclusivity, and silicon paid the difference.
unique case and priority case carry the same intent where the simulator watches. A wrong claim prints a warning in regression instead of escaping to the lab.
// snippet
logic [1:0] sel_q;
logic [7:0] a_q, b_q, y_old, y_new;
// OLD (dangerous): claim visible only to synthesis
always @(*) begin
case (sel_q) // synopsys parallel_case full_case
2'b01: y_old = a_q;
2'b10: y_old = b_q;
endcase
end
// NEW: the simulator checks the claim on every evaluation
always_comb begin
unique case (sel_q)
2'b01: y_new = a_q;
2'b10: y_new = b_q;
2'b00, 2'b11: y_new = '0;
endcase
endA violation is a warning by default. Promote these warnings to errors in regression flows, or they scroll past unread.
Combinational settling can print extra warnings in some tools even when the settled value is legal. Treat that noise as tool-dependent and confirm against settled values.
A unique decoder and a priority selector face all 12 legal patterns and must agree with a plain reference.
module uniq_dec (
input logic [1:0] sel,
output logic [3:0] onehot
);
always_comb begin
onehot = 4'b0000;
unique case (sel)
2'b00: onehot = 4'b0001;
2'b01: onehot = 4'b0010;
2'b10: onehot = 4'b0100;
2'b11: onehot = 4'b1000;
endcase
end
endmodule
module prio_sel (
input logic nmi,
input logic tmr,
input logic sw,
output logic [1:0] vec
);
always_comb begin
vec = 2'd0;
priority if (nmi) vec = 2'd3;
else if (tmr) vec = 2'd2;
else if (sw) vec = 2'd1;
else vec = 2'd0;
end
endmodule
PASS: unique decode and priority select agree on all 12 patternsunique but has no item for 2'b11. The bench drives 2'b11. What happens?The simulator reports the broken claim at that moment. Icarus prints a warning and carries on; Verilator treats it as a failed assertion and stops the run.
module gap_dec (
input logic [1:0] sel,
output logic [3:0] onehot
);
always_comb begin
onehot = 4'b0000;
unique case (sel) // claim: exactly one item matches
2'b00: onehot = 4'b0001;
2'b01: onehot = 4'b0010;
2'b10: onehot = 4'b0100;
endcase // 2'b11 is missing: the claim is false
end
endmodule
module tb_unique_violation;
logic [1:0] sel;
logic [3:0] onehot;
gap_dec dut (.*);
initial begin
sel = 2'b01; #1;
$display("sel=01 onehot=%b", onehot);
sel = 2'b11; #1; // matches nothing: the simulator reports it
$display("sel=11 onehot=%b", onehot);
$display("PASS: the legal selector decoded, and the illegal one was reported above");
$finish;
end
endmodulesel=01 onehot=0010
WARNING: /var/folders/41/dgs80y1569b4x8pwflv_w9jr0000gn/T/rtbtb-t4DnA5/t27.sv:8: value is unhandled for priority or unique case statement
Time: 1 Scope: tb_unique_violation.dut
sel=11 onehot=0000
PASS: the legal selector decoded, and the illegal one was reported aboveVerilator reports the same violation as a failed assertion and stops:
sel=01 onehot=0010
[1] %Error: unique_violation.sv:7: Assertion failed in tb_unique_violation.dut: unique case, but none matched for '2'h3'
%Error: unique_violation.sv:7: Verilog $stop
Aborting...Either way the message names the file, the line and the selector value. Make regressions treat it as a failure, or it scrolls past unread.
priority. It claims coverage and lets order decide. unique would fire on every overlap.
unique case has a default assignment before it and some selectors match nothing. unique or unique0?unique0. It keeps the exclusivity claim and drops coverage, so legal no-match values stay quiet.
Run on 2026-10-18: the legal-pattern bench on Verilator 5.048 (--binary --timing --assert) with no warnings, and the violation bench on Icarus 13 (-g2012), which warns and continues. The Verilator stop shown under it was recorded the same day with the same source.
Icarus 13 does not run the legal-pattern bench: it ignores the unique and priority qualifiers when it compiles them.