Operators and Expressions
Bitwise vs. Logical Operators in Verilog
Why & and && (and their OR/NOT counterparts) give different results on multi-bit values, and why "if (a & b)" is a classic bug when "if (a && b)" was intended.
3 min read · Updated
& is Verilog's bitwise AND: it compares two vectors bit by bit and produces a result of the same width. && is logical AND: for operands containing only known 0/1 bits, it reduces each operand to a single true/false value first (all-zero is false; any nonzero value is true), then ANDs those two 1-bit truth values. If an operand contains x or z, its logical value can instead be ambiguous. The single-character and double-character forms of | (OR) and the single-character ! (logical NOT) follow the same split. Hardware it becomes: bitwise operators describe one operation per bit, in parallel; logical operators describe reduction logic that feeds a 1-bit decision. Their exact synthesized area and gate structure depend on the operand widths, target technology, and optimization, but logical operators always discard per-bit result information.
| Comparison point | Bitwise (&, |) | Logical (&&, ||, !) |
|---|---|---|
| Result width | Same as the wider operand | Always 1 bit |
| What each operand means | Every bit individually | Reduced to true (nonzero) or false (all-zero) first |
| Typical use | Computing a value: masks, per-bit logic | Testing a condition: if, while, ?: guards |
If one operand is x | Per bit — see Four-State Logic for when a controlling value still resolves it | The whole result is x unless a controlling operand's own truth value is already determined |
Predict before running
a = 4'b0100 and b = 4'b0010 share no set bit. Before running it, predict whether a & b and a && b agree on truthiness even though they compute differently.
Expected output — reveal after you predict
a=0100 b=0010
a & b = 0000 (bitwise, per-bit)
a && b = 1 (logical, each operand reduced to true/false first)
if (a & b): NOT TAKEN
if (a && b): TAKEN
PASSa and b share no set bit, so the bitwise AND is all zero and its if does not take the branch. But both a and b are individually nonzero, so each reduces to "true," and the logical AND — and its if — does. The two operators answer different questions: "which bits do both share?" versus "are both operands nonzero?"
Common mistakes
- Writing
if (a & b)when the intent wasif (a && b). This compiles cleanly and is the single most common bug this pair of operators causes — the example above is the exact failure mode: a nonzero-but-disjoint pair of vectors reads as "false" under&and "true" under&&. - Using
&&/||to compute a multi-bit value. Logical operators always collapse to 1 bit; if you need a per-bit result, the operator is bitwise, not logical. - Assuming
!aand~aare interchangeable.!ais logical NOT (reducesato true/false, then inverts — always 1 bit).~ais bitwise NOT (inverts every bit, same width asa).
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.