The table lists what the testbench checks on every run.
Check | How |
|---|---|
Every clock of every frame is right | Acceptance is sampled before the rising edge; the monitor checks the post-update line against each expected frame sample, including start on the acceptance edge. |
Data is correct and in order | The driver queues each accepted byte; the monitor pops one per frame. |
No lost or extra frames | Completed frames + reset-cancelled frames = accepted bytes; unsolicited low line while idle fails. |
Valid/ready is honoured | The driver records acceptance at the rising edge and changes the offer only at the falling edge after an accepted one. An offered byte keeps |
Back-to-back frames have no gap | Every consecutive saturated acceptance is exactly 10*CPB rising edges apart; the full-frame monitor checks that each acceptance starts its frame immediately. Pair coverage is required, alongside the aggregate throughput bound. |
Parameter, reset and CTS boundaries | CPB=1,2,3,434; directed 00/FF/A5/96; idle and mid-frame resets; CTS withdrawal during a stalled offer and at the last STOP slot. The pending byte stays stable and the accepted frame finishes. |
Each mutation below is applied to the listing, and the testbench must fail.
Mutation | Result |
|---|---|
Tick compare changed from | Fails: every bit is one clock short; at CPB=4 the stop bit arrives early (sample 27) and burst spacing is 30 instead of 40 clocks; at CPB=1 the tick never fires and the offer times out |
STOP not accepting a byte at its last clock | Fails: burst phase gap check |
Data sent MSB-first | Fails on 0x96 (sample 4); 0x00, 0xFF and 0xA5 read the same in both orders and pass |
Producer side: follow valid/ready. A FIFO in front of uart_tx lets the producer burst bytes while the line drains at baud rate (10 × CLKS_PER_BIT clocks per byte).
Pin side: drive the pin from the transmitter's registered tx in its own clock domain, with the appropriate I/O timing constraints. A single output flop clocked by an unrelated clock is not a safe CDC circuit and can distort or miss serial bits. If transmission must run in another domain, cross complete bytes (or complete configured data words) through an asynchronous FIFO or a CDC handshake, then run the UART FSM and baud generator in that destination domain.
Reset: asynchronous assert, synchronous release (see reset strategy). Reset drives tx high and cancels an active frame and any pending producer offer under a shared reset contract. A remote receiver may see a truncated frame: discard it and reestablish framing before relying on subsequent bytes. The bench checks local cancellation and a fresh complete frame; it does not simulate receiver recovery.
Flow control: synchronize remote CTS and normalize its polarity to cts_allow in the UART clock domain. The listing gates exported tx_ready internally and uses exactly that ready in accept. Keep producer valid/data stable under stall. CTS blocks acceptance at the sampled edge; after acceptance the whole frame finishes. A stateless CTS mask on valid can withdraw a stalled offer and violates that contract.
Extension | Change |
|---|---|
Parity bit | Add a PARITY state after DATA; the bit is |
Two stop bits | Make STOP last 2 × CLKS_PER_BIT clocks (count a second bit) before |
Configurable word size (5 to 9 bits) | For a fixed WORD_BITS parameter, size tx_data and shreg as [WORD_BITS-1:0], bit_idx as [$clog2(WORD_BITS)-1:0], and compare bit_idx with WORD_BITS-1. Replace both fixed shreg[7:1] shift expressions with shreg >> 1. Nine bits require a 4-bit index and 9-bit data ports/storage. For runtime configuration, use 9-bit data ports/storage and a 4-bit index, and latch word_bits with each accepted word; enforce 5 through 9. |
Fractional baud | Replace |
The listing and testbench above remain fixed at 8N1. When implementing configurable width, extend the monitor and scoreboard too: a frame has word_bits + 2 bits including start and stop. Check 5-bit and 9-bit frames, especially 9'h100 and 9'h001, at every clock; require a bounded return to ready and back-to-back completion. For runtime configuration, change the live width input after acceptance to confirm the latched width controls the entire frame. Changing only the terminal comparison leaves the 3-bit index unable to reach 8, so a 9-bit frame never ends.
TX = 115207.373 baud, RX = 115107.914 baud; TX/RX - 1 = +0.0864%. That fits the illustrative 2% allocation before oscillator corners, but acceptance requires the selected receiver's tolerance and sampling-mode specification. A hardware register divisor may include an oversampling factor; 139 here is the total effective divisor.
The testbench was run with Icarus Verilog 13.0 (2026-10-16) and prints PASS. The checks cover the digital clock model, not receiver tolerance, pin timing or physical fault recovery.
The tick and MSB-first mutation rows were rerun against this listing on 2026-10-16 (Icarus Verilog, CPB=4). The STOP row was recorded on the original listing and has not been rerun.