Operators and Expressions
Verilog Operators Overview
A map of the classic Verilog operator categories — arithmetic, relational, logical, bitwise, reduction, shift, concatenation, and conditional — and why precedence, not just meaning, causes real bugs.
4 min read · Updated
Verilog operators fall into a handful of categories, and reading a module fluently means recognizing which category an operator belongs to at a glance — the same symbol can mean something very different depending on how many characters it is.
Categories
| Category | Operators | What it does | Hardware it becomes |
|---|---|---|---|
| Arithmetic | + - * / % | Ordinary arithmetic on the operand widths | Adder/subtractor/multiplier logic |
| Relational | < <= > >= | Compares magnitude; result is 1 bit | A comparator, typically built from subtraction plus sign/zero checks |
| Equality | == != === !== | ==/!= propagate unknowns; ===/!== compare exactly, see Four-State Logic | An XNOR-per-bit tree feeding an AND (===/!== are simulation-only — no hardware equivalent) |
| Logical | && || ! | Reduces each operand to true/false first, see Bitwise vs. Logical Operators | An "is this nonzero?" reduction feeding a 1-bit AND/OR/NOT decision |
| Bitwise | & | ^ ^~/~^ ~ | Per-bit operation across the full vector width | One AND/OR/XOR/NOT gate per bit, all in parallel |
| Reduction (unary) | & | ^ ~& ~| ~^/^~ | Collapses one vector into a single bit, see Reduction Operators | A tree of gates folding the whole vector down to one bit |
| Shift | << >> <<< >>> | Moves bits left/right, see Shift Operators | A constant shift is mostly rewiring; a variable-amount shift is a small selection network (a barrel shifter) |
| Concatenation/replication | { } {n{ }} | Joins or repeats bit vectors, see Concatenation and Replication | Wiring — no gates, just regrouping which bit connects where |
| Conditional | ?: | A single-expression if/else, see The Conditional (Ternary) Operator | A multiplexer |
The single-character pipe | is Verilog's bitwise-OR (and, written before a single operand, unary reduction-OR); doubled as || it is logical OR. Bitwise and reduction operators use the same symbols — &, |, ^ — in two different roles: written between two operands (a & b) they are bitwise; written before a single operand (&a) they are reduction. The position, not a different symbol, tells you which one you are reading.
Precedence is not intuition — verify it
Verilog operator precedence closely follows C, which means some of C's classic surprises carry over directly. Equality (==, !=) binds tighter than bitwise &/^/|, so a comparison mixed with a bitwise operator does not group the way it visually appears to.
Before running it, predict whether a & b == c evaluates as (a & b) == c or a & (b == c).
module tb;
reg a, b, c;
reg parsed_as_written, explicit_bitwise_first;
initial begin
a = 1'b0;
b = 1'b0;
c = 1'b0;
parsed_as_written = a & b == c;
explicit_bitwise_first = (a & b) == c;
$display("a=%b b=%b c=%b", a, b, c);
$display("a & b == c = %b (parses as a & (b == c))", parsed_as_written);
$display("(a & b) == c = %b (explicit grouping)", explicit_bitwise_first);
if (parsed_as_written !== explicit_bitwise_first)
$display("DIVERGES: precedence changed the result");
else
$display("SAME");
$display("PASS");
$finish;
end
endmoduleExpected output — reveal after you predict
a=0 b=0 c=0
a & b == c = 0 (parses as a & (b == c))
(a & b) == c = 1 (explicit grouping)
DIVERGES: precedence changed the result
PASSWith a=b=c=0, b == c is 1, so a & (b == c) is 0 & 1 = 0. The explicitly grouped (a & b) == c is (0 & 0) == 0 = 1. The two expressions genuinely diverge — precedence changed the answer, not just the readability.
The practical rule
Full operator-precedence tables exist and are worth bookmarking, but memorizing all fourteen levels is not the efficient move. Parenthesize any expression that mixes more than one operator category — bitwise with equality, shift with additive, conditional with almost anything. The parentheses cost nothing at simulation or synthesis time and remove the ambiguity for the next reader, including yourself in six months.
Sources and verification
Example provenance: SkillLift Labs authored the example for this tutorial. tests/scripts/tutorial-verified-examples.test.ts extracts the complete marked example from this Markdown file, compiles it in Verilog-2005 mode with Icarus Verilog, runs it, and requires the simulator output to match the Expected output block exactly. The same test also carries an independent, code-owned semantic oracle, and exercises the article-to-runner source-splitting path. Automation verifies those stated properties; human technical review for indexing remains a separate gate.