Skip to content
VLSI Mentor

UART · Module 6

Data-Valid Generation and the Receiver Handshake

A receiver cannot tell the far end to wait. That one fact decides the shape of the output interface, forces a policy for the frame that arrives while the last is still held, and explains why the answer is not a FIFO.

Chapter 6.4 leaned repeatedly on a behaviour it had not built: that a byte is held until the consumer takes it, and that the line keeps moving while it waits. Both halves of that sentence are decisions, and this chapter makes them.

It starts from a fact that shapes everything downstream, and that is easy to state and easy to forget:

A UART receiver cannot tell the transmitter to wait.

There is no return path in a bare UART link. The far end is executing a schedule it wrote (Chapter 5.1 §1) and has no mechanism to learn that the near end is behind. Whatever the receiver does with a completed byte, it must do in the time before the next one completes, and if it cannot, something is lost.

That is not a limitation to be engineered away at this layer. It is the defining property of the interface, and a receiver designed without acknowledging it will have an interface that works in testbenches and loses data in systems.

1. When Is a Byte Valid?

The candidates are not equally defensible.

When the last data bit is stored? No. The frame is not finished — parity and stop are still to come, and both can fail. Delivering here means delivering before the status that describes the byte exists, which makes Chapter 6.4's contract impossible.

When the stop bit has fully elapsed? No. That is a boundary the receiver does not locate — Chapter 6.3 showed the receiver knows interval centres, not edges, and finding the stop interval's end would need a second comparison and a second convention for no benefit.

At the stop sample. Yes. It is the last event of the frame, it is where the framing check happens, and it is the first instant at which every fact about the frame is known: the payload is complete, the parity comparison is done, and the stop level has just been read.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
A byte becomes valid at the stop sample — 9.5 UI from the candidate in 8N1,
10.5 UI in 8E1. That is the single publish point of Chapter 6.4 §4.

Delivering at the stop sample rather than at the stop interval's end also means the receiver publishes half a bit interval before the frame is physically over, which is not a problem: the remaining half interval is line time, not decision time, and the next frame's candidate cannot occur until the line returns to mark and departs again.

2. Pulse or Hold

Two interfaces, and the literature presents both as normal because both are.

One-cycle pulse. rx_valid_o rises for exactly one clock and falls. The consumer must be watching on that cycle.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Conceptual SystemVerilog — pulse interface.
rx_valid_o <= 1'b0;                    // default every cycle
if (frame_complete) begin
    rx_data_o  <= shreg_q;
    rx_valid_o <= 1'b1;                // exactly one cycle
end

Held valid with accept. rx_valid_o rises and stays high until rx_ready_i is observed.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Conceptual SystemVerilog — held interface.
if (rx_valid_o && rx_ready_i) rx_valid_o <= 1'b0;
if (frame_complete)           rx_valid_o <= 1'b1;
PulseHeld
Consumer mustsample every cyclepoll at any rate
Storage ownerthe consumerthe receiver
Missed readdata silently lost, nothing reports itbyte still there
Data stabilityone cycleuntil accepted
Overrun detectable?no — the receiver cannot knowyes
Costnoneone accept path
Suitsa FIFO or register directly attachedsoftware, a bus bridge, anything that polls

This receiver holds, and the deciding row is not the convenience one.

3. The Holding Register Owns One Frame

One register, one byte, and a contract:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
rx_data_o and the three status flags describe ONE frame.
They are written together on one edge — Chapter 6.4 §4.
They do not change while rx_valid_o is high and rx_ready_i is low.
They are released together when rx_ready_i is observed.

The stability clause is what makes the interface usable by a consumer that reads data and status in separate cycles — a software register read, for instance, which may take several bus cycles to collect all four values. If any of them could move in between, the consumer would need to re-read and compare, and the interface would have pushed a synchronisation problem across the boundary.

It is also directly assertable, and Chapter 6.4 §7 already wrote half of it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Assertion — the held byte and its status are immovable until accepted.
// This is the property that DEFINES the interface; every other statement
// in this chapter is a consequence of it.
property p_held_payload_stable;
    @(posedge clk) disable iff (!rst_n)
        (rx_valid_o && !rx_ready_i) |=>
            rx_valid_o && $stable(rx_data_o)
                       && $stable(rx_parity_err_o)
                       && $stable(rx_frame_err_o);
endproperty
assert property (p_held_payload_stable);

This property is only meaningful because the interface holds. Written against a pulse interface it would be vacuous — rx_valid_o is never high for two consecutive cycles, so the antecedent never fires. That is Chapter 6.6 §7's point about assertions matching architecture: this exact property copied into a pulse-based design would pass forever while checking nothing.

4. Nothing Stops the Wire

With the holding register defined, the consequence is unavoidable.

A byte occupies the register from its stop sample until the consumer accepts it. Meanwhile the far end continues transmitting on its own schedule. At 115,200 baud with 8N1, a frame is 10 intervals — 86.8 µs. If the consumer has not accepted within that window, a second frame completes while the first is still held.

The receiver then has exactly three options, and it must have chosen one at design time:

OptionBehaviourConsequence
Overwritenew byte replaces the held onethe byte the consumer was told about disappears; $stable is violated
Preserve and dropheld byte kept, new one discardedthe newer byte is lost, the older survives
Stall the linenot available. There is no backpressure path.
A derivation showing why a bare UART receiver has no backpressure. The transmitter emits frames according to a schedule it determined locally, sending each one onto the line without observing anything about the far end. The line delivers each frame to the receiver, which assembles it and presents the byte to its consumer with a valid signal. The consumer returns a ready signal to the receiver when it accepts the byte, and that acknowledgement stops there. No path exists from the receiver back to the line or to the transmitter, so the transmitter cannot learn that the consumer is behind and continues on its original schedule. Any frame completing while the previous byte is still held must therefore be resolved locally by the receiver.TransmitterLineReceiverConsumerframe A — on its ownschedulearrivesrx_valid_o + data +statusrx_ready_i — stopsHEREframe B —transmitter neverlearned anythingarrives while A maystill be heldno path back —resolve it locally
Figure 1 — why the third option does not exist. Every message in this exchange travels left to right. The transmitter executes a schedule it wrote and observes nothing; the receiver's only outward-facing signal, rx_ready_i, terminates at the consumer and has no continuation toward the line. There is no arrow from the receiver back to the transmitter because a bare UART link provides no wire for one.

The third is listed to be dismissed, because it is the instinct. There is no signal a bare UART receiver can assert that the transmitter will observe. RTS/CTS provides one — and it is Module 10's subject, it requires extra wires, it requires the far end to honour it, and crucially it operates a frame at a time: asserting RTS does not stop a frame already in flight. Even with flow control, this decision still has to be made.

This receiver preserves and drops. Two reasons, and the second is the stronger:

The held byte has already been announced. The receiver raised rx_valid_o and the consumer may have already begun reading. Replacing the data underneath it produces a torn read — exactly the failure §3's stability property exists to prevent — and the consumer has no way to detect that it happened.

Overwriting loses a byte the consumer knew about; dropping loses one it never saw. Both lose one frame, so the choice is not about quantity. It is about which loss the system can reason about: a consumer that read one byte and was told a later one was lost has a coherent picture, while a consumer that read a byte different from the one it was offered has been lied to.

This is a documented policy, not a discovered behaviour. Chapter 6.6's assumptions block states it, and a design that adopts the opposite policy is not wrong — it is making a different trade for a consumer that prefers freshness over coherence, which is reasonable for telemetry and unreasonable for a command stream. What is not acceptable is silently overwriting, which is what a receiver does when nobody decided.

5. The Overrun, From Simulation

Extracted from the compiled design, with the consumer deliberately not ready:

timeeventrx_data_orx_valid_orx_overrun_o
6.21 µsframe A (0x3C) completes0x3C10
consumer busy; A is held0x3C10
12.62 µsframe B (0xC3) completes0x3C11
13.23 µsconsumer accepts0x3C00
19.66 µsframe C (0x5A) completes0x5A10

At 12.62 µs the data does not move. Frame B is discarded, frame A survives intact, and the overrun flag records that a frame was lost — the interface saying the thing a pulse interface cannot say.

At 13.23 µs the accept clears valid and every flag together, because they all belong to the frame being released.

At 19.66 µs frame C arrives clean with overrun clear, which is the check that matters for the flag's lifetime: rx_overrun_o describes this byte's tenure in the register, not a running history. A sticky version that persists until software reads it is a different contract, and Module 9 owns it.

Frame lost while the consumer is behind

6 cycles
A sequence of six frame-level events. The first frame completes and its byte, 3C hexadecimal, is placed in the holding register with valid asserted and overrun clear. The consumer does not assert ready, so the byte is held. A second frame carrying C3 hexadecimal then completes while the first is still held: the held data remains 3C, unchanged, and the overrun flag is raised to record that a frame was discarded. When the consumer finally asserts ready, valid and the overrun flag clear together. A third frame carrying 5A hexadecimal then completes normally with the overrun flag clear, showing that the flag describes only the tenure of the byte it accompanied.frame A held — consumer behindframe A held — consumer behindconsumer keeping upconsumer keeping upB dropped — data UNCHANGEDB dropped — data UNCHANGEDaccept clears all flagsaccept clears all flagsC clean, overrun clearC clean, overrun cleareventA doneheldB doneacceptC doneacceptrx_data_o3C3C3C3C5A5Arx_valid_orx_ready_irx_overrun_ot0t1t2t3t4t5
Figure 2 — the overrun sequence. Columns are FRAME EVENTS, not clock cycles and not bit intervals; each transition is separated by roughly one frame time, 86.8 microseconds at 115,200 baud with 8N1. The held data does not change when the second frame completes, which is the preserve-and-drop policy visible as a flat bus row across the event that would otherwise have overwritten it.

6. Back-to-Back Frames Are Not an Overrun

A frame arriving immediately after another — no idle gap, the next start bit beginning as soon as the stop interval ends — is normal traffic, and the receiver must handle it at full rate.

It does, and the reason is structural rather than a special case. The stop sample publishes the byte and returns the FSM to S_IDLE half a bit interval before the stop interval ends (Chapter 6.2 §2). The receiver is therefore already watching for a candidate when the next start transition arrives. Simulation confirms two adjacent frames are received correctly with no gap.

No minimum idle time is required, and a receiver that needs one has a defect worth locating: usually an FSM that waits for the stop level rather than the stop sample (Chapter 6.2 §4's wedging hazard in a milder form), or a delivery path that takes several cycles between the stop sample and returning to idle.

The distinction from §5 is worth being precise about, because both involve two frames close together:

Back-to-backOverrun
Causethe transmitter sends without gapsthe consumer does not read in time
Receiver behaviourreceives both correctlykeeps the first, drops the second
Is it an error?no — normal trafficyes, and it is reported
Fixed bynothing — already correctreading faster, or a FIFO

A receiver that reports overrun on back-to-back frames has a consumer-side problem being misreported as a line-side one.

7. Why the Answer Is Not a FIFO

The obvious response to §5 is to add buffering, and it is the right response — at the right layer.

A FIFO does not remove the overrun; it moves the threshold. A single holding register overruns when the consumer is more than one frame time behind; a sixteen-deep FIFO overruns when it is more than sixteen frame times behind. If the consumer's average rate is below the line rate, every depth eventually overflows — buffering converts a hard real-time requirement into an average-rate requirement, which is a genuine and large improvement, and not the same as solving it.

So the receiver core deliberately stops at one register:

The overrun semantics have to exist anyway. Whatever sits downstream, the receiver must define what happens when its output cannot be accepted. A FIFO is a consumer with a deeper appetite, not a different contract.

Depth is a system decision, not a receiver decision. It depends on interrupt latency, on the software's polling interval, on whether DMA is present. None of that is knowable from inside the receiver, and Module 10 is where it is decided with the relevant facts in hand.

The FIFO's own interface is this one. An RX FIFO attaches to rx_valid_o / rx_ready_i and is very often unconditionally ready — which, per §2, is precisely the case where a pulse would have been adequate. The held interface composes with a FIFO without loss; a pulse interface would have prevented anything else from attaching.

8. Verification

Stall the consumer. The single most valuable receiver test, and the one that exposes Chapter 6.4 §4's status-ownership defect as well as this chapter's overrun policy. A bench that always drives rx_ready_i high exercises neither.

Assert the policy, not just the flag. rx_overrun_o rising proves something was noticed. What matters is that rx_data_o did not change across the event — the preserve-and-drop policy is the claim, and the flag alone does not test it.

Sweep the consumer's latency across a frame time. Accepting at 0, 0.5, 1 and 2 frame times after valid covers the comfortable case, the marginal case, the first overrun and the sustained-loss case. The boundary at exactly one frame time is where a design with an extra cycle of delivery latency starts failing.

Drive back-to-back frames continuously, and assert that no overrun occurs while the consumer keeps up. This separates the two failure modes of §6, which are easily conflated in a bug report.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Assertion — the preserve-and-drop policy, stated as a property.
// A rising overrun must NOT be accompanied by a change in the held data.
property p_overrun_preserves_data;
    @(posedge clk) disable iff (!rst_n)
        $rose(rx_overrun_o) |-> $stable(rx_data_o);
endproperty
assert property (p_overrun_preserves_data);

// Assertion — valid is released only by an accept, never spontaneously.
property p_valid_falls_only_on_accept;
    @(posedge clk) disable iff (!rst_n)
        $fell(rx_valid_o) |-> $past(rx_valid_o && rx_ready_i);
endproperty
assert property (p_valid_falls_only_on_accept);

// Assertion — overrun cannot be reported when no byte is held, because
// there was nothing for the incoming frame to collide with.
property p_overrun_requires_held_byte;
    @(posedge clk) disable iff (!rst_n)
        $rose(rx_overrun_o) |-> $past(rx_valid_o);
endproperty
assert property (p_overrun_requires_held_byte);

The second is worth its line: a receiver that drops valid because an internal timeout expired, or because a new frame started, has silently converted the held interface into something weaker, and no data-comparison test detects it.

9. What This Means on an FPGA

The accept path is one AND gate. rx_valid_o && rx_ready_i clears the register set. This is not a place where the held interface costs anything measurable.

rx_ready_i must not be combinationally derived from rx_valid_o. A consumer that computes ready from valid in the same cycle creates a combinational loop through the receiver's clear logic. Every mainstream handshake convention has this rule; it is stated here because a bus bridge written quickly is exactly where it gets violated, and the symptom is a design that fails timing in a way that points nowhere useful.

Probe rx_valid_o and rx_ready_i together during bring-up. Valid rising and never falling means the consumer is not accepting — a software or plumbing problem, not a line problem, and it is distinguishable from every line-side failure in one glance. Adding rx_overrun_o to the same capture tells you immediately whether data has already been lost.

One frame time is the budget, and it is generous. 86.8 µs at 115,200 baud is thousands of clock cycles at any sensible fabric frequency. A consumer missing that budget is almost never too slow to execute; it is usually blocked, in a long interrupt handler, or polling on a timer slower than the line rate. That distinction is what the overrun flag points at.

10. Understanding Check

11. Summary

A UART receiver cannot tell the transmitter to wait. Whatever it does with a completed byte must happen before the next one completes, and that fact shapes the entire interface.

A byte becomes valid at the stop sample — the first instant every fact about the frame is known, and the single publish point Chapter 6.4 established.

Held valid is chosen over a one-cycle pulse, and the deciding argument is not convenience: a pulse interface cannot express overrun, because a missed read is indistinguishable from a deliberate one. The pulse form is right when the consumer is a FIFO or register that is unconditionally ready — which is exactly how Module 10 attaches.

The holding register owns one frame. Data and status are written together, do not move while held, and are released together — a property that is directly assertable, and that would be vacuous against a pulse interface.

When a frame completes while a byte is held, three options exist and one is unavailable. There is no backpressure path; RTS/CTS is Module 10's and operates a frame at a time. This receiver preserves and drops, because overwriting replaces a byte the consumer was already offered — losing coherence rather than just data. Simulation shows it: frame B completes, rx_data_o stays at 0x3C, rx_overrun_o rises.

Back-to-back frames are not an overrun — they are normal traffic the receiver handles with half a bit interval to spare, and confusing the two misattributes a consumer problem to the line.

A FIFO moves the threshold, it does not remove it. Depth is a system decision made with facts the receiver does not have.

12. What Comes Next

Five chapters have specified a receiver completely: a partition with stated contracts, a state machine with eight enumerated transitions, two counters with derived widths and stated semantics, two validation checks with a publish discipline, and an output interface with a documented overrun policy.

Chapter 6.6 assembles it. One synthesizable module, walked block by block with the invariant each part maintains, preceded by the assumptions block that says exactly what it does and does not support. Then it does what a module of this kind should end with: reviews itself the way a reviewer would — the questions to ask of each subsystem, the corner cases that break each assumption, the failure signature each defect produces, and the verification that would have caught it. It also reports what the RTL was actually compiled and simulated with, and what that does and does not prove.

Browse the full path on the UART tutorials index. For the per-frame status this interface carries, read back to Chapter 6.4.

Continue learning

Where this fits

Part of the UART curriculum.