Docs/RTL & IP

uart

UART with AXI4-Lite CSRs — TX/RX FIFOs, programmable framing and baud rate.


A UART with AXI4-Lite CSRs for FPGA and ASIC: TX/RX FIFOs, programmable framing and baud rate, sticky error flags, a level interrupt, and a loopback self-test. Plain synthesizable SystemVerilog verified by self-checking Verilator testbenches plus SymbiYosys formal proofs; portable (the one vendor-aware cell, the RX synchronizer, is isolated in rtl/tech/); registers single-sourced from gen/regmap.py; packaged as vendor-neutral IP-XACT 1685-2014. The CSR port drops onto any AXI4-Lite fabric.

Design spec: docs/spec.md · register map: docs/registers.md (generated).

Features

  • 8 data bits, parity none/even/odd, 1–2 stop bits (TX; RX checks the first stop bit), programmable 24-bit divisor (min 8 cycles/bit)
  • parameterizable TX/RX FIFOs (FIFO_DEPTH, power of 2, default 16)
  • sticky W1C errors: overrun / frame / parity (errored frames still deliver their data byte)
  • level interrupt irq_o = |(IE & IP) over {rx_avail, tx_empty, err}
  • loopback self-test mode; RX start-glitch (runt) rejection
  • RX line synchronized through uart_tech_sync (generic/xilinx/intel/lattice, TECH= make knob)

Status

AreaState
RTL✅ lint -Wall-clean across all four tech vendors
Loopback TBUART P 0000 — config sweep, readback, IRQ truth table, TX-full drop, RX overrun + W1C
Line-level TBUARTL P 0000 — independent encoder/decoder, ±2% divisor mismatch, parity/stop corruption, runt rejection
Coverage98.7% rtl/ (150/152; the 2 misses are unreachable defensive FSM defaults)
Formal✅ F_fifo proven (occupancy + complete shadow-memory data integrity, DEPTH 4/16, mutation-tested) + F_tx basic proven (idle-high, pop discipline) + F_tx shape bounded-checked (btormc, 350 cycles ≈ 2 max frames: exact (1+8+P+S)·DIV length, start/stop windows)
IP-XACT✅ schema-validated (ipxact/); ERR carries modifiedWriteValue=oneToClear, RXD carries readAction=modify
IntegrationUARTX P 0000 — CSRs hosted behind ../xbar's crossbar incl. DECERR path (make sim-xbar)
OOC✅ timing closed on xc7a100t-1 (Vivado 2026.1): 370 LUT / 496 FF / 0 BRAM, WNS +2.75 ns @ 10 ns → Fmax ≈ 138 MHz
Board2000/2000 on the Arty A7-100T: arty_uart_echo (FSM AXI master → ../xbar crossbar → this UART on the physical USB-UART; make synth-echo prog echo-test)
make lint       # Verilator -Wall (TECH= picks the sync cell vendor)
make lint-tech  # all four vendors
make sim        # both TBs -> "UART P 0000", "UARTL P 0000"
make sim-xbar   # behind the crossbar (needs ../xbar) -> "UARTX P 0000"
make coverage   # merged line coverage, rtl/ only
make formal     # F_fifo + F_tx (SymbiYosys, abc pdr)
make ipxact     # vendor-neutral IEEE 1685-2014 package
make synth-ooc  # Vivado out-of-context synth+impl, timing-gated

Layout

rtl/     core/{fifo,tx,rx}.sv, bus/axil_regs.sv, uart_axil.sv (top),
         tech/{generic,xilinx,intel,lattice}/tech_sync.sv
tb/      tb_uart_loop.sv (CSR loopback), tb_uart_line.sv (line-level +
         error injection), tb_uart_xbar.sv (integration), shared AXI tasks
formal/  uart_fifo.sby + uart_tx.sby (yosys-dialect harnesses; DUTs sv2v'd)
docs/    spec.md, registers.md (generated)
gen/     regmap.py (single source of truth), ipxact_gen.py

License

Apache-2.0 — see LICENSE. Copyright 2026 Hasan Kurşun.