UART · Module 7
TX Datapath and Parallel-to-Serial Conversion
The datapath that turns a parallel word into a bit stream — why the transmitter must capture the payload rather than index a live bus, how LSB-first emission falls out of a right shift, and where the frame's fixed bits come from.
Module 6 built a receiver that had to infer everything: where a frame began, when to look, whether what it saw was real. Every mechanism in it existed because the receiver had no advance knowledge.
The transmitter has the opposite problem, which is barely a problem at all. Chapter 5.1 stated the asymmetry in one line:
The transmitter executes a schedule it wrote. The receiver makes four judgements from one edge.
A transmitter needs no synchroniser, no oversampling, no start qualification, no majority voting and no sampling-position arithmetic. It knows the byte, it knows the configuration, and it decides when each interval begins. The entire timing problem reduces to: hold each level for exactly one bit period.
What remains is still worth doing carefully, and this chapter is about the half of it that is pure datapath: turning a parallel word into the right sequence of levels, and — the part that is easy to get subtly wrong — making sure the word cannot change underneath you while you do it.
1. What the Datapath Must Produce
From Chapter 3.1 and Chapter 3.5, a frame is a fixed sequence of one-bit-period levels:
| Field | Level | Source |
|---|---|---|
| idle | mark (1) | a constant |
| start | space (0) | a constant |
data[0] … data[DATA_W−1] | the payload, LSB first | the shift register |
| parity (optional) | derived from the payload | an XOR reduction |
| stop | mark (1) | a constant |
Three of those five are constants, which is worth noticing early: the transmitter's datapath does not need a general mux over a frame buffer. It needs a payload serialiser, a parity bit, and the ability to drive a constant. The sequencing — which of those is selected right now — is control, and Chapter 7.2 owns it.
That split is why this chapter can be read without a state machine in it.
2. The Concrete Example
Use an asymmetric byte. 0x00, 0xFF, 0x55 and 0xAA are the obvious choices and every one of them is a bad demonstration of bit order — §7 shows why.
payload 0x53 = 0101_0011
bit position 7 6 5 4 3 2 1 0
value 0 1 0 1 0 0 1 1
emission order (LSB first):
D0 D1 D2 D3 D4 D5 D6 D7
1 1 0 0 1 0 1 0The complete 8N1 wire sequence, machine-computed and confirmed against the simulated design:
field IDLE START D0 D1 D2 D3 D4 D5 D6 D7 STOP
level 1 0 1 1 0 0 1 0 1 0 1
└──────── payload, LSB first ───────┘
frame length = 1 start + 8 data + 0 parity + 1 stop = 10 bit intervalsNote that 0x53 and its bit-reversal 0xCA are different bytes, which is exactly what makes it a usable test vector. §7 returns to this.
3. Two Ways to Serialise
Both are correct. They are not equivalent in hardware.
Indexed register — keep the payload still and move a pointer across it:
// Conceptual SystemVerilog — indexed serialisation.
// Correct, and not what this transmitter uses.
assign serial_bit = data_q[bit_idx_q];Shift register — keep the pointer still and move the payload past it:
// Synthesizable SystemVerilog — the form Chapter 3.2 §6 established.
// THE INVARIANT: shreg_q[0] is always the next payload bit to place on
// the line. Everything else follows from maintaining it.
assign serial_bit = shreg_q[0];
// ... and on each bit boundary:
shreg_q <= shreg_q >> 1;| Indexed | Shift | |
|---|---|---|
| Logic | a DATA_W-to-1 mux driven by bit_idx_q | a fixed wire from bit n+1 to bit n |
Scales with DATA_W as | mux grows | unchanged |
| Needs the bit counter? | yes — as the select | no — only control needs it |
| Payload after emission | intact | consumed |
| Debug visibility | the whole byte stays readable | remaining bits only |
This transmitter shifts, for two reasons.
It matches what is already published. Chapter 3.2 established shreg[0] as the invariant, and a Module 7 that switched to indexing would contradict a live chapter for no gain.
It removes the counter from the datapath, exactly as Chapter 6.3 §6 did on the receive side. bit_idx_q then exists only to tell the control machine when the payload field ends, and the datapath has no select logic at all.
4. The Payload Must Be Captured
This is the part that is easy to get wrong, and the error is invisible in most testbenches.
The tempting datapath reads the producer's bus directly:
// WRONG — the transmitter has no control over tx_data_i.
assign serial_bit = tx_data_i[bit_idx_q];It works perfectly whenever the producer happens to hold tx_data_i stable for the whole frame. A frame at 115,200 baud is 86.8 µs (Chapter 4.1); the producer is a piece of logic that wrote a byte and moved on. Nothing in the interface obliges it to hold that value for eight and a half thousand clock cycles, and nothing tells it that it must.
The consequence when it does not is characteristic: the first bits of the byte are correct and the later ones belong to a different byte. The frame is well-formed — correct length, correct start and stop, parity computed over a payload that was never transmitted — so every structural check passes and the data is simply wrong, intermittently, in a way that correlates with how busy the producer is.
The fix is a register and a rule:
// Synthesizable SystemVerilog — capture at acceptance.
// After this edge, tx_data_i may change freely: the transmitter is
// working from its own copy and the producer owns nothing.
if (accept) begin
shreg_q <= tx_data_i;
endCapture is an ownership transfer. Before acceptance the producer owns the value and must hold it; after acceptance the transmitter owns a copy and the producer is free. Chapter 7.4 makes the acceptance condition precise; what matters here is that the datapath never reads anything it does not own.
The shift register is the capture register. There is no separate data_q — the payload is loaded straight into shreg_q, which is free whenever the transmitter is able to accept. That is one register rather than two, and it is what makes the back-to-back behaviour of Chapter 7.4 possible without a buffer.
5. The Same Argument Applies to Configuration
If parity mode is a runtime input, it has exactly the same problem, and it is less obvious because configuration feels static:
// WRONG — parity_mode_i can change mid-frame.
// The frame then has a parity bit computed under one rule and a field
// layout decided under another.A producer that reconfigures the UART while a frame is in flight is not misbehaving — nothing told it not to. The transmitter's defence is the same register discipline:
// Synthesizable SystemVerilog — freeze the frame's format at acceptance.
if (accept) begin
shreg_q <= tx_data_i;
par_q <= parity_of(parity_mode_i, tx_data_i);
mode_q <= parity_mode_i; // this frame's format, fixed
endmode_q — not parity_mode_i — decides whether this frame has a parity interval at all. Chapter 7.2's state machine reads the captured copy, so a mid-frame configuration change affects the next frame and not this one. Chapter 7.5 returns to this as the chapter's named subject.
If parity mode were a parameter instead, the problem would not exist — a parameter cannot change at all. That is a legitimate design, and the trade is the one Chapter 6.1 §5 set out: a parameter changes the hardware, an input selects a path through hardware that already exists.
6. Parity Enters the Datapath Once
The receiver accumulated parity bit by bit, because it only had the bits as they arrived (Chapter 6.4 §1). The transmitter has the whole payload at capture, so it has a choice the receiver did not:
| Compute at capture | Accumulate while shifting | |
|---|---|---|
| Logic | one XOR tree over DATA_W bits | one XOR gate |
| State | one flip-flop | one flip-flop |
| When available | immediately | only after the last shift |
| Depends on | tx_data_i at one instant | the shifting being correct |
This transmitter computes at capture. The XOR tree is three levels at DATA_W = 8 and closes at any frequency a UART runs at, and computing once means the parity bit is a stored constant for the whole frame rather than a value that depends on the shift register still being right.
That last point is the real argument. An accumulate-while-shifting transmitter computes parity from the same signal path it is serialising, so a shift defect corrupts the data and the parity in a correlated way — and a receiver checking that frame may find the parity consistent with the corrupted payload. Computing from the captured word keeps the two independent.
The rule itself is Chapter 3.3's, unchanged:
// Synthesizable SystemVerilog — the transmitter's parity, one function.
// Identical rule to the receiver's expectation in Chapter 6.4 §2, which is
// the correctness argument: both ends must apply the same reduction.
function automatic logic parity_of(input parity_mode_t m,
input logic [DATA_W-1:0] d);
case (m)
PARITY_EVEN: parity_of = ^d; // XOR reduction
PARITY_ODD: parity_of = ~(^d);
default: parity_of = 1'b1; // MARK — constant, no detection
endcase
endfunctionMachine-computed for the standard patterns:
| byte | ones | ^d | even parity bit | odd parity bit |
|---|---|---|---|---|
0x00 | 0 | 0 | 0 | 1 |
0xFF | 8 | 0 | 0 | 1 |
0x55 | 4 | 0 | 0 | 1 |
0xAA | 4 | 0 | 0 | 1 |
0x01 | 1 | 1 | 1 | 0 |
0x80 | 1 | 1 | 1 | 0 |
0x53 | 4 | 0 | 0 | 1 |
0xA6 | 4 | 0 | 0 | 1 |
Six of these eight bytes have even weight. Only 0x01 and 0x80 exercise the other branch — a fact that cost real debugging time while verifying this module, and §7 explains how.
7. The Patterns That Prove Bit Order, and the Ones That Cannot
Machine-computed. "Reversed" is what the byte becomes if the transmitter emits MSB first:
| byte | binary | D0…D7 | emitted MSB-first | detectable? |
|---|---|---|---|---|
0x00 | 0000_0000 | 0 0 0 0 0 0 0 0 | 0x00 | no — palindromic |
0xFF | 1111_1111 | 1 1 1 1 1 1 1 1 | 0xFF | no — palindromic |
0x55 | 0101_0101 | 1 0 1 0 1 0 1 0 | 0xAA | yes |
0xAA | 1010_1010 | 0 1 0 1 0 1 0 1 | 0x55 | yes |
0x01 | 0000_0001 | 1 0 0 0 0 0 0 0 | 0x80 | yes — unambiguous |
0x80 | 1000_0000 | 0 0 0 0 0 0 0 1 | 0x01 | yes — unambiguous |
0x53 | 0101_0011 | 1 1 0 0 1 0 1 0 | 0xCA | yes — unambiguous |
0xA6 | 1010_0110 | 0 1 1 0 0 1 0 1 | 0x65 | yes |
0x00 and 0xFF are palindromic and cannot detect a reversed serialiser. They are also the two bytes most likely to be written first in a bring-up test, because they are the easiest to recognise on a scope.
0x55 and 0xAA reverse into each other, which means a reversal is detected, but the failure presents as "I sent 0x55 and got 0xAA" — and since both are in the test set, the natural reading is a mix-up in the testbench rather than a defect in the DUT.
0x01, 0x80 and 0x53 are unambiguous: their reversals are not in any plausible test set, so a reversal is immediately legible as a reversal. 0x53 → 0xCA is the signature to recognise.
8. The Datapath, Assembled
The shift register's behaviour over one payload field, extracted from simulation of the assembled transmitter:
Payload field of 0x53, LSB first
11 cyclesRead the tx_o row against §2: 0 · 1 1 0 0 1 0 1 0 · 1. That is 0x53, LSB first, with its start and stop intervals — the sequence the reference model predicted and the simulator produced.
9. Verification
Check the wire, not the register. The transmitter's architectural output is tx_o. A testbench that inspects shreg_q is checking an implementation detail and will pass on a design whose output mux is wrong. Chapter 7.5 builds a monitor that reconstructs bytes from the line alone.
Use patterns chosen by property, not by appearance. §7's table is the argument: 0x00 and 0xFF cannot detect a reversal, and 0x55/0xAA detect it ambiguously. Include 0x01, 0x80 and 0x53.
Choose parity patterns by weight. §6's table shows six of eight standard bytes share even weight, so a parity test set drawn from them exercises one branch. This is not hypothetical: while verifying this module, a defect that mis-handled odd parity passed on six patterns and failed only on 0x01 and 0x80 — the two odd-weight bytes — which is what made it visible at all.
Change tx_data_i immediately after acceptance. This is the test that catches §4's defect, and a bench that politely holds the bus stable will never fail it. Drive the payload, wait for acceptance, then scribble a different value onto tx_data_i and confirm the emitted frame still carries the captured byte.
Change parity_mode_i mid-frame and confirm the frame in flight keeps its original format. Same argument, and Chapter 7.5 makes it an assertion.
10. What This Means on an FPGA
The shift register is flip-flops and wires. DATA_W registers with a load mux — nothing here infers a RAM or an SRL, and if a tool reports either, DATA_W has been parameterised far beyond what a UART needs.
The XOR tree is small and off the critical path. At DATA_W = 8 it is three levels of LUT logic, evaluated once at capture and then stored. It never sits between a register and the pin.
The capture registers are the ownership boundary and should be visible during bring-up. Probing shreg_q alongside tx_o answers the first question in a data-corruption investigation: if the register holds the byte the producer intended, the defect is in emission; if it does not, the defect is in capture or in the producer's timing.
tx_o must idle at mark. That is a datapath consequence with a board-level effect — a transmitter whose output floats or resets low presents a permanent start condition to the far end. Chapter 7.5 §6 covers the reset behaviour; the datapath's part is simply that the idle level is a constant 1 and not an undriven register.
11. Understanding Check
12. Summary
The transmitter executes a schedule it wrote, so none of the receiver's inference machinery applies. Its whole timing problem is holding each level for one bit period.
A frame's five fields come from three places: constants for idle, start and stop; the shift register for the payload; an XOR reduction for parity. Which one drives the line at any moment is control, not datapath.
Serialisation is a right shift with emission from bit 0, matching Chapter 3.2's published invariant and removing the bit counter from the datapath entirely. The receiver shifts the same direction for the mirrored reason — but the code is not symmetric, and writing one by reversing the other produces a reversed byte.
The payload must be captured, because nothing obliges the producer to hold its bus for 86.8 µs. The failure is structurally invisible: correct frame, correct parity, wrong data, intermittently. Capture is an ownership transfer, and the shift register doubles as the capture register.
Configuration needs the same discipline. mode_q and par_q are frozen at acceptance so a mid-frame reconfiguration affects the next frame, not this one.
Parity is computed once, at capture, because the transmitter has the whole payload — and because deriving it from the shifting path would let a serialisation defect produce a self-consistent corrupt frame.
And the test patterns are chosen by property: 0x00/0xFF are palindromic and cannot detect a reversal; 0x55/0xAA detect it ambiguously; 0x01, 0x80 and 0x53 are unambiguous. Six of the eight standard bytes share even weight, so odd parity is exercised only by 0x01 and 0x80.
13. What Comes Next
The datapath can produce every level a frame needs and has no idea which one to produce.
Chapter 7.2 builds the control machine. It derives the state graph from the frame structure rather than drawing it, specifies the tx_o source for every state, shows the single place where the captured configuration steers the path, and handles the transition out of the last data bit — the one that produces the classic off-by-one, where a comparison against DATA_W instead of DATA_W − 1 emits nine data bits and everything after them is displaced.
Browse the full path on the UART tutorials index. For the receiver this transmitter is the complement of, read Chapter 6.6.
Continue learning
Related tutorials
- Related topic
Data Bits and LSB-First Transmission
Three different orderings get called bit order: numerical significance, array index, and time on the wire. UART fixes only the third, and the byte is never reversed — a verified byte-to-wire walkthrough, the shift-register invariant, and how to annotate a capture without fooling yourself.
- Related topic
RX Datapath and Block Partitioning
Module 5 built the receiver's timing mechanisms as separate demonstrators. Assembling them means deciding which blocks exist, what each owns, and what contract joins them — including the two oversample counters that must merge into one.
- Related topic
Sample Counters, Bit Counters and the RX Shift Register
Two counters and a shift register, with every width derived from the parameters and every semantic stated before the RTL — plus the simulator-extracted trace of a byte being reassembled, and why the bit counter wrapping to zero is harmless.
- Related topic
The TX FSM and Frame Sequencing
Five states, eight transitions, and one rule that keeps the line honest: tx_o is a register written only inside the bit-boundary branch. Includes the off-by-one that emits nine data bits, and the state table the RTL was checked against.
Where this fits
Part of the UART curriculum.
