Skip to content
VLSI Mentor

UART · Module 15

Baud Mismatch, Reset-During-Traffic and Boundary Stress

The three stresses that find real UART bugs, measured: the recovery window against its arithmetic prediction, a mid-frame reset that delivers a wrong byte with no error anywhere, and the FIFO boundary that hid a defect through an entire suite.

The faults of Chapter 15.4 are single-frame events. These three are not: they are conditions that persist, or that straddle a boundary, and each of them found something.

One confirms a prediction to within a fraction of a percent. One produces a silently wrong byte with no error reported anywhere in the system. One hid a genuine defect through sixty-two passing checks.

1. Baud Mismatch: a Prediction and a Measurement

The two ends of a UART link never agree exactly. Each has its own oscillator, and the question is how far apart they may drift before the link stops working.

The arithmetic is short. A receiver samples the last data bit 8.5 bit periods after the start edge, so accumulated error must stay under half a bit:

0.5 / 8.5 = 5.88%

And the measurement, sweeping the driver's rate from −10% to +10% while the receiver's stays nominal:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  [info] recovery window: -6% to 6% (13 of 21 offsets OK)
  PASS the sweep found BOTH working and failing rates -- a real edge exists
  PASS recovery survives at least +/-4% of baud error
  PASS and fails beyond +/-7%, as 0.5/8.5 = 5.9% predicts

±6% against a prediction of ±5.88%, and the same window falls out of the Verilog, SystemVerilog and VHDL implementations independently.

A derivation of the UART baud mismatch test. A test sequence chooses a bit period offset between minus ten and plus ten percent and hands it to the line driver as an argument. The driver transmits a frame at that deliberately wrong rate. The receiver samples using its own nominal bit period, so the error between the two accumulates across the frame: half a bit period of error by the eighth data bit is the point at which the sample lands in the wrong bit. The scoreboard records whether the byte survived, and the sweep reports the widest offset in each direction that still recovered, which is compared against the arithmetic prediction of one half divided by eight point five, or five point eight eight percent.SweepDriverReceiverVerdictbit period, off bye%a frame at the wrongratesamples on ITS OWNperiodbyte, or a framingerrorwidest e% that stillworksmeasured +/-6% vs5.88% predicted
Figure 1 — the baud-mismatch test. The driver's bit period is swept while the receiver's stays nominal, and each offset is scored on whether the byte survives. The sampling error accumulates across the frame, so the last data bit is the one that fails first — which is why the budget is set by 8.5 bit periods rather than by one.

2. Reset During Traffic: the One That Reports Nothing

Assert reset on the transmitter part-way through a frame. Three observers, three answers.

The property checker of Chapter 15.2 reports nothing:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  after one clean frame : fail=0 mask=00000000
  mid-frame             : busy=1 line=1
  during reset          : busy=0 line=1
  after release         : fail=0 mask=00000000 line=1
  clean frame after     : fail=0 mask=00000000 frames=1

T8 — busy does not drop mid-frame — is exactly the property this should violate, and it does not fire. The checker shares the DUT's reset. When reset asserts, the checker is reset too: in_frame goes false, the tick counter clears, and the fact that a frame was in progress is erased from the only thing that was watching.

And the far end sees a perfectly well-formed frame:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  far end saw 1 frame(s)
    frame 0 : data=0x0fd  parity_err=0  framing_err=0
  (the byte actually requested was 0xA5)

No parity error. No framing error. One frame, correctly structured, carrying 0xFD where 0xA5 was requested.

The arithmetic is exact. 0xA5 is 1010_0101, sent least significant first: 1, 0, 1, 0, 0, 1, 0, 1. The reset landed after three data bits had gone out, and reset forces the line to MARK — so the remaining five bits are read as ones:

1, 0, 1 then 1, 1, 1, 1, 1 = 1011_1111 = 0xFD

The stop interval is MARK, which is legal. The frame is well-formed. Nothing in the protocol distinguishes it from a deliberate transmission of 0xFD.

This is Chapter 12.4 §4's finding — a well-formed frame with the wrong byte — reproduced from the verification side, with the byte value derived rather than observed.

The only thing that detects it is a scoreboard, comparing the byte requested against the byte received. No status bit, no assertion, and no amount of error injection.

3. FIFO Boundaries: the One That Hid a Defect

Chapter 15.3 §6 records this in full; it belongs here as a boundary.

The FIFO boundaries worth targeting are not "empty" and "full" — those are reached constantly. They are the simultaneous cases:

BoundaryWhy it is a corner
push into an empty FIFO with a pop in the same cyclethe pop must not consume the byte being pushed
push into a full FIFO with a pop in the same cyclethe two candidate acceptance rules disagree here and nowhere else
pop from a FIFO at level 1 with a push in the same cyclethe level passes through zero and back
the level at DEPTH−1the last cycle before full asserts

The second row is the one that mattered. A mutant carrying the wrong acceptance rule survived sixty-two passing checks across three languages and 4,079 clocks of random push/pop traffic, because:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  clocks=4079   push+pop while FULL occurred 0 times

Not rarely. Zero. push and pop were independent random bits, the FIFO spends very little of a random walk at exactly full, and the joint condition never arose.

Five lines of directed stimulus killed it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
for (i = 0; i < DEPTH; i = i + 1) @(negedge clk) push = 1'b1;
@(negedge clk) push = 1'b0;
repeat (2) @(negedge clk);
@(negedge clk) push = 1'b1; pop = 1'b1;        // both, while full
@(negedge clk) push = 1'b0; pop = 1'b0;

Randomisation has no reason to prefer a corner. It explores the space in proportion to how large each region is, and a corner is by definition the smallest region there is. What tells you a corner was missed is a coverage bin; what reaches it is a directed test.

4. Module 15 Verification Evidence

Every listing published in this module was extracted from the page, compiled with a real tool, and simulated.

Three components, three languages, nine implementations:

ComponentSystemVerilogVerilog-2001VHDL-2008 + PSLChapter
uart_fifo_assert✅✅✅15.2
uart_tx_assert✅✅✅15.2
uart_cov✅✅✅ (package)15.3

The checkers are bound to designs this curriculum published earlier and did not modify: the transmitter of Chapter 7.1 and the FIFO of Chapter 10.2.

Nine testbenches, identical check counts across all three languages:

SuiteChecksVerilog-2001SystemVerilogVHDL-2008
uart_fifo_assert2020 / 020 / 020 / 0
uart_tx_assert1818 / 018 / 018 / 0
uart_cov2424 / 024 / 024 / 0
Total per language6262 / 062 / 062 / 0

186 checks across the three languages, 0 failures. Tooling: Icarus Verilog 13.0 (-g2001, -g2012) and NVC 1.23.0 with --psl.

Mutation campaign — twelve defects, twelve killed:

#ComponentDefect installedResult
M1fifoP4 compares against the current cycle's push/popkilled, 7
M2fifoP2 made one-directionalkilled, 1
M3fifoP7 deletedkilled, 1
M4fifoacceptance rule simplified to push && !fullsurvived, then killed
M5fifoP8 deletedkilled, 1
M6txT1 (idle line is MARK) deletedkilled, 1
M7txT6 checks the start bit one tick earlykilled, 3
M8txT2 reverted to ready-and-busy-exclusivekilled, 3
M9txT5 frame-length bound made inclusivekilled, 2
M10covthe cross bin never incrementedkilled, 3
M11covhole counting skips the crosskilled, 2
M12covthe DEPTH−1 level bin folded into the middlekilled, 2

M4 is the module's result. It survived the entire suite, the coverage instrumentation explained why in one number, five lines of directed stimulus killed it, and the campaign closed at twelve of twelve.

5. Verification

Assert on both sides of a boundary. The baud sweep requires a working region and a failing one; without the second, the test passes on a receiver that measures nothing.

Compare a measurement against its arithmetic. ±6% against 5.88% is evidence that the design and the theory describe the same thing. A measurement with no prediction to check it against is a number.

Put at least one observer outside the reset domain. A checker reset with the design cannot see anything about a reset event, by construction.

Target simultaneous boundaries, not single ones. Empty and full are reached constantly; push-and-pop-at-full was reached zero times in 4,079 clocks.

Use coverage to find the corner and a directed test to reach it. Randomisation explores in proportion to region size, and a corner is the smallest region there is.

And do not expect a stress test to raise an error flag. Two of this chapter's three stresses produce no error status anywhere — one because the checker is blind to it, one because the resulting frame is genuinely well-formed.

6. Debugging

7. Understanding Check

8. Summary

Baud tolerance measured at ±6% against an arithmetic prediction of 5.88%, consistently across three independent implementations — and asserted on both sides of the edge, because a one-sided check passes on a receiver that measures nothing.

A mid-frame reset produces no error anywhere in the system. The property checker is blind to it because it shares the DUT's reset; the far end receives one well-formed frame carrying 0xFD instead of 0xA5, and nothing in the protocol distinguishes that from a deliberate transmission.

Only a scoreboard detects it — the same conclusion Chapter 15.4 reached about a truncated stop bit.

The FIFO boundary worth targeting is the simultaneous one, and it hid a real defect through 62 passing checks and 4,079 clocks of random traffic by occurring exactly zero times.

Twelve mutants, twelve killed, with the twelfth requiring a coverage observation rather than a better checker.

And six property bugs, none of them in a design: four about timing, one about the specification, one about folklore. A property file is a program, and the most expensive way it fails is by being confidently wrong about a correct design.

9. What Comes Next

Module 15 is complete, and with it the evidence layer. The UART now has properties that hold continuously, coverage that says what was exercised, and injected failures that prove detection works.

Module 16 rebuilds the whole environment in UVM: the agent, sequencer, driver and monitor as classes; sequences as objects that can be composed and randomised; the factory and configuration database that let one environment serve many tests; and the analysis ports that connect a scoreboard without wiring. The roles do not change — Modules 14 and 15 defined them — and what changes is that the properties and coverage written here become components that travel with the agent rather than files bound to one instance.

Browse the full path on the UART tutorials index. For the coverage observation that closed this module's last mutant, read back to Chapter 15.3.

Continue learning

Where this fits

Part of the UART curriculum.