Skip to content
VLSI Mentor

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:

FieldLevelSource
idlemark (1)a constant
startspace (0)a constant
data[0]data[DATA_W−1]the payload, LSB firstthe shift register
parity (optional)derived from the payloadan XOR reduction
stopmark (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.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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  0

The complete 8N1 wire sequence, machine-computed and confirmed against the simulated design:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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 intervals

Note 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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;
IndexedShift
Logica DATA_W-to-1 mux driven by bit_idx_qa fixed wire from bit n+1 to bit n
Scales with DATA_W asmux growsunchanged
Needs the bit counter?yes — as the selectno — only control needs it
Payload after emissionintactconsumed
Debug visibilitythe whole byte stays readableremaining 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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;
end

Capture 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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
end

mode_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 captureAccumulate while shifting
Logicone XOR tree over DATA_W bitsone XOR gate
Stateone flip-flopone flip-flop
When availableimmediatelyonly after the last shift
Depends ontx_data_i at one instantthe 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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
endfunction

Machine-computed for the standard patterns:

byteones^deven parity bitodd parity bit
0x000001
0xFF8001
0x554001
0xAA4001
0x011110
0x801110
0x534001
0xA64001

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:

bytebinaryD0…D7emitted MSB-firstdetectable?
0x000000_00000 0 0 0 0 0 0 00x00no — palindromic
0xFF1111_11111 1 1 1 1 1 1 10xFFno — palindromic
0x550101_01011 0 1 0 1 0 1 00xAAyes
0xAA1010_10100 1 0 1 0 1 0 10x55yes
0x010000_00011 0 0 0 0 0 0 00x80yes — unambiguous
0x801000_00000 0 0 0 0 0 0 10x01yes — unambiguous
0x530101_00111 1 0 0 1 0 1 00xCAyes — unambiguous
0xA61010_01100 1 1 0 0 1 0 10x65yes

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

A UART transmit datapath. The producer presents a parallel payload and a parity mode, both of which may change at any time. At an accepted transaction, the payload is captured into a shift register, the parity bit is computed from that payload by an exclusive-or reduction and stored, and the parity mode is captured into a frame-format register. During the frame, the line value is selected from three sources: the constant mark level used for idle and stop, the constant space level used for the start bit, and the shift register's least significant bit which supplies each payload bit in turn, or the stored parity bit. The selection is made by the control machine. The shift register advances one position at each bit boundary, so its least significant bit always holds the next payload bit to emit.tx_data_iproducer — volatilecaptureat acceptanceshreg_qbit 0 = next bitline selectcontrol choosesparity_mode_ialso volatileXOR treecomputed oncepar_q + mode_qframe format frozentx_oone bit period eachpayloadloadbit 0modeparitypar_qlevel12
Figure 1 — the transmit datapath. Everything left of the capture boundary belongs to the producer and may change at any time; everything right of it belongs to the transmitter for the duration of the frame. The line's value comes from one of three places — a constant, the shift register's bit 0, or the stored parity bit — and control decides which. No path exists from the producer's bus to the line except through capture.

The shift register's behaviour over one payload field, extracted from simulation of the assembled transmitter:

Payload field of 0x53, LSB first

11 cycles
A trace of eleven bit intervals transmitting the byte 53 hexadecimal in an eight-data-bit, no-parity, one-stop-bit frame. The first interval is the start bit at the space level. The next eight intervals carry the payload least significant bit first, with values one, one, zero, zero, one, zero, one, zero. The shift register contents progress from 53 hexadecimal down through 29, 14, 0A, 05, 02, 01 and 00 as each bit is emitted and the remaining bits move one position toward bit zero. The final interval is the stop bit at the mark level, whose value comes from a constant because the shift register is empty by then.payload from shreg_q[0]payload from shreg_q[0]start — a constantstart — a constantshreg_q[0] = 1shreg_q[0] = 1payload consumedpayload consumedstop — a constantstop — a constantfieldSTARTD0D1D2D3D4D5D6D7STOPidleshreg_q535329140A050201000000tx_ot0t1t2t3t4t5t6t7t8t9t10
Figure 2 — 0x53 leaving the shift register. Columns are BIT INTERVALS, not fabric-clock cycles: each is one baud period, and the value shown is what the line carries for the whole of it. The register is loaded at capture and shifts once per interval, so its bit 0 — the highlighted row — is always the bit currently on the wire. After eight shifts the payload is consumed, which is why the stop interval's level comes from a constant rather than from the register.

Read 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

Where this fits

Part of the UART curriculum.