The conditional if else statement decides whether a statement is executed. A plain if ... else if chain says nothing about your intent. Can several conditions be true at once? Is it a mistake if none of them are? SystemVerilog lets you state that intent with three qualifiers, unique, unique0 and priority. The simulator then checks it on every evaluation, and the synthesis tool uses it to build better logic.

7 min read | Intermediate Level

What You'll Learn

  • What unique if, unique0 if and priority if each check
  • How to read the violation messages these checks produce in simulation
  • How each qualifier changes the logic a synthesis tool builds
  • When each qualifier is safe to use, and when it hides a bug

Syntax


unique   if (cond1) stmt1; else if (cond2) stmt2; [else stmt3;]
unique0  if (cond1) stmt1; else if (cond2) stmt2; [else stmt3;]
priority if (cond1) stmt1; else if (cond2) stmt2; [else stmt3;]

The qualifier goes before the first if and applies to the whole if ... else if chain. Each qualifier performs different checks:

QualifierViolation if more than one condition is trueViolation if no condition is true and there is no else
uniqueYesYes
unique0YesNo
priorityNoYes

A failed check produces a violation report. Most simulators issue it as a warning, as the *W messages in the logs below show, and the simulation keeps running.

unique-if and unique0-if

unique declares that the conditions are mutually exclusive: at most one can be true. They can therefore be evaluated in any order, or all in parallel. A unique if reports a violation when:

  • more than one condition in the chain is true, or
  • no condition is true and there is no final else.

unique0 performs only the first check. It does not report a violation if none of the conditions match.

No else block for unique-if


module tb;
	int x = 4;

  	initial begin
      	// This if else if construct is declared to be "unique"
		// Error is not reported here because there is a "else"
      	// clause in the end which will be triggered when none of
      	// the conditions match
    	unique if (x == 3)
      		$display ("x is %0d", x);
    	else if (x == 5)
      		$display ("x is %0d", x);
      	else
      		$display ("x is neither 3 nor 5");

      	// When none of the conditions become true and there
      	// is no "else" clause, then an error is reported
    	unique if (x == 3)
      		$display ("x is %0d", x);
    	else if (x == 5)
      		$display ("x is %0d", x);
  	end
endmodule
Output
ncsim> run
x is neither 3 nor 5
ncsim: *W,NOCOND: Unique if violation:  Every if clause was false.
            File: ./testbench.sv, line = 18, pos = 13
           Scope: tb
            Time: 0 FS + 1

ncsim: *W,RNQUIE: Simulation is complete.

The first chain ends in an else, so "no match" is a legal outcome and no violation is reported. The second chain has no else, so the simulator reports NOCOND: every condition was false. Had this been written as unique0 if, the second chain would have run silently.

Multiple matches in unique-if


module tb;
	int x = 4;

  	initial begin

      	// This if else if construct is declared to be "unique"
		// When multiple if blocks match, then error is reported
      	unique if (x == 4)
          $display ("1. x is %0d", x);
      	else if (x == 4)
          $display ("2. x is %0d", x);
      	else
          $display ("x is not 4");
  	end
endmodule
Output
ncsim> run
1. x is 4
ncsim: *W,MCONDE: Unique if violation:  Multiple true if clauses at {line=8:pos=15 and line=10:pos=13}.
            File: ./testbench.sv, line = 8, pos = 15
           Scope: tb
            Time: 0 FS + 1

ncsim: *W,RNQUIE: Simulation is complete.

Both conditions are true, so the overlap check fails with MCONDE, even though the chain has an else. The first matching branch is still executed. A final else only satisfies the "no match" check, never the overlap check.

Notice Time: 0 FS + 1 in the logs. The checks are deferred to the end of the time step, so a zero-delay glitch in an always_comb block, where inputs briefly overlap while settling, does not produce a false violation. Only the settled values are checked.

Quick Check

Q: A unique0 if chain has no else, and for the current inputs none of its conditions are true. Is a violation reported?

Show Answer

No. unique0 checks only for overlapping conditions. "No match" is allowed, so the chain simply does nothing.

priority-if

priority declares that the conditions must be evaluated in order and that the first true one wins, which is the normal behavior of an if ... else if chain. It also declares that at least one branch must be taken. A violation is reported only when no condition is true and there is no final else. Overlapping conditions are allowed and are not reported.

No else clause in priority-if


module tb;
	int x = 4;

  	initial begin
      	// This if else if construct is declared to be "priority"
		// Error is not reported here because there is a "else"
      	// clause in the end which will be triggered when none of
      	// the conditions match
    	priority if (x == 3)
      		$display ("x is %0d", x);
    	else if (x == 5)
      		$display ("x is %0d", x);
      	else
      		$display ("x is neither 3 nor 5");

      	// When none of the conditions become true and there
      	// is no "else" clause, then an error is reported
    	priority if (x == 3)
      		$display ("x is %0d", x);
    	else if (x == 5)
      		$display ("x is %0d", x);
  	end
endmodule
Output
ncsim> run
x is neither 3 nor 5
ncsim: *W,NOCOND: Priority if violation:  Every if clause was false.
            File: ./testbench.sv, line = 18, pos = 15
           Scope: tb
            Time: 0 FS + 1

ncsim: *W,RNQUIE: Simulation is complete.

Exit after first match in priority-if


module tb;
	int x = 4;

  	initial begin
      	// Exits if-else block once the first match is found
      	priority if (x == 4)
      		$display ("x is %0d", x);
      else if (x != 5)
      		$display ("x is %0d", x);
  	end
endmodule
Output
ncsim> run
x is 4
ncsim: *W,RNQUIE: Simulation is complete.

With x = 4, both conditions are true. priority takes the first branch and reports nothing, because overlap is expected in a priority chain. The same code with unique would report MCONDE.

Using unique and priority if in Digital Design

All three qualifiers are synthesizable. They are design-intent statements as much as simulation checks.

The synthesis tool trusts the qualifier and builds simpler logic:

  • unique: conditions are exclusive, so the priority chain can be replaced by parallel AND-OR logic. Without an else, the "no match" case is also treated as don't-care, so no latch is needed for it.
  • unique0: conditions are exclusive, so parallel logic is used, but "no match" must still be handled.
  • priority: the order is kept, and without an else the "no match" case is treated as don't-care.

module onehot_mux (
  input  logic [2:0] sel,          // one-hot: at most one bit set
  input  logic [7:0] a, b, c,
  output logic [7:0] y
);
  always_comb begin
    unique if (sel[0]) y = a;      // tells synthesis the conditions never overlap
    else if   (sel[1]) y = b;
    else if   (sel[2]) y = c;
    else               y = '0;     // sel == 0 is legal: drive 0
  end
endmodule

Without unique, synthesis must build a priority chain in which sel[0] blocks sel[1], and so on. With it, the tool can build a flat AND-OR mux. During simulation, a MCONDE violation tells you if the one-hot assumption is ever broken.

The keyword changes the hardware, but the check runs only in simulation. If two sel bits are ever set together on silicon, the parallel mux produces a value that no branch of the RTL describes, and simulation will not match the gates. Treat every unique or priority violation in simulation as a real bug.

Where are unique and priority used?

RTL teams use unique on decoders driven by one-hot state vectors or one-hot grant signals from arbiters, where parallel logic shortens the critical path. Interrupt controllers use priority to make the order of the request checks explicit. Many verification flows promote these violations to errors so that a regression fails as soon as a design assumption breaks.

Common Beginner Mistakes

Mistake #1: Adding unique to conditions that can overlap

Wrong: unique if (addr < 16) ... else if (addr < 256) ...
Right: priority if (addr < 16) ... else if (addr < 256) ...

Why? Any addr below 16 satisfies both conditions. The code depends on order, so it is a priority chain by nature. unique would report violations, and synthesis would build the wrong logic.

Mistake #2: Thinking a final else silences all unique checks

A final else only covers the "no match" case. Why? The overlap check is separate, as the multiple-match example shows: it reported MCONDE despite having an else.

Mistake #3: Expecting priority to catch overlapping conditions

priority never reports overlap. Why? In a priority chain, overlap is normal, and the first true condition wins. If you need both the order and an overlap check, the conditions are not really prioritized. Use unique.

Practice Exercise

Challenge: Interrupt vector selection

An interrupt controller has three request lines, irq[2:0], where irq[2] has the highest priority. Several requests can be active at once. The block that computes the 2-bit vector vec is only used when at least one request is pending. Write the always_comb block and choose the right qualifier.

Hint

Requests can overlap, which rules out one qualifier. "At least one is always pending" means the no-match case should never happen, and you want simulation to tell you if it does.

Solution

always_comb begin
  priority if (irq[2]) vec = 2'd2;   // highest priority checked first
  else if     (irq[1]) vec = 2'd1;
  else if     (irq[0]) vec = 2'd0;
  // no else: "no request" should never happen here, and
  // priority reports a violation in simulation if it does
end

unique is wrong because several requests can be active together. priority keeps the order, lets synthesis treat "no request" as don't-care, and flags that case in simulation if the assumption is ever broken. Some lint tools still warn about the missing assignment in always_comb. Adding a default such as vec = '0; before the chain silences that warning, and priority still flags the no-request case.

Summary

In this tutorial, you learned:

  • unique if checks that conditions never overlap and that one always matches, unless there is an else
  • unique0 if checks only for overlap; "no match" is allowed
  • priority if keeps evaluation order and checks only that some branch is taken
  • Violations are deferred to the end of the time step and are usually reported as warnings
  • Synthesis trusts the qualifier: unique gives parallel logic, and a missing else becomes don't-care
  • Every violation in simulation points to a possible simulation-versus-synthesis mismatch and should be fixed
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5
Cron Job Starts