Skip to content
VLSI Mentor

UART · Module 3

Parity Generation, Checking and Error Detection

One interval, one XOR reduction, and a detection guarantee with a sharp edge: parity catches every corruption that flips an odd number of protected bits and provably misses every even-numbered one — demonstrated, not asserted.

Chapter 3.2 delivered a payload across a sequence of intervals and said nothing about whether it arrived intact. Nothing so far in the framing does. A receiver that samples every interval correctly and a receiver that samples one of them wrongly produce results that are indistinguishable to the software above them.

Parity is the smallest possible response: one additional interval, whose value is derived from the payload, so that a receiver can recompute it and compare. It costs one bit period per frame and a handful of gates.

What makes it worth a chapter is not the mechanism — that is an XOR reduction and a comparison — but the shape of its guarantee. Parity does not catch "most" errors or "small" errors. It catches a precisely defined class and provably misses its complement, and the boundary between them is sharp enough to compute. An engineer who knows where that boundary is can decide whether parity is worth the interval. One who believes parity means "the data is checked" will trust a frame that was corrupted.

1. One Interval, Derived From the Payload

Parity adds a single interval immediately after the payload field. Its value is not chosen by the transmitter in any meaningful sense — it is a function of the payload bits, computed by both endpoints independently from the same rule.

That independence is the whole mechanism. The transmitter computes the value from the payload it is about to send and places it on the line. The receiver computes the value from the payload it believes it received, compares against the interval it observed, and disagreement means something is wrong.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
frame with parity:

START | D0 D1 ... D(N−1) | P | STOP...
        └── payload ───┘   └─ derived from the payload

The field is optional. A configuration may omit it entirely, in which case the interval does not exist and the frame is one interval shorter — Chapter 3.5 assembles the choices. Where it is present, both endpoints must agree not only that it exists but on which rule computes it, and §3 gives the options.

2. Generation: an XOR Reduction

For payload bits d, the quantity that matters is the XOR of all of them:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
^d  =  d[0] ^ d[1] ^ ... ^ d[N−1]

This equals 1 when the payload contains an odd number of ones and 0 when it contains an even number. That is the entire content of the operation, and it is why parity is cheap: XOR reduction is a tree of two-input gates, with no state and no arithmetic.

Even parity makes the total number of ones across payload plus parity bit even:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
p_even = ^d

If the payload already has an even count, ^d is 0 and nothing is added. If it has an odd count, ^d is 1 and the parity bit makes the total even.

Odd parity makes that same total odd:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
p_odd = ~(^d)

Worked on two payloads that differ by a single bit, which makes the contrast visible:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
payload = 0xA6 = 1010_0110      ones = 4  (even)
  ^d = 0
  p_even = 0      total ones = 4 + 0 = 4   even  ✓
  p_odd  = 1      total ones = 4 + 1 = 5   odd   ✓

payload = 0xA7 = 1010_0111      ones = 5  (odd)
  ^d = 1
  p_even = 1      total ones = 5 + 1 = 6   even  ✓
  p_odd  = 0      total ones = 5 + 0 = 5   odd   ✓

Note what changed. A single bit of difference in the payload flips ^d, and therefore flips the parity bit in both modes. That sensitivity to a single bit is exactly the property the detection guarantee rests on, and §5 makes it precise.

3. Four Modes, Two of Which Detect Nothing

Configurations commonly expose more than even and odd, and the extra options are worth understanding precisely because their behaviour surprises people.

ModeParity interval valueDepends on payload?Detects corruption?
Even^dYesYes — see §5
Odd~(^d)YesYes — see §5
Markconstant 1NoNo
Spaceconstant 0NoNo
(none)interval absent

Mark and space place a fixed value in the parity position — always mark, or always space — regardless of what the payload contains. Since the value carries no information about the payload, a receiver comparing it against an expectation learns nothing about whether the payload was corrupted. These modes provide no error detection whatsoever, and describing them as parity is a historical courtesy rather than a description.

What they provide is a fixed, known interval at a defined position in the frame. Some systems use that deliberately — a constant marker at a known offset, or a position whose value software controls for a purpose unrelated to error detection. Whether a given UART offers these modes at all is a capability of that implementation, not something the framing guarantees.

The important consequence for a design review: a system configured for mark or space parity is paying one interval per frame and receiving no integrity checking in return. If that is intentional, fine. If someone selected it believing it was parity, the link has an error-detection mechanism that detects nothing.

4. Generation and Checking in RTL

The generation side is a small combinational function of the mode and the payload.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Synthesizable SystemVerilog — parity generation only.
// The frame sequencer (Module 7) decides WHEN this value is placed on the
// line; the configuration source (Chapter 3.5 and Module 13) supplies mode_i.
package uart_parity_pkg;
    typedef enum logic [1:0] {
        PARITY_NONE  = 2'b00,
        PARITY_EVEN  = 2'b01,
        PARITY_ODD   = 2'b10,
        PARITY_MARK  = 2'b11        // constant 1 — no detection (§3)
    } parity_mode_t;
endpackage

module uart_parity_gen #(
    parameter int unsigned DATA_W = 8
) (
    input  uart_parity_pkg::parity_mode_t mode_i,
    input  logic [DATA_W-1:0]             data_i,
    output logic                          parity_o
);
    import uart_parity_pkg::*;

    always_comb begin
        // Default first: every branch assigns, so no latch can be inferred
        // even if the enumeration gains a member later.
        parity_o = 1'b1;
        unique case (mode_i)
            PARITY_EVEN: parity_o = ^data_i;      // XOR reduction
            PARITY_ODD:  parity_o = ~(^data_i);
            PARITY_MARK: parity_o = 1'b1;
            PARITY_NONE: parity_o = 1'b1;         // unused — no interval sent
        endcase
    end
endmodule

^data_i is a reduction operator, not a bitwise XOR of two operands. It reduces the whole vector to one bit, and synthesis implements it as a tree of two-input XOR gates — balanced or otherwise according to the technology and timing constraints. The designer's intent is "the parity of these bits"; specifying the gate topology is neither necessary nor desirable.

The default assignment before the case is deliberate. unique case tells the tool the branches are mutually exclusive and expects full coverage, but an assignment on every path is what actually guarantees no latch is inferred. If the enumeration later gains a space mode, the default keeps the block combinational while the missing branch is added.

PARITY_NONE still drives an output because a combinational block must. The value is unused — the sequencer does not emit a parity interval in that mode — and driving mark rather than leaving it undefined means a design error that does emit the interval produces a benign value rather than an X.

The width is parameterised and the reduction follows it automatically, which is the whole reason to write ^data_i rather than an explicit chain of XORs.

On the receive side, the safest formulation recomputes and compares rather than relying on a Boolean identity:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Conceptual SystemVerilog — the check, not the error-reporting architecture.
// rx_data_i and rx_parity_i are the assembled payload and the observed
// parity interval; how the resulting flag is latched, reported and cleared
// is Module 9's, and the RX datapath around it is Module 6's.
uart_parity_gen #(.DATA_W(DATA_W)) u_expect (
    .mode_i   (mode_i),
    .data_i   (rx_data_i),
    .parity_o (parity_expected)
);

assign parity_error = (mode_i == PARITY_EVEN || mode_i == PARITY_ODD)
                    ? (parity_expected != rx_parity_i)
                    : 1'b0;   // none / mark / space: nothing to check

Two design points here are worth more than the code.

Reusing the generator is not laziness, it is the correctness argument. The check must apply the same rule as the transmitter, and instantiating the same module guarantees it. A hand-written receive-side expression — ^{rx_data_i, rx_parity_i} for even parity, and its inverse for odd — is shorter, correct, and a place where the odd-parity inversion gets dropped during a refactor. The synthesised logic is the same tree either way.

The mode gate is not optional. In none, mark and space modes there is nothing to check, and a design that compares anyway will report errors on every frame in mark mode the moment the payload's parity happens to differ from 1. Reporting an error where the configuration guarantees none is worse than not checking, because it destroys trust in the flag.

A transmitter applies an XOR reduction to its payload to produce a parity value, which is placed on the line after the payload intervals. A receiver assembles the payload it observed, applies the same XOR reduction to produce an expected parity value, and compares that expected value against the parity interval it actually observed. A mismatch raises a parity error. The comparison establishes that something differs from what was transmitted but does not identify whether the payload, the parity interval, or both were affected.TX payloadabout to be sentXOR reductionsame rule, both endsparity intervalone bit on the linecomparemismatch = parity errorRX payloadas assembledXOR reductionsame rule, both endsreducesendobservedreduceexpected12
Figure 1 — generation and checking as the same function evaluated twice. The transmitter reduces the payload it is about to send; the receiver reduces the payload it believes it received and compares against the interval it observed. Disagreement means the payload, the parity interval, or both differ from what was transmitted — the check does not say which.

5. What Parity Detects — Exactly

Now the guarantee, stated precisely rather than approximately.

Consider the protected set: the payload bits together with the parity interval. Parity's construction fixes the number of ones in that set to a known parity — even in even mode, odd in odd mode. A receiver checks whether the set it observed still has that property.

Flipping any single bit in the set changes the count by one and therefore flips its parity, so the property fails and the error is detected. Flipping two bits changes the count by two, or by zero if one went up and one went down — either way the parity of the count is unchanged, and the check passes.

Generalising:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
parity detects  a corruption that flips an ODD number of bits
                in the protected set — always

parity misses   a corruption that flips an EVEN number of bits
                in the protected set — always

Both halves are absolute, and that is unusual. Most error-detection mechanisms offer probabilistic coverage; parity offers a certainty in each direction. It is not that odd-weight errors are likely caught and even-weight ones likely missed — the first are caught with certainty and the second are missed with certainty.

6. Demonstrating an Undetected Error

The claim in §5 deserves a worked counterexample rather than an assertion.

Take the payload from §2 under even parity:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
transmitted payload = 0xA6 = 1010_0110      ones = 4
transmitted parity  = p_even = 0
protected set ones  = 4 + 0 = 4             even  ✓

Now corrupt two payload bits — bit 0 and bit 1:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
received payload = 0xA5 = 1010_0101         ones = 4
received parity  = 0                        (unchanged)
protected set ones = 4 + 0 = 4              even  ✓  CHECK PASSES

The count is unchanged because bit 0 went from 0 to 1 and bit 1 went from 1 to 0 — one addition, one subtraction, net zero. The receiver recomputes ^d from 0xA5, gets 0, compares against the observed 0, finds agreement, and reports no error.

The software above receives 0xA5 where 0xA6 was sent, with a parity check that passed.

Contrast with a single-bit corruption of the same payload:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
received payload = 0xA7 = 1010_0111         ones = 5
received parity  = 0                        (unchanged)
protected set ones = 5 + 0 = 5              odd   ✗  ERROR DETECTED

0xA6 with even parity — and the pair that defeats it

10 cycles
A UART line is shown over ten bit intervals. Interval zero is the start interval at the space level. Intervals one through eight carry the payload 0xA6 in least-significant-first order, giving line values zero, one, one, zero, zero, one, zero, one. Interval nine is the parity interval carrying zero, because the payload contains four ones and even parity requires an even total. Markers identify the start interval, the payload interval D0 whose individual corruption would be detected, the payload interval D1 which together with D0 forms a pair whose simultaneous corruption is not detected, and the parity interval with its computed value.STARTSTARTpayload D0..D7payload D0..D7PARITYPARITYSTARTSTARTD0 — flip alone: detectedD0 — flip alone: detectedD1 — flip BOTH: undetectedD1 — flip BOTH: undetectedP = 0 — even, 4 onesP = 0 — even, 4 oneslinet0t1t2t3t4t5t6t7t8t9
Figure 2 — an 8E1 frame carrying 0xA6. Each column is one UART bit interval, not a system-clock cycle. The payload occupies D0 through D7 in LSB-first order, and the parity interval carries 0 because the payload has an even number of ones. Flipping either D0 or D1 alone changes the count by one and is detected; flipping both leaves the count at four and passes the check, delivering corrupted data with no error reported.

The parity interval is itself protected. A corruption that flips only the parity bit, leaving the payload intact, changes the count by one and is detected — as an error, even though the payload was fine. The check reports that the set is inconsistent; it does not identify which member of the set is at fault, and it cannot correct anything.

7. Why Keep a Check This Weak

Given §6, the reasonable question is whether one interval per frame is worth it.

What it costs. One bit period per frame — roughly a tenth of the line time in a common configuration, and the difference between N_frame = 10 and N_frame = 11 that Chapter 3.5 computes. In gates, an XOR tree and a comparator.

What it buys. Certain detection of every odd-weight corruption in the protected set. On a link where corruption arrives as isolated single-bit events — a brief disturbance affecting one interval — that covers the realistic failure mode, and covers it with certainty rather than with probability.

Where it fails. Corruption that is not isolated. A timing failure of the kind Chapter 2.4 described does not flip one random bit; it displaces the sampling point so that several consecutive intervals are misread, and a multi-bit disturbance has an even weight about half the time. Parity is a poor detector of exactly the failure mode UART is most prone to, which is worth knowing before relying on it.

What the alternative would be. A cyclic redundancy check gives far stronger structured detection — bounded burst-length guarantees rather than a parity-of-count property — at the cost of more state, more logic, and more transmitted redundancy than a single interval. Protocols needing real integrity use one. Parity exists at the other end of that trade: the cheapest thing that is better than nothing, in a frame with room for exactly one extra interval.

The honest summary is that parity is a smoke detector, not a guarantee. A system whose correctness depends on detecting corruption should not rest on it; a system that would like to notice obvious damage cheaply can reasonably use it.

8. What This Means for Verification

Parity is unusually well suited to being verified thoroughly, because its guarantee is exact and the input space is small.

Cover the modes, including the ones that detect nothing. None, even, odd, and whichever of mark and space the design supports. The non-detecting modes need a test that confirms no error is reported — the §4 failure of comparing anyway shows up only in that test.

Choose payloads by their population count, not at random. A payload with zero ones, one with all ones, one with an even count and one with an odd count exercise the generation rule at its meaningful points. A single-bit-set walking pattern verifies that every payload bit actually participates in the reduction — a design that drops one bit from the XOR tree passes most random payloads and fails exactly half the walking cases.

Inject corruption by weight, and check both outcomes. A one-bit flip must be detected. A two-bit flip must not be, and a testbench should assert that as a positive expectation rather than tolerating it. This is the unusual part: verifying what the mechanism cannot do is as important as verifying what it can, because a design that reports an error on the §6 case is wrong — it has invented detection the rule does not provide, which means its check is not the specified one.

Corrupt the parity interval itself. Leaving the payload intact and flipping only the parity bit must be detected, and confirms the parity interval is inside the protected set rather than being treated as a value the receiver merely echoes.

Mismatch the two endpoints' modes. A transmitter in even mode and a receiver in odd mode disagree on every frame whose payload makes them disagree — which is every frame, since the two rules differ by inversion. The symptom is a parity error on every frame rather than an intermittent one, and that signature is worth knowing because it is diagnostic: intermittent parity errors suggest corruption; universal parity errors suggest configuration.

9. What This Means on an FPGA

The cost is genuinely negligible. An XOR reduction over eight bits is a handful of LUTs and a comparator is one more. There is no reason to omit parity support from a configurable design on resource grounds; the reason to omit it is that the frame has no room for the interval, which is a link-budget decision rather than an area one.

Compute it in parallel unless there is a reason not to. With a payload register already present, reducing the whole vector in one cycle is simpler to review than accumulating across intervals and needs no reset or clear logic. The bitwise accumulation is attractive only when the payload is never held in parallel — which, given Chapter 3.2's shift register, it usually is.

Bring the flag out during bring-up. A parity error indicator on a spare pin or in a capture separates two failure modes that otherwise look identical from software: data arriving wrong with the check passing points at a multi-bit disturbance or a configuration mismatch, while data arriving wrong with the check failing points at isolated corruption. §8's intermittent-versus-universal distinction is the first question to ask of that signal.

10. Understanding Check

11. Summary

Parity adds one interval after the payload, carrying a value derived from the payload by an XOR reduction^d, which is 1 for an odd population of ones and 0 for an even one. Even parity sends ^d; odd parity sends its inverse. Both endpoints compute the same function independently, and disagreement is the signal. Because XOR is commutative, the LSB-first serialisation of Chapter 3.2 has no effect on the result.

Mark and space modes place a constant in the interval and therefore detect nothing. They provide a fixed value at a known position, which is occasionally useful and is not integrity checking.

The guarantee is exact in both directions. Over the protected set — payload plus parity interval — parity detects every corruption that flips an odd number of bits and misses every corruption that flips an even number. Not probably: certainly, each way. "Parity detects all errors" is false, and "parity detects only single-bit errors" understates it — three flips are caught as reliably as one.

The undetected case is easy to construct. 0xA6 has four ones and even parity 0; corrupting bits 0 and 1 gives 0xA5, which also has four ones, so the check passes and corrupted data is delivered silently.

In RTL, generation is a reduction inside a fully-assigned always_comb, and checking is best done by instantiating the same generator and comparing — which guarantees the two ends apply the same rule, and keeps odd-parity inversion from being dropped in a refactor. The check must be gated by mode, because none, mark and space have nothing to check.

Parity is a smoke detector, not a guarantee. It is cheapest-possible notification of isolated damage, and it is weak against the multi-interval corruption that a mistimed UART actually produces.

12. What Comes Next

The payload is delivered and optionally checked. What remains is the frame's end — and it is the field UART material most often describes wrongly. Chapter 3.4 establishes what the stop interval actually requires, what a framing error does and does not tell an engineer, and how two frames can follow one another with no idle between them while still giving the receiver a fresh timing origin.

Browse the full path on the UART tutorials index. For a structured error-detection scheme with guarantees of a different shape, where the redundancy is sized to the burst lengths it must cover, see Why CRC Exists.

Continue learning

Where this fits

Part of the UART curriculum.