Verilog · Chapter 10.4 · Operators & Operands
Bitwise Operators in Verilog — & | ^ ~ and Bit Manipulation
The bitwise operators, AND, OR, XOR, NOT, and XNOR, combine operands bit by bit and produce a result as wide as the operands. Where the logical operators ask one yes-or-no question about a whole value, bitwise operators work on every bit in parallel, which makes them the tools of bit manipulation. You use them to set, clear, toggle, mask, and invert the individual bits of a vector. They build a row of gates, one per bit, and they appear everywhere in real RTL, including control-register updates, byte masks, parity and error correction, and datapath gating. This page drills the five operators, the canonical set, clear, and toggle idioms and the mask logic beginners get subtly wrong, the special properties of XOR, how unknown and high-impedance values propagate per bit, and how a bitwise operator differs from a reduction.
Foundation18 min readVerilogBitwise OperatorsBit ManipulationMasksXORRTL Design
Chapter 10 · Section 10.4 · Operators & Operands
1. The Engineering Problem
An engineer needs to clear bit 3 of an 8-bit control register, leaving the other bits untouched. They write what looks reasonable:
ctrl = ctrl & (1 << 3); // intent: clear bit 3The result is catastrophic — not "bit 3 cleared," but every bit except bit 3 cleared. (1 << 3) is the mask 8'b0000_1000, and ANDing the register with it keeps only bit 3 and zeroes everything else — the opposite of the intent. The whole control register is wiped.
The correct "clear one bit" idiom inverts the mask first:
ctrl = ctrl & ~(1 << 3); // clear bit 3, keep the rest ✓
// ^ the ~ is the whole point: AND with all-ones-except-bit-3~(1 << 3) is 8'b1111_0111 — all ones except bit 3 — and ANDing with it forces bit 3 to 0 while passing every other bit through. The single missing ~ is the difference between "clear bit 3" and "destroy the register."
Bitwise operators manipulate individual bits, and the mask logic is precise and unforgiving: AND clears, OR sets, XOR toggles — but only with the correct mask. A subtly wrong mask compiles, simulates, and corrupts data silently.
Bitwise operators are how RTL reaches into a vector and changes specific bits. This page teaches the operators, the canonical idioms that get the masks right, and the properties (especially XOR's) that make bit manipulation reliable.
2. Mental Model — Bitwise Operators Are Per-Bit Parallel Gates
Visual A — bitwise AND is a row of gates
3. The Five Operators
wire [3:0] a = 4'b1100, b = 4'b1010;
a & b // = 4'b1000 AND — 1 where BOTH bits are 1
a | b // = 4'b1110 OR — 1 where EITHER bit is 1
a ^ b // = 4'b0110 XOR — 1 where the bits DIFFER
a ^~ b // = 4'b1001 XNOR — 1 where the bits are the SAME (= ~(a^b))
~a // = 4'b0011 NOT — invert every bit (unary)&,|,^,^~are binary (two operands);~is unary (one operand).^~and~^are the same operator — bitwise XNOR, the complement of XOR.- The result width equals the wider operand's width; a narrower operand is zero-extended before the operation.
Each maps to its per-bit gate (AND, OR, XOR, XNOR, inverter), one per bit position — cheap hardware, since there is no carry chain to build.
4. The Bit-Manipulation Idioms
This is what bitwise operators are for. Each common bit operation is a fixed idiom — learn these as patterns and the masks are always right:
// SET bit n (force to 1) → OR with a 1 in position n
ctrl = ctrl | (1 << n); // or: ctrl | MASK
// CLEAR bit n (force to 0) → AND with a 0 in position n (1s elsewhere)
ctrl = ctrl & ~(1 << n); // the ~ is essential — see §1
// TOGGLE bit n (flip) → XOR with a 1 in position n
ctrl = ctrl ^ (1 << n);
// TEST bit n (is it set?) → select the bit, or mask and compare
if (ctrl[n]) // direct bit-select (simplest)
if (ctrl & (1 << n)) // mask then test nonzero
// MASK a field (keep some bits, zero the rest) → AND with a field mask
field = value & 8'b0000_1111; // keep low nibble, zero high nibble
// INVERT a whole vector → unary NOT
inverted = ~value;The mental shortcuts: | sets, & ~ clears, ^ toggles, & masks, ~ inverts. The most error-prone is clear, because it needs the inverted mask (& ~mask, not & mask) — the §1 bug. Get the idiom right once and bit manipulation is reliable.
Visual B — set, clear, toggle
The three bit operations and their masks
data flow5. XOR — The Specially Useful Operator
XOR (^) deserves its own section because its algebraic properties make it the basis of comparison, parity, and reversible bit tricks:
a ^ a == 0 // anything XOR itself is zero → equality test
a ^ 0 == a // XOR with zero is identity
a ^ 1'b1 == ~a // XOR with 1 inverts (per bit) → conditional invert
a ^ b ^ b == a // XOR is reversible → masking/unmasking, swapsThese power real RTL idioms:
- Equality / difference:
a ^ bis zero exactly whena == b; nonzero bits mark where they differ. (A reduction-XOR of that,^(a^b), gives parity of the difference — 10.5.) - Parity: XOR-ing all bits of a word gives its parity bit — the foundation of parity checking and the building block of ECC/CRC. (
^datareduction, 10.5.) - Conditional invert:
data ^ {N{invert}}flips every bit wheninvertis 1 and passes through when 0 — a one-line controllable inverter. - Reversibility: because
x ^ k ^ k == x, XOR with a key masks and the same XOR unmasks — used in scramblers, LFSRs, and lightweight data whitening.
XOR is the operator that does the most work per gate; recognizing these patterns is a mark of an experienced RTL engineer.
6. Width and the Per-Bit X Rule
Two behaviours distinguish bitwise operators from the arithmetic operators of 10.2.
Width: the narrower operand is zero-extended. 8'hFF & 4'h0F treats the 4-bit operand as 8'h0F, giving 8'h0F. Be deliberate about widths so a short mask doesn't accidentally zero the high bits you meant to keep (DebugLab 3).
x/z propagate per bit, not across the word. Because there is no carry, an unknown bit corrupts only the output bits that depend on it — unlike arithmetic, where one x poisons everything:
1'b0 & 1'bx // = 1'b0 — 0 dominates AND, defined despite x
1'b1 & 1'bx // = 1'bx — undetermined
1'b1 | 1'bx // = 1'b1 — 1 dominates OR, defined despite x
1'b0 | 1'bx // = 1'bx
1'bx ^ 1'b1 // = 1'bx — XOR with x is always x
// word example: only the affected positions go x
8'b1111_0000 & 8'b1010_xx10 // = 8'b1010_0000 (low x bits AND'd with 0 → 0)This bit-locality is why bitwise logic is more x-robust than arithmetic: masking a known-zero region cleans up unknowns there, and a single bad bit doesn't necessarily ruin the whole result.
7. Bitwise vs Logical vs Reduction — Disambiguation
The same symbols appear in three roles; knowing which is which prevents real bugs.
| Form | Example | Operator | Result |
|---|---|---|---|
| Binary, two operands | a & b | bitwise (this page) | N-bit, per-bit AND |
| Unary, one operand | &a | reduction (10.5) | 1-bit (AND of all bits of a) |
| Double symbol | a && b | logical (10.3) | 1-bit (truth AND) |
a & b(two operands) is bitwise — per-bit, N bits wide.&a(one operand) is reduction — ANDs all ofa's bits into one bit (drilled in 10.5).a && b(double&&) is logical — truth values, one bit (drilled in 10.3).
For NOT: ~a is bitwise invert (N bits); !a is logical negation (1 bit, 10.3). The number of operands and whether the symbol is doubled tell them apart — and the result width is the giveaway: bitwise stays wide, logical and reduction collapse to one bit.
8. Worked Examples
8.1 Example 1 — set, clear, toggle one bit
localparam BIT = 3;
assign set_result = ctrl | (1 << BIT); // force bit 3 to 1
assign clear_result = ctrl & ~(1 << BIT); // force bit 3 to 0 (note ~)
assign toggle_result = ctrl ^ (1 << BIT); // flip bit 3The three canonical idioms side by side. Each touches only bit 3 and passes the other seven bits through unchanged. The ~ on the clear is the one easy-to-forget piece (§1).
8.2 Example 2 — mask a field
// Extract the low nibble (bits 3:0), zero the high nibble.
assign low_nibble = value & 8'b0000_1111;
// Merge: take high nibble from A, low nibble from B.
assign merged = (a & 8'b1111_0000) | (b & 8'b0000_1111);Masking with & keeps selected bits and zeros the rest; combining two masked values with | merges fields from different sources — the everyday pattern for packing and unpacking bit fields. (For contiguous fields, a part-select value[3:0] is often cleaner, but masking generalizes to non-contiguous bits.)
8.3 Example 3 — XOR for compare and conditional invert
assign differ = a ^ b; // bits where a and b differ
assign are_equal = (a ^ b) == 0; // equal iff no bits differ
assign maybe_inv = data ^ {8{invert_en}}; // invert all bits when invert_en=1a ^ b marks differences; comparing it to zero is an equality test; XOR-ing with a replicated control bit gives a one-line conditional inverter. These are XOR's §5 properties in working form.
9. Industry Perspective
- Control/status register manipulation is bitwise. Reading, setting, clearing, and toggling individual bits of configuration and status registers — the bread-and-butter of peripheral RTL — is all
|/& ~/^idioms. - Masking and field packing are everywhere. Byte enables, lane masks, packing several fields into one word and unpacking them — bitwise AND/OR with masks, often combined with shifts (10.7).
- XOR underpins error detection and scrambling. Parity, CRC, ECC, LFSR-based scramblers and PRBS generators are built on XOR's reversibility and parity properties. An RTL engineer sees
^and thinks "comparison, parity, or whitening." - The bitwise-vs-logical choice is a lint and review point. As in 10.3, using a bitwise operator where a boolean was meant (or vice versa) is flagged; the operators signal intent — bit manipulation vs truth.
10. Common Mistakes
- Clearing with
& maskinstead of& ~mask— keeps only the masked bit and zeros the rest; the §1 register-destroyer (DebugLab 1). - Setting with
& maskinstead of| mask— AND can't set a bit; OR sets (DebugLab 2). - Width-mismatched masks — a too-narrow mask zero-extends and clears high bits you meant to keep (§6, DebugLab 3).
- Bitwise where logical was meant —
&/|/~in a boolean condition instead of&&/||/!(recap of 10.3). - Confusing
a & b(bitwise) with&a(reduction) — two operands vs one; different result widths (§7).
11. Debugging Lab
Three bitwise-operator debug post-mortems
12. Interview Q&A
13. Exercises
Exercise 1 — Evaluate the operators
For a = 4'b1100, b = 4'b0110, give each result and its width: (a) a & b; (b) a | b; (c) a ^ b; (d) ~a; (e) a ^~ b.
Exercise 2 — Write the idiom
Give the expression for each, on an 8-bit register r: (a) set bits 0 and 7; (b) clear bit 4; (c) toggle the low nibble; (d) keep only bits 5:2 (zero the rest); (e) invert the whole register.
Exercise 3 — Fix the mask bug
Each line states an intent. Identify the bug and give the fix.
y = x & (1 << 2); // intent: clear bit 2
y = x & (1 << 6); // intent: set bit 6
y = x & 8'h0F; // intent: keep the HIGH nibbleExercise 4 — XOR reasoning
(a) What is a ^ a for any a, and how is it used? (b) Write a one-line expression that inverts all 8 bits of data when inv is 1 and passes data through when inv is 0. (c) If crc ^ data ^ data appears, what does it simplify to and why?
14. Summary
The bitwise operators — &, |, ^, ~, ^~ — combine operands bit by bit, producing a result as wide as the operands. They are the per-bit workhorses of bit manipulation: masking, setting, clearing, toggling, and inverting.
The core ideas:
- Per-bit, N-bit-wide, no carry — one gate per position, each output bit depending only on the same input positions. Contrast logical operators (whole-operand truth → 1 bit).
- Each operator is a bit tool —
&masks/clears,|sets,^toggles/compares,~inverts,^~matches. - The idioms: SET
| mask, CLEAR& ~mask(the~is essential), TOGGLE^ mask, MASK& field, INVERT~. - XOR is special —
a^a=0,a^0=a, reversibility — powering equality, parity, conditional invert, and scrambling. x/zpropagate per bit (bit-local, unlike arithmetic), and dominance resolves bits (0 & x = 0,1 | x = 1).- Disambiguation:
a & b(bitwise, N bits) ≠&a(reduction, 1 bit, 10.5) ≠a && b(logical, 1 bit, 10.3).
The discipline this page instils:
- Match the operator to the bit job — clear with AND-inverted-mask, set with OR, toggle with XOR.
- Size masks to the operand width so zero-extension can't silently clear bits.
- Use bitwise for bits, logical for truth — the operator signals intent.
You now command per-bit manipulation. The next page takes the unary forms of these same symbols: Chapter 10.5 Reduction Operator drills &a, |a, ^a (and their negations) — operators that collapse a whole vector into a single bit, the basis of all-bits-set checks, any-bit-set flags, and parity.
Related Tutorials
- Logical Operators — Chapter 10.3; the whole-operand-truth operators these per-bit ones are confused with.
- Verilog Operators & Operands — Chapter 10 overview; the operator-as-hardware model.
- Operator Precedence — Chapter 10.1; how
&binds tighter than^than|, and all bind looser than comparisons. - Scalar vs Vector vs Arrays — Chapter 5.2.4; the vectors whose bits these operators manipulate.