Skip to content

Latest commit

 

History

History
183 lines (118 loc) · 7.77 KB

File metadata and controls

183 lines (118 loc) · 7.77 KB

Module 3: UART — Protocol + RTL + Basic Testbench

Goal: Understand the UART protocol (8N1, baud), translate it to RTL (TX, RX, baud gen), and verify with a basic (non-UVM) directed testbench.


Navigation

← Previous: Module 2: Methodology (Part 2) | Next: Module 4: UART UVM+SV →

↑ Back to README


Before You Start (Learning Path)

Modules 3–8 are learning modules, not just exercises. Before running commands:

  1. Read the detailed UART learning guide: UART_LEARNING_GUIDE.md — what UART is, what kind of protocol (serial, asynchronous, point-to-point), how it works (frame format, baud rate, TX/RX), timing, and where it’s used.
  2. Read the protocols + UVM overview: LEARNING_GUIDE_PROTOCOLS_AND_UVM.mdPart B § 4. When to Use Baseline vs UVM (why we start with a baseline testbench before UVM).

Then return here and follow OverviewTopics CoveredExampleExercises.


Running Module 3

Quick run (from repo root):

cd module3/examples/uart_baseline
make run

Or: ./scripts/module3.sh --run


Overview

Module 3 is the first protocol module:

  • UART protocol: 8N1 framing, start/stop bits, baud rate.
  • RTL: uart_tx, uart_rx, baud_gen — translating protocol to RTL (same methodology as Module 1).
  • Basic testbench: Directed test (loopback TX→RX, send bytes, check received bytes). No UVM — UVM for UART is Module 4.

What You'll Learn

  • UART 8N1: Start bit (0), 8 data bits (LSB first), stop bit (1); idle high.
  • Baud rate: Role of a baud generator (clock divider → baud_tick).
  • RTL architecture: TX (parallel→serial, shift per baud_tick), RX (start detect, sample, data_valid), baud_gen (divider).
  • Basic TB: Loopback, directed stimulus, and checking without UVM.

Prerequisites

  • Module 1 (spec → RTL) and Module 2 (basic TB → UVM, toolchain).
  • Verilator, Make, C++ compiler. No UVM required for the uart_baseline example.

Topics Covered

1. UART Protocol (8N1)

  • Signals: Serial line (tx/rx), idle high; system clock; baud_tick (one pulse per bit time).
  • Frame: 1 start bit (0), 8 data bits (LSB first), 1 stop bit (1).
  • Timing: One bit per baud_tick; baud_tick derived from system clock via a divider (e.g. DIVIDER = clk_freq / baud_rate).

UART quick reference (8N1)

  • Framing: idle=1start=0 → 8 data bits (LSB first) → stop=1.
  • Baud math: DIVIDER = round(clk_hz / baud). Example: 50 MHz clock, 115200 baud → divider ≈ 434.
  • Sampling: Basic design samples once per bit at the baud_tick. Production UARTs often oversample (e.g., 8x or 16x) to tolerate clock drift; you can add this later by replacing baud_tick with an oversample tick and using a mid-bit sample.
  • Reset state: Line idles high, TX not busy, RX clears internal shift register, data_valid low.
  • Errors: framing_error when stop bit is not high at expected sample; optional parity_error if parity enabled (not used in 8N1 baseline).

TX design checklist

  • Inputs: clk, rst_n, baud_tick, start, data_in[7:0].
  • Outputs: tx, busy.
  • Behavior: On start, latch data_in, drive start bit low, then shift out bits [0:7] each baud_tick, then drive stop bit high for one baud_tick. Deassert busy after stop bit.
  • Edge cases: Ignore start while busy (or queue it in a FIFO if you extend the design).

RX design checklist

  • Inputs: clk, rst_n, baud_tick, rx.
  • Outputs: data_out[7:0], data_valid (pulse), framing_error.
  • Behavior: Detect falling edge for start; wait one baud_tick to sample mid-start; sample 8 bits on successive baud_ticks; sample stop bit last. If stop is not high, raise framing_error. Pulse data_valid for one cycle when byte is ready.
  • Robustness options: Add metastability sync on rx; add oversampling + majority vote; add rx_ready/rx_valid handshake if you later connect to a FIFO.

Baud generator notes

  • Inputs: clk, rst_n, divisor (constant parameter in the baseline).
  • Output: baud_tick high for one cycle every divisor clocks.
  • For synthesis, keep the counter simple (divisor-1 down-counter or up-counter compare). For sim, you can parametrize divisor to speed up runs.

Protocol extensions (not in baseline example)

  • Data bits: 5–9 data bits are common.
  • Parity: Even/odd/mark/space; adds a parity bit before stop.
  • Stop bits: 1 or 2 stop bits.
  • Flow control: RTS/CTS hardware pins (outside the serial line) to throttle traffic.
  • The baseline RTL assumes 8N1 with no parity and no flow control.

2. RTL Architecture

  • baud_gen: Divides clk; outputs baud_tick one cycle every DIVIDER cycles.
  • uart_tx: On start, loads data_in into shift register; outputs one bit per baud_tick (start, data[0:7], stop); asserts busy during frame.
  • uart_rx: Detects start bit (line low), samples one bit per baud_tick, reconstructs byte; pulses data_valid and outputs data_out; can assert framing_error if stop bit is bad.

3. Basic Testbench

  • Loopback: Connect TX output to RX input; send bytes from TX, check they appear on RX.
  • Directed test: Reset release, send 0x55 and 0xAA, wait for data_valid, check data_out. Implemented in top_uart_baseline.sv (initial block) and C++ (clk, rst_n); no UVM.

Example: uart_baseline

Component Role
dut/ uart_tx.v, uart_rx.v, baud_gen.v
top_uart_baseline.sv Loopback (rx=tx), baud_gen, uart_tx, uart_rx; directed test in initial block
sim_main.cpp Clock, reset; run until $finish

Run: cd module3/examples/uart_baseline && make run


Command Reference

cd module3/examples/uart_baseline
make run
./scripts/module3.sh --check   # Environment + example dirs
./scripts/module3.sh --run     # Run uart_baseline

Learning Outcomes

  • Describe UART 8N1 frame and baud timing.
  • Explain the role of uart_tx, uart_rx, and baud_gen.
  • Run the uart_baseline example and interpret the loopback test.
  • Ready for Module 4: UART UVM+SV verification.

Exercises

  1. Run uart_baseline

    • Run make run in module3/examples/uart_baseline. Confirm you see loopback success (e.g. bytes sent and received match).
  2. Trace one byte

    • Open top_uart_baseline.sv and the DUT sources. For one byte (e.g. 0x55), trace: testbench drives start and data_in → uart_tx sends start bit, 8 data bits (LSB first), stop bit → uart_rx detects start, samples 8 bits, pulses data_valid with data_out. Map each step to the corresponding RTL (baud_tick, busy, etc.).
  3. Baud and divider

    • In the example, find the baud divisor (or clock/baud relationship). Change the baud rate (or divisor) in simulation only and re-run; confirm the test still passes if TX and RX use the same timing.
  4. Optional: Waveforms

    • If the Makefile generates a VCD, open it and identify: baud_tick, tx, rx, start, data_valid, data_out. Confirm one UART frame (start + 8 data + stop) per byte.

Assessment

  • Can describe UART 8N1 (start bit, 8 data LSB first, stop bit) and the role of baud_tick.
  • Can explain the role of uart_tx, uart_rx, and baud_gen in the RTL.
  • Can run uart_baseline and interpret the loopback test result.
  • Ready for Module 4: UART UVM+SV verification.

Next Steps

After completing this module, proceed to Module 4: UART UVM+SV — full UART verification with UVM (agent, sequences, driver, monitor, scoreboard).