UART 16550

1. Overview

The UART provides a 16550-style programming interface over 32-bit AXI4-Lite. It transmits and receives serial characters, buffers them in independently sized FIFOs, and reports line, modem and FIFO-integrity events. Extensions include larger FIFO depths, FIFO data/pointer parity protection, extended receive thresholds and a FIFO-error interrupt.

The TX and RX FIFOs default to 16 entries each. Software selects FIFO or single-character operation, frame format, baud divisor and interrupt enables. Modem signals provide status and software-controlled outputs; CTS does not stop transmission and RTS does not automatically throttle reception. DMA-ready outputs indicate service conditions but do not themselves move data. The UART section of the Programmer’s Guide gives the configuration, interrupt service and flow-control procedures.

uart_wrap: an AXI-Lite demux in front of NUM_UARTS uart_log_engine_wrap instances and an error subordinate, and an AXI-Lite mux that merges the instances' log-fetch ports
Figure 1. SMC UART wrapper

Figure 1 shows the SMC wrapper around the UART 16550. uart_wrap runs on one clock, clk_i, which in the SMC is the gated peripheral clock; both of its AXI4-Lite ports cross to the SMC clock in smc_peripherals_cdc. The register port has 32-bit address and data. The demux u_csr_axi_lite_demux and the mux u_log_fetch_axi_lite_mux are PULP blocks, marked by the project name in parentheses. The demux selects the instance whose window, 0x400 bytes apart, contains the address, and sends every other address to an error slave that answers DECERR with read data 0xBADCAB1E.

Each instance, gen_uart_log_engine_wraps[i].u_uart_log_engine_wrap, holds one UART 16550 and, when bit i of GEN_LOG_ENGINES is set, a log engine; Log-engine wrapper diagram shows its contents. The mux u_log_fetch_axi_lite_mux merges the instances' log-fetch manager ports onto the single log-fetch port, with 56-bit address and 64-bit data. The SMC instantiates four UARTs, each with a log engine and 32-entry TX and RX FIFOs.

Every per-instance port is a vector with one bit per instance, and the figure labels the slice that instance 0 drives. In the SMC, uart_dsr_ni, uart_ri_ni and uart_dcd_ni are tied high, and uart_dtr_no, uart_out1_no, uart_out2_no, uart_rxrdy_o and uart_txrdy_o are unconnected. uart_irq_o, uart_err_o and log_engine_irq_o of each instance are ORed into one interrupt, peripheral interrupts 18 to 21.

2. Architecture

uart_16550 selects the register view; uart_core manages buffering, baud timing, modem state and interrupts; uart_tx and uart_rx serialize and sample characters. All core logic uses clk_i.

2.1. Transmit and Receive Paths

With LCR.DLAB=0, a write to THR supplies a transmit byte and a read of RBR consumes a received byte. FIFO mode queues characters; non-FIFO mode uses one holding register per direction. Changing FCR.FIFO_ENABLE clears both FIFOs and the single-character holding state, so changing mode can discard data.

The transmitter runs whenever enabled and data is available, independently of CTS. LSR.THRE means the TX FIFO/holding register is empty; LSR.TEMT also requires the serializer to be idle. Use TEMT when the final character must have left the transmitter before reconfiguration.

The receiver synchronizes rx_i and takes a majority of three consecutive clk_i samples, which rejects single-cycle glitches. It then samples each bit once, at the bit midpoint timed by the 16-times-baud tick. Received parity, framing and break indications accompany characters; software reads line status before consuming their data. In FIFO mode, an overrun drops the newly received character; in non-FIFO mode an unread character can be overwritten in RBR. Frame format supports 5–8 data bits, selectable parity and stop-bit configuration. LCR.SET_BREAK forces the transmit line low.

2.2. Baud Timing and Register Views

LCR.DLAB selects DLL/DLM at offsets 0x00 and 0x04 for divisor programming. With DLAB clear, these offsets select RBR/THR and IER. Other offsets retain their normal meaning. Serial operation is disabled when the combined divisor is zero; otherwise baud rate is clk_i_frequency / (16 * (divisor + 1)). The smallest usable divisor, 1, gives a maximum baud rate of clk_i_frequency/32.

2.3. FIFO Protection and Line Errors

FIFO/holding-register data and FIFO pointers have parity protection. An internal parity failure drives err_o and can raise the separately enabled FIFO-error interrupt. This is different from parity in a received serial frame.

Table 1. UART serial errors
LSR field Meaning

OE

Receive FIFO overrun: a character arrived while the receive FIFO was full.

PE

Parity error on the character exposed at the receive head.

FE

Invalid stop bit on that character.

BI

Break: the received frame remained low.

In the current RTL, overwriting an unread non-FIFO RBR does not set OE. These error fields clear on an LSR read. Capture the status once for the character being serviced; repeated diagnostic reads can consume error evidence. The generated map specifies the status fields and their access side effects.

2.4. Interrupt Priority and Service

irq_o reports the OR of the interrupt requests. IIR.INTERRUPT_PENDING=0 means a request is pending; IIR.INTERRUPT_ID identifies the highest-priority source. The following table is ordered highest first; IDs are the three-bit field values, not the full IIR register value.

Table 2. UART interrupt priority and service
ID Source Service / control

7

FIFO integrity error

Investigate err_o; IER.EFEI masks this source. An IIR read does not repair or acknowledge an underlying parity failure.

3

Receiver line status

Capture LSR error fields, then service receive data; controlled by IER.ELSI.

6

Receive timeout

Read RBR to clear the latched timeout. It is generated in FIFO mode when the receive FIFO holds data and its occupancy has not changed for roughly four character times. In the current RTL this request is not gated by IER.

2

Received data ready

Drain RBR below the selected FIFO trigger, or consume the non-FIFO character; controlled by IER.ERBFI.

1

Transmit holding register empty

Write THR, or read IIR while this is the selected source, to clear its latch. A subsequent transition back to empty re-arms it; controlled by IER.ETBEI.

0

Modem status

Read MSR once to capture levels and clear delta bits; controlled by IER.EDSSI.

MCR.OUT2 does not gate irq_o; its modem and loopback uses are described in the UART modem status section of the Programmer’s Guide. The ITR extension can force interrupt sources for testing. Clear test settings after use. Do not rely on clearing IER alone to silence the unmasked timeout source; use the subsystem interrupt controller when masking all delivery is required.

3. Interface

3.1. Configuration Parameters

The UART 16550 module provides configurable parameters to customize FIFO sizes according to system requirements.

The parameters and ports of uart_16550 are listed in uart_16550.

3.2. Modem Control Interface

The modem control interface provides full RS-232 modem signaling compatibility. All modem signals are active low at the pins, matching the RS-232 convention.

The modem inputs are status only. Each one is synchronized and then reported in the MSR register in the opposite polarity (a bit reads 1 while its pin is asserted low), and a change on any of them raises the Modem Status Interrupt. None of them gates the datapath: this component implements no automatic flow control, so software must act on the interrupt to throttle traffic. The software flow control procedure is in the Programmer’s Guide.

3.3. DMA Interface

The DMA interface provides signals for Direct Memory Access controllers to manage data transfers automatically. The rxrdy_o and txrdy_o signals indicate when DMA operations can proceed, with behavior configurable through FIFO control modes.

3.5. Clock Domain

All interface signals operate in a single clock domain referenced to clk_i. The following timing considerations apply:

  • AXI4-Lite Protocol: All AXI4-Lite signals must meet setup and hold time requirements relative to clk_i

  • Asynchronous Inputs: rx_i and modem control inputs (cts_ni, dsr_ni, ri_ni, dcd_ni) are asynchronous and are synchronized internally

  • Reset Requirements: rst_ni should be asserted asynchronously and deasserted synchronously relative to clk_i

3.6. Serial Interface Timing

  • Baud Rate: Serial data rate is determined by the divisor latch registers (DLL/DLM) and uses 16x oversampling

  • Maximum Baud Rate: Limited to system_clock_frequency / 32 - a divisor of 0 disables the transmitter and receiver, so the smallest usable divisor is 1

  • Data Frame: Configurable start bit (always 1), 5-8 data bits, optional parity bit, 1-2 stop bits

3.7. Protocol Support

The interface supports standard UART communication protocols:

  • RS-232: Full modem control and serial data signaling

  • RS-485: Can be used with external transceivers (using RTS for direction control)

  • Industrial Protocols: Compatible with Modbus RTU and other industrial serial protocols

  • Debug Interfaces: Suitable for system debug and console applications

The comprehensive interface design ensures compatibility with a wide range of serial communication requirements while maintaining the flexibility needed for diverse embedded system applications.

4. Memory Map and Register Reference

4.1. Memory Map

The core decodes a 64-byte register space with 32-bit registers on four-byte boundaries. Offsets 0x00 and 0x04 change meaning with LCR.DLAB; offset 0x08 reads IIR and writes FCR. See Programming for safe divisor and FIFO configuration. The generated views below retain all field definitions, including ECR extended trigger selection and ITR interrupt tests.

4.2. Detailed Register Map

The first two register views apply when LCR.DLAB=0; read-only and write-only aliases at the same offset are shown separately. Registers outside offsets 0x00 and 0x04, including FCR at 0x08, are accessible for either LCR.DLAB value. The divisor-latch view applies when LCR.DLAB=1.

UART 16550 Main Address Map

Contains the mode-independent registers and the read-only registers accessible only
when `DLAB = 0`.

Register List:

Table 3. UART 16550 Main Address Map register list
AddressNameAccessDescription
0x0RBRRReceiver Buffer Register
0x4IERRWInterrupt Enable Register
0x8IIRRInterrupt Identification Register
0xCLCRRWLine Control Register
0x10MCRRWModem Control Register
0x14LSRRLine Status Register
0x18MSRRModem Status Register
0x1CSCRRWScratch Register
0x20ECRRWExtended Control Register
0x24ITRRWInterrupt Test Register

Register Details:

RBR

Table 4. uart_16550_main.RBR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7:0DATAR RMOD0x0Received Data. Contains a received character. If FIFOs are enabled, this field
points to the bottom of the RX FIFO. Otherwise, this field points to a single-
byte Receiver Buffer Register.

IER

Table 5. uart_16550_main.IER fields
BitsFieldAccessResetDescription
31:5Reserved--Reserved
4EFEIRW0x0Enable FIFO Error Interrupt.
3EDSSIRW0x0Enable (Delta Status of) Modem Status Interrupt.
2ELSIRW0x0Enable (Receiver) Line Status Interrupt.
1ETBEIRW0x0Enable Transmitter Buffer Empty (Transmitter Holding Register Empty)
Interrupt.
0ERBFIRW0x0Enable Receiver Buffer Full (Received Data Ready) Interrupt.

IIR

Table 6. uart_16550_main.IIR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7:6FIFOS_ENABLEDR0x0FIFOs Enabled:
* `0x0` - FIFOs are disabled
* `0x3` - FIFOs are enabled
5:4Reserved--Reserved
3:1INTERRUPT_IDR0x0Interrupt ID:
* `0x7` - FIFO Error Interrupt (priority 0)
* `0x3` - Receiver Line Status Interrupt (priority 1)
* `0x6` - Reception Timeout Interrupt (priority 2)
* `0x2` - Received Data Ready Interrupt (priority 3)
* `0x1` - Transmitter Holding Register Empty Interrupt (priority 4)
* `0x0` - Modem Status Interrupt (priority 5)
0INTERRUPT_PENDINGR0x1Interrupt Pending. Active-low.

LCR

Table 7. uart_16550_main.LCR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7DLABRW0x0Divisor Latch Access Bit. If set, allows access to the `DLL` and `DLM` registers
when accessing addresses `0x0` and `0x4`, respectively. If unset, allows access
to the `THR`, `RBR`, and `IIR` registers.
6SET_BREAKRW0x0Set Break. If set, forces the `tx_o` output to `0` to cause a break condition
on the receiving UART.
5STICK_PARITYRW0x0Stick Parity. If set, forces the transmit and received parity bits to be `0` if
even parity is selected and `1` if odd parity is selected.
4EPSRW0x0Even Parity Select:
* `1` - even parity
* `0` - odd parity
3PENRW0x0Parity Enable.
2STBRW0x0Stop Bits:
* `0` - 1 stop bit.
* `1` - 2 stop bits (or 1.5 stop bits if word length is set to 5 bits)
1:0WLSRW0x0Word Length Select:
* `0x0` - 5 bits per character
* `0x1` - 6 bits per character
* `0x2` - 7 bits per character
* `0x3` - 8 bits per character

MCR

Table 8. uart_16550_main.MCR fields
BitsFieldAccessResetDescription
31:6Reserved--Reserved
5LINE_LOOPBACKRW0x0Line Loopback. If set, the `rx_i` input is internally connected to the
`tx_o` output.
4LOOPRW0x0System Loopback. If set, the transmitter is internally connected to the
receiver. The `tx_o` output is set to `1`.
3OUT2RW0x0User Output 2. Writing to this bit drives the `out2_no` in the opposite
polarity.
2OUT1RW0x0User Output 1. Writing to this bit drives the `out1_no` in the opposite
polarity.
1RTSRW0x0Request to Send. Writing to this bit drives the `rts_no` output in the opposite
polarity.
0DTRRW0x0Data Terminal Ready. Writing to this bit drives the `dtr_no` output in the
opposite polarity.

LSR

Table 9. uart_16550_main.LSR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7ERROR_IN_RCVR_FIFOR0x0Error in Receiver FIFO. When set, indicates that the receiver FIFO or (RBR in
non-FIFO mode) has the parity, framing, or break error. In other words, at
least one of the PE, FE, and BI bits is set.
6TEMTR0x1Transmitter Empty. When set, indicates that the transmitter shift register and
the transmitter FIFO (or THR in non-FIFO mode) are empty.
5THRER0x1Transmitter Holding Register Empty. When set, indicates that the TX FIFO (or
THR in non-FIFO mode) is empty. Clearing the Transmitter Holding Register Empty
Interrupt does NOT clear this bit.
4BIR RC0x0Break Interrupt. When set, indicates that the `rx_i` input is `0` for an entire
frame's time (start + data + parity + stop bits). In FIFO mode, this bit set
when the character reaches the top of the receiver FIFO. In non-FIFO mode, this
bit is set when the character enters the RBR. This bit triggers the Receiver
Line Status Interrupt.
3FER RC0x0Framing Error. When set, indicates that the received character is missing a
stop bit. In FIFO mode, this bit is set when the character reaches the top of
the FIFO. In non-FIFO mode, this bit is set when the character enters the RBR.
This bit triggers the Receiver Line Status Interrupt.
2PER RC0x0Parity Error. When set, indicates that the character at the top of the receiver
FIFO (or RBR in non-FIFO mode) has a parity error. This bit triggers the
Receiver Line Status Interrupt.
1OER RC0x0Overrun Error. When set, indicates that the RX FIFO (or Receiver Buffer
Register in Non-FIFO Mode) is full when new character is received. In FIFO Mode, the new character
is dropped. In non-FIFO mode, the existing character in the RBR is overwritten.
This bit triggers the Receiver Line Status Interrupt.
0DRR0x0Data Ready. When set, indicates that the RX FIFO (or RBR in non-FIFO
mode) contains data.

MSR

Table 10. uart_16550_main.MSR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7DCDR0x0Data Carrier Detect. This bit reflects the `dcd_ni` input in the opposite
polarity, so it reads `1` while a carrier is detected.
6RIR0x0Ring Indicator. This bit reflects the `ri_ni` input in the opposite polarity, so
it reads `1` while the remote modem signals an incoming call.
5DSRR0x0Data Set Ready. This bit reflects the `dsr_ni` input in the opposite polarity,
so it reads `1` while the remote modem is connected and ready.
4CTSR0x0Clear to Send. This bit reflects the `cts_ni` input in the opposite polarity, so
it reads `1` while the remote device is ready to receive data.
3DDCDR RC0x0Delta Data Carrier Detect. When set, indicates that the `DCD` bit has changed
since the last time this register was read. This bit triggers the Modem Status
Interrupt.
2TERIR RC0x0Trailing Edge Ring Indicator. When set, indicates that the `RI` bit has changed
from a `1` to a `0`. This bit triggers the Modem Status Interrupt.
1DDSRR RC0x0Delta Data Set Ready. When set, indicates that the `DSR` bit has changed since
the last time this register was read. This bit triggers the Modem Status
Interrupt.
0DCTSR RC0x0Delta Clear to Send. When set, indicates that the `CTS` bit has changed since
the last time this register was read. This bit triggers the Modem Status
Interrupt.

SCR

Table 11. uart_16550_main.SCR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7:0SCRRW0x0Scratch. Holds user data.

ECR

Table 12. uart_16550_main.ECR fields
BitsFieldAccessResetDescription
31:2Reserved--Reserved
1:0RCVR_TRIGGER_MS2BRW0x0Receiver FIFO Trigger Level Most Significant 2 Bits. To configure the least
significant 2 bits, use the `FCR.RCVR_TRIGGER` register field. The
configurations for the trigger levels are:
* `0x0` - 1 character
* `0x1` - 4 characters
* `0x2` - 8 characters
* `0x3` - 14 characters
* `0x4` - 32 characters
* `0x5` - 64 characters
* `0x6` - 128 characters
* `0x7` - 256 characters
* `0x8` - 512 characters
* `0x9` - 1024 characters
* `0xA` - 2048 characters
* `0xB` - 4096 characters

ITR

Table 13. uart_16550_main.ITR fields
BitsFieldAccessResetDescription
31:6Reserved--Reserved
5TRTIRW0x0Test Reception Timeout Interrupt. Writing a `1` forces the interrupt and
writing `0` releases it.
4TFEIRW0x0Test FIFO Error Interrupt. Writing `1` forces the interrupt and writing `0`
releases it.
3TDSSIRW0x0Test (Delta Status of) Modem Status Interrupt. Writing `1` forces the
interrupt and writing `0` releases it.
2TLSIRW0x0Test (Receiver) Line Status Interrupt. Writing `1` forces the interrupt and
writing `0` releases it.
1TTBEIRW0x0Test Transmitter Buffer Empty (Transmitter Holding Register Empty) Interrupt.
Writing `1` forces the interrupt and writing `0` releases it.
0TRBFIRW0x0Test Receiver Buffer Full (Received Data Ready) Interrupt. Writing `1` forces
the interrupt and writing `0` releases it.

UART 16550 Main Write-Only Address Map

Contains the write-only registers. THR is accessible only when `LCR.DLAB = 0`;
FCR is writable for either `LCR.DLAB` value.

Register List:

Table 14. UART 16550 Main Write-Only Address Map register list
AddressNameAccessDescription
0x0THRWTransmitter Holding Register
0x8FCRWFIFO Control Register

Register Details:

THR

Table 15. uart_16550_main_wo.THR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7:0DATAW WMOD0x0Transmit Data. Holds a character to be transmitted. If FIFOs are enabled, this
field points to the top of the TX FIFO. Otherwise, this field points to a
single-byte Transmitter Holding Register.

FCR

Table 16. uart_16550_main_wo.FCR fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7:6RCVR_TRIGGERW0x0Receiver FIFO Trigger Level (Least Significant 2 Bits). To configure the most
significant 2 bits, use the `ECR.RCVR_TRIGGER_MS2B` register field. The
configurations for the trigger levels are:
* `0x0` - 1 character
* `0x1` - 4 characters
* `0x2` - 8 characters
* `0x3` - 14 characters
* `0x4` - 32 characters
* `0x5` - 64 characters
* `0x6` - 128 characters
* `0x7` - 256 characters
* `0x8` - 512 characters
* `0x9` - 1024 characters
* `0xA` - 2048 characters
* `0xB` - 4096 characters
5:4Reserved--Reserved
3DMA_MODE_SELECTW0x0DMA mode select:
* `0` - DMA Mode 0
* `1` - DMA Mode 1
2XMIT_FIFO_RESETW 1P0x0Transmitter FIFO Reset. Writing `1` clears the TX FIFO.
1RCVR_FIFO_RESETW 1P0x0Receiver FIFO Reset. Writing `1` clears the RX FIFO.
0FIFO_ENABLEW0x0FIFO Enable. When set, enables the TX and RX FIFOs (FIFO Mode). When unset,
disables the FIFOs (Non-FIFO Mode).

UART 16550 Divisor Latch Address Map

Contains the registers accessible only when `LCR.DLAB = 1`.

Register List:

Table 17. UART 16550 Divisor Latch Address Map register list
AddressNameAccessDescription
0x0DLLRWDivisor Latch Least Significant Byte Register
0x4DLMRWDivisor Latch Most Significant Byte Register

Register Details:

DLL

Table 18. uart_16550_dl.DLL fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7:0DLLRW0x0Divisor Latch Least Significant Byte. Baud rate is calculated as
`baud_rate = system_clock_frequency / (16 * (divisor + 1))`. When the divisor is set
to `0`, the transmitter and receiver logic are disabled.

DLM

Table 19. uart_16550_dl.DLM fields
BitsFieldAccessResetDescription
31:8Reserved--Reserved
7:0DLMRW0x0Divisor Latch Most Significant Byte. Baud rate is calculated as
`baud_rate = system_clock_frequency / (16 * (divisor + 1))`. When the divisor is set
to `0`, the transmitter and receiver logic are disabled.