USRT is a UART-like serial peripheral connected to an APB bus, implemented in Verilog.
The project was built as a small digital design exercise around three pieces working together:
- an APB-facing register interface
- a configurable serial transmit / receive path
- simulation testbenches for the individual modules and the integrated top-level design
The top-level module in src/top.v connects the bus interface, status/config register, baud-rate generator, transmit path, and receive path into a single peripheral.
The peripheral exposes three APB-visible register targets through i_Paddr[31:30]:
00: status / control register01: transmit data register10: receive data register
The status/control register stores:
- transmit busy flag
- receive-full flag
- parity configuration
- baud-rate selection
The implemented baud presets are:
1200240048009600192003840057600115200
Main modules in src/:
top.v: full peripheral integrationbusint.v: APB address decode and enable generationstatusreg.v: control register, status bits, parity selection, baud selectionbaudgen.v: baud clock generationtxdatreg.v: transmit data register and ready/busy handshaketxparity.v: transmit frame generation with paritytxshift.v: parallel-to-serial transmit shift registerrxshift.v: serial-to-parallel receive shift registerrxparity.v: parity checking and received byte extractionrxdatreg.v: receive data register with full flag
Testbenches are also included in src/, for example:
test_top.v: integrated peripheral testtest_tx.v,test_rx.v: transmit / receive path teststest_bus.v,test_busint.v: APB-side tests
- The CPU writes control bits to the status register.
- The CPU writes one byte to the transmit register.
txparity.vbuilds the serial frame.txshift.vshifts the frame out on the serial line using the generated baud clock.- Status bits expose the busy/ready state back to the bus side.
rxshift.vdetects a start bit and samples the incoming serial line.rxparity.vchecks parity and extracts the received byte.rxdatreg.vstores the byte and raises the receive-full status bit.- The CPU polls the status register and reads the receive register when data is available.
The repository includes module-level and top-level testbenches. The integrated example is src/test_top.v.
Example flow with Icarus Verilog:
cd src
iverilog -o test_top.out test_top.v
vvp test_top.out
gtkwave test.vcdThe top-level testbench does the following:
- resets the peripheral
- writes the status/control register
- sends one transmit byte
- injects one received serial frame
- polls the status register for new data
- reads the receive register
The transmit path loads one byte through the APB side, builds the serial frame, and shifts it out using the configured baud clock.
The receive path samples the serial input, reconstructs the frame, validates parity, and stores the received byte in the RX data register.
The integrated testbench polls the status register until the receive-full flag is raised, then reads the received byte from the RX register.
The images/ directory contains diagrams and waveform screenshots for the design, including:
- APB-side behavior
- baud generation
- transmit flow
- receive flow
- parity/status handling
- the overall circuit diagram
Those images are meant to complement the source by showing the module interactions and simulation behavior.
- This is a learning project, not a production UART core.
- The implementation is intentionally split into small modules so the bus logic, framing, and shift-register logic can be tested separately.
- Naming follows the original project as-is, including
USRT.



