1. intro
A typical UART uses 2 main signal lanes (wires) to bridge two endpoints: TX (Transmit) RX (Receive)
Device A TX ───────────────► Device B RX Device A RX ◄────────────── Device B TX
The receiver (RX) and transmitter (TX) are independent. You can read and write UART at the same time without conflict. Internally, UART has separate buffers/FIFOs for RX and TX. The buffer is FIFO based and in the UART module and seperate for TX and RX
Some UART implementations use additional lanes for hardware flow control:
| Signal | Name | Direction | Purpose |
| ------ | ------------------- | ---------------- | -------------------------------- |
| RTS | Request To Send | Output from host | Used to signal readiness |
| CTS | Clear To Send | Input to host | Used to grant permission |
| DSR | Data Set Ready | Optional | Used in modem control |
| DTR | Data Terminal Ready | Optional | Legacy modem signals |
| RI | Ring Indicator | Optional | Indicates incoming call (modems) |
| Configuration | Lanes Used | Description |
| ------------------------- | -------------------- | ----------------------------------- |
| Minimal UART | 2 (TX, RX) | Used in xv6, embedded systems, etc. |
| UART + hardware flow ctrl | 4 (TX, RX, RTS, CTS) | Adds robustness for fast links |
| RS-232 full modem | 6–8+ | Legacy setups, rarely needed today |
2. Uart in xv6
[CPU / SoC] ------------------> [External Device]
[CPU / SoC] <----------------- [External Device]
↑
UART module
Serial protocol
(TX/RX over wires)
with FIFO buffer
The external device could be a host with a terminal emulator consists of: A keyboard (for input) A display (CRT or screen — for output)
So the uart TX connects to the display, while the RX connects to the keyboard.
3. control registers in uart
| Name | Offset | Access | Purpose / Description | Used in xv6? |
| ------- | ------ | ------ | --------------------------------------------------------------- | ------------------------ |
| RHR | 0x00 | Read | Receiver Holding Register — read incoming byte | ✅ Yes |
| THR | 0x00 | Write | Transmitter Holding Register — write byte to send | ✅ Yes |
| IER | 0x01 | R/W | Interrupt Enable Register — enables interrupt types | ✅ Yes |
| IIR | 0x02 | Read | Interrupt Identification Register — why interrupt fired | (Not used) |
| FCR | 0x02 | Write | FIFO Control Register — enables/clears FIFOs | ✅ Yes |
| LCR | 0x03 | R/W | Line Control Register — sets word length, stop bits, parity | ✅ Yes |
| MCR | 0x04 | R/W | Modem Control Register — controls OUT2, RTS, DTR | ✅ Yes (for enabling IRQ) |
| LSR | 0x05 | Read | Line Status Register — RX ready, TX ready, errors | ✅ Yes |
| MSR | 0x06 | Read | Modem Status Register — modem control lines | ❌ Not used |
| SCR | 0x07 | R/W | Scratch Register — test register (general-purpose) | ❌ Not used |
| DLL | 0x00 | R/W | Divisor Latch LSB — set baud rate (if DLAB=1) | ✅ Yes |
| DLM | 0x01 | R/W | Divisor Latch MSB — set baud rate (if DLAB=1) | ✅ Yes |
4. UART Frame
[ Start Bit ] [ Data Bits (5–8) ] [ Optional Parity ] [ Stop Bit(s) ] Start bit: Always 1 bit, value = 0 Data bits (word length): Usually 5 to 8 bits Optional parity: For error detection Stop bit(s): Usually 1 or 2, value = 1
Word length = number of data bits. The LCR (Line Control Register) is used to set word length, stop bits and parity
LCR[1:0] bits 0 and 1 of the LCR (Line Control Register) set the word length:
| LCR\[1:0] | Word Length (data bits) |
| --------- | -------------------------- |
| `00` | 5 bits |
| `01` | 6 bits |
| `10` | 7 bits |
| `11` | 8 bits (standard) ✅ |
One example is following:
*reg_lcr = 0x03; // 0b00000011 → 8 data bits, 1 stop bit, no parity