Skip to content
VLSI Mentor

UART · Module 14

Verifying the Transmitter

Checking bit timing, frame structure, ordering and the ready/busy contract against the specification rather than the RTL — and measuring the fractional baud generator from outside.

The transmitter has been checked many times already, and always by the design's own receiver. Loopback is a fine functional test and it has one structural weakness: both ends share a timing generator, so a transmitter emitting bits at entirely the wrong rate loops back perfectly (Chapter 11.5 §2 measured exactly that).

This chapter checks the transmitter against a nominal grid instead — an ideal bit period computed from the specification, not taken from the design.

1. Structure, Predicted Before It Is Observed

The predictor computes what must appear on the wire, from the configuration alone:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Predict the exact line pattern a correct transmitter must emit.
// Returned LSB-first as: start, data[0..nbits-1], [parity], stop.
task automatic predict_tx_bits(input logic [8:0] data, input int nbits,
                               input int parity_mode,
                               output logic [15:0] bits, output int nbit_total);
    int i, b;
    begin
        bits = '0; b = 0;
        bits[b] = 1'b0; b++;                                  // start
        for (i = 0; i < nbits; i++) begin bits[b] = data[i]; b++; end
        if (parity_mode != P_NONE) begin
            bits[b] = bfm_parity_bit(parity_mode, data, nbits); b++;
        end
        bits[b] = 1'b1; b++;                                  // stop
        nbit_total = b;
    end
endtask

It is written from Chapter 3.1 and 3.2, not from uart_tx. Four properties fall straight out of it, and each is a requirement from Chapter 14.1 §2:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- 1. structure: what the specification says must appear
     0x55 8N1 must be 10 intervals: start + 8 data LSB-first + stop
  pass predicted frame is 10 intervals
  pass predicted start bit is SPACE
  pass predicted stop bit is MARK
  pass predicted data is LSB-first

The LSB-first check is worth its line. 0x55 is 1010_0101, so the first data interval must be 1 and the second 0. A transmitter that shifted MSB-first would produce a perfectly well-formed frame carrying 0xAA, and a loopback test against a receiver that also assembled MSB-first would pass.

2. Content, Through an Independent Monitor

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- 2. eight patterns through an independent monitor
  pass monitor observed all 8 frames
  pass every transmitted byte matches what was queued

Eight patterns chosen by shape rather than value — alternating, inverse-alternating, nibble-split both ways, single-one at each end, all-ones-but-one, and a mixed value. That is Chapter 14.1 §3's pattern binning applied.

The monitor decodes using its own nominal bit period. It is the same algorithm a receiver uses, implemented from the specification, and it therefore cannot follow the transmitter into a timing error.

3. Timing, Measured Against an Ideal

This is what loopback cannot do. The ideal bit period at 115,200 baud is exactly

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  1 / 115200 s  =  8680.5556 ns

and the transmitter runs on a 100 MHz clock, so it cannot produce that period. It must approximate it. Timestamping every edge on the wire and keeping the intervals that are a single bit long:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- 3. bit period, measured against the IDEAL grid
     single-bit intervals: 20 at 8680 ns (868 clk), 1 at 8690 ns (869 clk), 0 other
     measured mean        8680.4762 ns   (ideal 8680.5556 ns)
     mean error           -9.1 ppm
     measured single-bit   8680.0000 .. 8690.0000 ns
     error at the short end -64.0 ppm

4. The Ready/Busy Contract

Chapter 7.4 designed the transmitter to accept the next byte while the current one is still going out, so that back-to-back frames have no gap. That is a claim about when tx_ready_o re-asserts, and it is checkable from outside by watching the pin and the flag together.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- 4. ready/busy contract
     frame lasted 9147 clocks (= 10.54 bit times)
     ready high for 868 of them; first went low at clock 0
     ready rose at clock 8279 = bit time 9.54 of the frame
  pass ready is high for part of the frame (a holding register exists)
  pass ready is NOT high for the whole frame (the register fills)
  pass busy clears only after the line returns to MARK

Ready rises at bit time 9.54 of a 10.54-bit-time frame and stays high for exactly one bit period. Bit time 9.54 is the start of the stop interval — so the transmitter opens its holding register for precisely the stop bit, which is exactly the design Chapter 7.4 described, confirmed by an observer that knows nothing about it.

The frame is 10.54 bit times rather than 10. The extra half is launch latency: the byte was accepted, and the start bit begins on the next baud tick rather than immediately. That is real and it is not a defect — it is the granularity of a design whose transmitter advances on a bit-rate enable (Chapter 8.1).

A derivation showing four independent checks applied to a UART transmitter. From the configuration alone, a predictor computes the exact sequence of line intervals a correct transmitter must emit: a start bit at the space level, the data bits least significant first, an optional parity bit, and a stop bit at the mark level. Separately, the byte queued by the test is recorded. On the wire, an independent monitor running on its own nominal bit period recovers each frame and reports the byte it decoded, which is compared against the byte queued. Also on the wire, every edge is timestamped and the single-bit intervals are collected, giving a measured mean bit period which is compared against the ideal computed from the baud rate rather than from the design. Finally the ready and busy flags are observed together against the frame on the pin, establishing when the transmitter opens its holding register relative to the stop interval.SpecificationPredictorThe wireCheckframe = start + dataLSB-first + parity +stopexpected intervalpatternmonitor decodes atNOMINAL tbitT_bit = 1 / 115200 —exactedge timestamps ->measured meanready and busy vsthe pinno branch uses thedesign's own tick
Figure 1 — how a transmitted frame is checked without using the design's timing. Each observable is derived from the specification and compared against something measured on the wire, so no branch of the check depends on the transmitter being right about anything.

0x55 on the wire, and the ready window

12 cycles
A trace of twelve bit intervals showing one transmitted UART frame and the associated handshake flags. The line is idle at mark, then a start bit at the space level begins the frame. The eight data bits of the byte 0x55 follow, least significant bit first, giving the alternating sequence one, zero, one, zero, one, zero, one, zero. A stop bit at the mark level ends the frame and the line returns to idle. The busy flag asserts from just before the start bit and remains asserted until the stop interval completes, covering slightly more than ten bit times because of launch latency. The ready flag is low for the body of the frame and returns high for exactly the stop interval, which is the one bit period during which the transmitter will accept the next byte.busy: the frame in flightbusy: the frame in flightLSB first — 0x55 starts with 1LSB first — 0x55 startswith 1ready returns here — one bit wideready returns here — onebit wideintervalidlestartd0d1d2d3d4d5d6d7stopidletx_otx_busy_otx_ready_omonitor samplest0t1t2t3t4t5t6t7t8t9t10t11
Figure 2 — one measured frame. Columns are bit intervals. The byte 0x55 appears LSB-first between a space start and a mark stop; busy covers the whole frame and a little launch latency; ready returns for exactly the stop interval, which is the window a careless driver double-fills.

5. Ordering

Eight frames were driven back to back and compared in order. Ordering is a separate requirement from content (Chapter 14.1 R9), and a scoreboard that compares sets rather than sequences will not catch a transmitter that swaps two bytes.

The check is that the nth observed frame equals the nth queued byte — not that the multiset matches. The distinction sounds academic until a FIFO pointer bug reverses two entries, which is a defect that preserves the multiset exactly.

6. The Same Environment, Built as a UVM Agent

Everything this module has built so far is a directed testbench: a driver module, a monitor module, a predictor, and a test that calls them in order. That is the right instrument for a link with one wire in each direction, and it is what the published suites use.

A UVM agent is the same three components with the connections made explicit and the stimulus separated from the sequencing. Nothing about the checking changes — and that is the point worth making, because the methodology is often sold as though it improved the checking. It does not. It improves the reuse and the layering.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------------
//  uart_frame_item — one frame, described the way a test thinks about it
//
//  The fields are the SPECIFICATION's parameters, not the design's signals.
//  There is no `tx_o`, no oversample count and no clock here: a transaction
//  says what should appear on the wire, and the driver decides how.
// ---------------------------------------------------------------------------
class uart_frame_item extends uvm_sequence_item;
    `uvm_object_utils(uart_frame_item)

    rand bit [8:0] data;
    rand int       nbits;         // 5..9
    rand int       parity_mode;   // P_NONE, P_EVEN, P_ODD, P_MARK
    rand int       stop_halves;   // 2 = 1 bit, 3 = 1.5, 4 = 2
    rand real      tbit_ns;       // the argument that makes the BFM useful
    rand int       err;           // ERR_NONE .. ERR_BREAK

    // observed-only fields, filled in by the monitor
    bit parity_err, frame_err;

    constraint c_format { nbits inside {[5:9]};
                          parity_mode inside {[0:3]};
                          stop_halves inside {[2:4]}; }
    constraint c_data   { data < (1 << nbits); }

    // Baud error is the axis that matters, so it is randomised in BINS
    // rather than uniformly: the interesting values cluster at the edge of
    // the tolerance window, not in the middle of it.
    constraint c_baud   { tbit_ns dist { 8680.5556       := 40,
                                         [8160 : 8420]   := 15,   // about -5%
                                         [8940 : 9200]   := 15,   // about +5%
                                         [7800 : 8160]   := 5,
                                         [9200 : 9560]   := 5 }; }

    // Clean traffic must dominate, or the error cases stop being corners.
    constraint c_err    { err dist { 0 := 70, [1:5] := 30 }; }

    function new(string name = "uart_frame_item");
        super.new(name);
    endfunction
endclass

The driver is a thin wrapper around the BFM this module already built — which is the argument for having built it as a standalone component first:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class uart_line_driver_c extends uvm_driver #(uart_frame_item);
    `uvm_component_utils(uart_line_driver_c)
    virtual uart_line_if vif;

    task run_phase(uvm_phase phase);
        vif.tx <= 1'b1;                       // idle MARK before anything
        forever begin
            seq_item_port.get_next_item(req);
            drive_frame(req);
            seq_item_port.item_done();
        end
    endtask

    // The whole body is the send_frame task of Chapter 14.2, reached through
    // a virtual interface instead of a hierarchical name. The LOGIC did not
    // move; only the plumbing did.
    protected task drive_frame(uart_frame_item t);
        ...
    endtask
endclass

The sequence library is where transmitter verification actually lives. The agent is infrastructure; these are the tests:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Every byte value, at the nominal rate -- the coverage floor.
class uart_all_bytes_seq extends uvm_sequence #(uart_frame_item);
    `uvm_object_utils(uart_all_bytes_seq)
    task body();
        for (int d = 0; d < 256; d++) begin
            `uvm_do_with(req, { data == d; nbits == 8; parity_mode == 0;
                                stop_halves == 2; err == 0;
                                tbit_ns == 8680.5556; })
        end
    endtask
endclass

// The full format cross -- Chapter 14.6 section 2.
class uart_format_cross_seq extends uvm_sequence #(uart_frame_item);
    `uvm_object_utils(uart_format_cross_seq)
    task body();
        foreach_format: for (int nb = 5; nb <= 9; nb++)
            for (int pm = 0; pm <= 3; pm++)
                for (int sh = 2; sh <= 4; sh++)
                    repeat (4)
                        `uvm_do_with(req, { nbits == nb; parity_mode == pm;
                                            stop_halves == sh; err == 0; })
    endtask
endclass

// The baud sweep of Chapter 14.4, as a sequence rather than a loop in a test.
class uart_baud_sweep_seq extends uvm_sequence #(uart_frame_item);
    `uvm_object_utils(uart_baud_sweep_seq)
    rand int lo_pct = -10, hi_pct = 10;
    task body();
        for (int e = lo_pct; e <= hi_pct; e++)
            `uvm_do_with(req, { nbits == 8; parity_mode == 0; err == 0;
                                tbit_ns == 8680.5556 * (100.0 + e) / 100.0; })
    endtask
endclass

7. Verification

Check structure separately from content. §1 checks that the predicted frame has the right shape before any frame is transmitted. If that fails, the predictor is wrong and every subsequent comparison is meaningless.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Assertion — the transmit line is idle at MARK whenever nothing is in
// flight. Written from Chapter 3.1, not from uart_tx, and it is what stops
// a design from emitting a spurious start bit after reset.
property p_idle_is_mark;
    @(posedge clk) disable iff (!rst_n)
        !tx_busy_o |-> tx_o;
endproperty

// Assertion — busy must cover the whole frame. If busy clears while the
// line is still at SPACE, a driver that gates a transceiver on busy will
// truncate the final character — Chapter 13.4 section 4.
property p_busy_covers_the_frame;
    @(posedge clk) disable iff (!rst_n)
        $fell(tx_busy_o) |-> tx_o;
endproperty

Assert the mean bit period, not each interval. §3's dither means an interval-by-interval check fails on a correct design. The specification constrains the average.

Drive the handshake correctly, and know why. §4's callout is the single most common transmitter-testbench defect, and it manifests as a duplicated byte that looks like an RTL bug.

Do not check the transmitter with the design's own receiver alone. It is a useful test and it cannot see a systematic timing error, because both halves share a generator. That is not a hypothetical — it is measured in Chapter 11.5 §2.

8. Debugging

9. What This Means in Practice

A scope measurement is this chapter's §3. On hardware, measuring the bit period on the transmit pin is the first check worth making, and the number to compare against is 1 / baud, computed independently of the device.

Expect dither on any fractional design. A scope triggered on single edges will show two populations one clock apart. That is correct, and mistaking it for jitter has sent people looking for a power-supply problem.

The ready window is short. One bit period at the end of the frame — 8.68 µs at 115,200 baud, and 0.33 µs at 3 Mbaud. A driver that polls rather than responding to the handshake may miss it entirely at high rates, which presents as poor throughput rather than as an error.

Launch latency is real and is up to one bit time. Frames are 10.54 bit times here, not 10. Any budget that assumes exactly N × T_bit for a burst will drift.

10. Understanding Check

11. Summary

Check the transmitter against a nominal grid, not against the design's own receiver. Loopback shares a timing generator and therefore cannot see a systematic rate error at all.

Predict the frame before observing it. Ten intervals, start at space, stop at mark, data LSB-first — four checks that come from the specification and that a bit-reversed transmitter cannot pass even though its frames are well formed.

The fractional baud generator is measurable from outside: 20 intervals of 868 clocks and 1 of 869, a mean of 8680.4762 ns against an ideal of 8680.5556, −9.1 ppm where an integer divider would sit permanently at −64 ppm.

Assert the mean, not each interval — the dither is the mechanism, not a fault.

Ready returns for exactly one bit period, at bit time 9.54 of a 10.54-bit-time frame: the stop interval, confirming the holding-register design from outside, and explaining the duplicated-byte testbench defect precisely.

Frames are 10.54 bit times, not 10, because launch waits for the next bit-rate enable. Any burst budget assuming N × T_bit will drift.

And the discipline underneath all of it: no branch of any check used the design's own tick.

12. What Comes Next

The transmitter emits what the specification demands. Chapter 14.4 turns the environment around and drives the receiver — with legal traffic, with marginal traffic at the edge of its timing budget, and with traffic that is simply illegal.

That is where the BFM's arbitrary bit period earns its place: the receiver's tolerance is a specification claim that has been derived, quoted and assumed for eleven modules, and it is about to be measured against the RTL.

Browse the full path on the UART tutorials index. For the fractional divider this chapter measured, read back to Chapter 8.3.

Continue learning

Where this fits

Part of the UART curriculum.