Skip to content

Verilog · Chapter 10.5 · Operators & Operands

Reduction Operators in Verilog — &a, |a, ^a and Vector-to-Bit

The reduction operators take a single vector and collapse all of its bits into one bit by applying the operation across the whole word. Reduction AND asks whether all bits are set, reduction OR asks whether any bit is set, which is exactly whether the value is nonzero, and reduction XOR computes parity, the exclusive-or of every bit. They use the same symbols as the bitwise operators, but with one operand instead of two, and that single difference changes everything: bitwise stays the full width while reduction collapses to a single bit. This is how RTL answers whole-vector questions like all-ones detection, any-flag checks, and error detection in one width-independent symbol, instead of hand-writing a bit-by-bit expression. This lesson drills all six operators, the three you use constantly, the truthiness link to the logical operators, and the unary-versus-binary distinction.

Foundation17 min readVerilogReduction OperatorsParityVectorRTL Design

Chapter 10 · Section 10.5 · Operators & Operands

1. The Engineering Problem

An engineer generates a parity bit for an 8-bit data word — the XOR of all its bits — by writing it out by hand:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assign parity = data[0] ^ data[1] ^ data[2] ^ data[3]
              ^ data[4] ^ data[5] ^ data[6] ^ data[7];

It works. Then the bus is widened to 16 bits. Someone updates the data declaration but forgets to extend this expression, so it now XORs only the low 8 bits — the parity is computed over half the word. Every parity check downstream is subtly wrong, and nothing flags it: the expression is still legal, still 8 terms, just incomplete.

The reduction operator does the same job in one symbol, and it is width-independent:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assign parity = ^data;        // XOR of EVERY bit of data, whatever its width

^data reduces the whole vector — 8 bits, 16 bits, any width — to a single parity bit. Widen data and ^data automatically covers the new bits; there is nothing to forget.

Reduction operators collapse a whole vector into one bit by applying an operation across all its bits — &a (all set), |a (any set), ^a (parity) — in a single, width-independent symbol. Hand-writing the bit-by-bit version is verbose, error-prone, and breaks when the width changes.

This page teaches the reduction operators: the six of them, the three you reach for constantly, and how the single unary symbol ^a differs from the binary a ^ b of the previous page.

2. Mental Model — Reduction Collapses a Vector to One Bit

Visual A — reduction is a tree of gates

Reduction AND as a gate treea[3:0]one vector ina[3] & a[2]a[1] & a[0]ANDcombine&a1 bit out (all set?)12
A reduction AND of a 4-bit vector ANDs all four bits together into one result bit — built as a small tree of 2-input gates (log-depth, cheap). Every reduction operator works this way: one vector in, the operation applied across all bits, one bit out. Widening the vector just adds leaves to the tree.

3. The Hardware View — A Reduction Tree

A reduction operator builds a tree of its base gate across the operand's bits — &a is a tree of AND gates, ^a a tree of XOR gates. The tree is log-depth in the width (a 16-bit reduction is about 4 gate-delays deep) and cheap — there is no carry, just a fan-in of the same gate. The output is a single wire.

This is why reduction is the right tool for whole-vector questions: the alternative — comparing against a constant (a == 8'hFF) or hand-writing the bit list — is either width-locked or verbose, while the reduction operator scales with the vector for free and synthesizes to the same compact tree. One operand in, one bit out, a small tree between.

4. The Six Operators

reduction-operators.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   wire [3:0] a = 4'b1011;
 
   &a       // = 1'b0   AND-reduce : all bits 1?      (1011 → 0, bit[2]=0)
   |a       // = 1'b1   OR-reduce  : any bit 1?       (1011 → 1)
   ^a       // = 1'b1   XOR-reduce : odd # of 1s?     (three 1s → 1)
   ~&a      // = 1'b1   NAND-reduce: = ~(&a)
   ~|a      // = 1'b0   NOR-reduce : = ~(|a)  (1 only if a == 0)
   ~^a      // = 1'b0   XNOR-reduce: = ~(^a)  (even parity)
  • All six are unary (one operand) and return one bit.
  • ~&, ~|, ~^ are the negations of &, |, ^ — NAND, NOR, and XNOR reductions. (~^a and ^~a are the same: XNOR reduction.)
  • The three negated forms are used less; the three base forms (&, |, ^) cover the vast majority of real RTL.

5. The Three You Actually Use

Most reduction in practice is one of these three:

key-reductions.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // &a — ALL bits set: terminal-count / all-ones / all-valid detection
   assign at_max  = &counter;          // 1 when counter is all-ones (about to wrap)
   assign all_rdy = &ready_vec;        // 1 when every agent's ready bit is set
 
   // |a — ANY bit set (= nonzero): not-empty / any-flag / valid detection
   assign not_empty = |fifo_count;     // 1 when count != 0
   assign any_irq   = |irq_lines;      // 1 when any interrupt line is asserted
 
   // ^a — PARITY: error detection (XOR of all bits)
   assign parity = ^data;              // 1 when data has an odd number of 1s
  • &a ("all set") — terminal-count detect (counter at max), all-flags-set, all-channels-ready. The clean, width-independent way to ask "is every bit 1?"
  • |a ("any set" = nonzero) — FIFO not-empty (|count), any-interrupt-pending (|irq), any-valid. This is the single most common reduction.
  • ^a ("parity") — generate or check a parity bit; the building block of error detection (parity, CRC, ECC). ^data is 1 when data has an odd number of set bits.

Visual B — the three key reductions

The three reductions you reach for

data flow
The three reductions you reach for&a → ALL set?terminal count, all-ready|a → ANY set?nonzero, not-empty, any-flag^a → PARITYodd # of 1s, error detection
Three whole-vector questions, three reductions: &a asks if every bit is set (all-ones / terminal count), |a asks if any bit is set (nonzero / not-empty — the most common), and ^a computes parity (odd number of set bits) for error detection. Each is one width-independent symbol.

The OR-reduction |a is exactly the question "is a nonzero?" — which is the truthiness rule from the logical operators (10.3). This connects the two families:

reduction-and-truthiness.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   |a   ==  (a != 0)        // OR-reduce: 1 if any bit set = a is nonzero = "true"
   ~|a  ==  (a == 0)        // NOR-reduce: 1 only if all bits 0 = a is zero
   ~|a  ==  !a              // NOR-reduction equals logical NOT

So when 10.3 said a logical operator "reduces each operand to nonzero," that reduction is |a. A bare operand in a condition (if (a)) is implicitly OR-reduced to its truth value; !a is implicitly ~|a. The reduction operators make explicit what logical operators and conditional contexts do implicitly. Writing assign valid = |data; and assign valid = (data != 0); build the same hardware — the OR-reduction tree.

7. X Behaviour and Unary-vs-Binary Disambiguation

X behaviour follows dominance, per the base gate. A reduction can resolve to a known value even with x bits if a dominating bit decides it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   &(4'b1x11)   // = 1'bx   no 0 to force it, an x remains → undetermined
   &(4'b1x01)   // = 1'b0   a known 0 forces AND-reduce to 0, despite the x
   |(4'b0x00)   // = 1'bx   no 1 to force it → undetermined
   |(4'b0x10)   // = 1'b1   a known 1 forces OR-reduce to 1, despite the x
   ^(4'b1x11)   // = 1'bx   XOR-reduce with any x is always x

AND-reduce is 0 if any bit is a known 0; OR-reduce is 1 if any bit is a known 1; otherwise x if any bit is x. XOR-reduce is x if any bit is x (parity can't tolerate an unknown).

Unary vs binary — the recurring &a / a & b distinction. The same symbol is reduction with one operand and bitwise with two:

FormOperandsOperatorResult
&aonereduction (this page)1 bit — AND of all bits of a
a & btwobitwise (10.4)N bits — per-bit AND
a && btwological (10.3)1 bit — truth AND

The giveaway is operand count and result width: one operand → reduction → 1 bit; two operands → bitwise (N bits) or, doubled, logical (1 bit). Reading &data as a per-bit operation, or a & b as a reduction, is the confusion to avoid.

8. Worked Examples

8.1 Example 1 — a width-independent parity generator

parity-gen.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module parity_gen #(
    parameter integer WIDTH = 8
)(
    input  [WIDTH-1:0] data,
    output             parity        // even-parity bit
);
    assign parity = ^data;           // XOR of all bits, any WIDTH
endmodule

^data computes the parity over the whole word regardless of WIDTH — change the parameter and the parity still covers every bit. This is the §1 fix: one symbol, no hand-written term list to forget. (^data is 1 when data has an odd number of 1s, so appending it makes the total count even — even parity.)

8.2 Example 2 — terminal-count detect

terminal-count.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // "Is the counter at its maximum (all ones), about to wrap?"
   assign at_max = &count;          // width-independent all-ones detect
 
   // compare to the width-locked alternative:
   // assign at_max = (count == 4'hF);   // must change if width changes

&count asks "are all bits set?" — true exactly at the maximum value — and works for any counter width. The == 4'hF form is correct but hard-codes the width, so it silently breaks if count is later resized. The reduction is the maintainable choice.

8.3 Example 3 — any-flag / not-empty

any-set.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   assign not_empty  = |fifo_count;     // FIFO has entries (count nonzero)
   assign any_irq    = |irq_pending;    // some interrupt is pending
   assign all_empty  = ~|valid_vec;     // NO valid bit set (all zero)

|x is the "any bit set / nonzero" workhorse — not-empty, any-pending, has-data. Its negation ~|x ("all zero / none set") is equally handy. Both reduce a whole status vector to a single decision bit.

9. Industry Perspective

  • |x is ubiquitous for status reduction. FIFO not-empty, any-interrupt, any-error, has-valid — collapsing a status/flag vector to a single "something is happening" bit is everyday RTL, and |x is the idiom.
  • &x detects terminal/all conditions. Counter-at-max (wrap detect), all-channels-ready, all-lanes-valid — the width-independent all-ones check, preferred over a width-locked == ALL_ONES.
  • ^x underpins error detection. Parity generation and checking, and the bit-level core of CRC and ECC, are XOR-reductions. A single ^data replaces an error-prone hand-written XOR chain.
  • Reduction keeps code width-agnostic. Parameterized modules use reductions so logic scales with the width parameter automatically — a key reason reductions are favored over constant comparisons in reusable IP.

10. Common Mistakes

  1. Confusing &a (reduction) with a & b (bitwise) — one operand vs two; 1-bit vs N-bit result (§7).
  2. Hand-writing the bit list instead of reducing — verbose and breaks on width change (§1, DebugLab 1).
  3. Using a width-locked == ALL_ONES instead of &a — correct but silently wrong after a resize (§8, DebugLab 3).
  4. Even/odd parity confusion^a is 1 for an odd number of 1s; ~^a (XNOR-reduce) is the even-count form.
  5. Expecting a multi-bit result — reduction always returns one bit, never a vector.

11. Debugging Lab

Three reduction-operator debug post-mortems

12. Interview Q&A

13. Exercises

Exercise 1 — Evaluate the reductions

For a = 6'b101100, give each: (a) &a; (b) |a; (c) ^a; (d) ~&a; (e) ~|a; (f) ~^a. State each result as a single bit.

Exercise 2 — Pick the reduction

For each intent, write the one-symbol reduction: (a) "true when the 8-bit status is all ones"; (b) "true when any of the 4 request lines is asserted"; (c) "the even-parity bit of a 32-bit word"; (d) "true when the 16-bit count is zero".

Exercise 3 — Replace the fragile code

Rewrite each as a width-independent reduction: (a) all = a[3] & a[2] & a[1] & a[0];; (b) nz = (data != 0);; (c) at_max = (count == 8'hFF);.

Exercise 4 — Reason about parity

(a) For ^data to be a valid even-parity bit, what should ^{data, parity} equal at the receiver, and why? (b) If data has an even number of 1s, what is ^data? (c) How would you compute a parity that is 1 for an even number of set bits?

14. Summary

The reduction operators — unary &, |, ^, ~&, ~|, ~^ — collapse a whole vector into a single bit by applying the operation across all its bits. They answer whole-vector questions in one width-independent symbol.

The core ideas:

  • One operand, one-bit result, width-independent. &a ANDs all bits, |a ORs all bits, ^a XORs all bits — covering whatever width a has, automatically.
  • The three you use: &a (all bits set — terminal count, all-ready), |a (any bit set = nonzero — not-empty, any-flag, the most common), ^a (parity — error detection).
  • |a is truthiness|a == (a != 0), ~|a == !a; the explicit form of the implicit nonzero reduction logical operators perform.
  • Reduction builds a log-depth gate tree — cheap, scaling with the vector.
  • Disambiguation: &a (one operand, reduction, 1 bit) ≠ a & b (two operands, bitwise, N bits, 10.4) ≠ a && b (logical, 1 bit, 10.3).

The discipline this page instils:

  • Reduce, don't hand-write^data, not an 8-term XOR chain; it scales and won't break on a resize.
  • Prefer &a over == ALL_ONES for all-ones detection; width-independent and maintainable.
  • Read by arity — one operand is reduction (1 bit); two is bitwise (N bits).

You can now collapse vectors to decision bits. The chapter turns next to comparison — operators that ask how two values relate: Chapter 10.6 Relational Operator drills <, <=, >, >= — the magnitude comparators — including the signed-versus-unsigned subtlety that, like in arithmetic, changes the answer on negative values.