i-RISCV Input/Output Support

The i-RISCV SoC provides the following input/output mechanisms.

IOMMU

The SoC implements the RISC-V IOMMU (v1.0) for DMA-capable devices. Supported mechanisms:

  • Device Directory Table (DDT) walk in Off, Bare, 1LVL, 2LVL, and 3LVL modes
  • Second-stage-only DMA address translation (Sv39x4/Sv48x4/Sv57x4) with hardware A/D update on page-table entries
  • MSI address translation, redirecting a device’s writes to a guest’s virtual IMSIC interrupt file onto the real physical guest file (AIA/IMSIC tie-in)
  • IOATC: a device-context cache and an I/O TLB, invalidated via IODIR.INVAL_DDT and IOTINVAL.VMA/.GVMA commands
  • Command queue (IOTINVAL, IOFENCE.C, IODIR) and fault queue for translation errors
  • WSI (wire-signal) interrupt delivery to the PLIC/APLIC on faults or fence completion
  • IOPMP enforcement of the final physical address after every successful translation

AIA and IMSIC

The core implements the RISC-V Advanced Interrupt Architecture (AIA, v1.0). Supported mechanisms:

  • Smaia/Ssaia: M-level and S-level AIA CSRs (miselect/mireg, siselect/sireg, mtopi/stopi, mvien/mvip)
  • IMSIC (Incoming MSI Controller) with per-hart M-file and S-file, memory-mapped MSI delivery (seteipnum_le), and claim-and-clear via mtopei/stopei
  • Two VS-level guest interrupt files per hart for the H extension, selected by hstatus.VGEIN, each with its own physical MSI region to support migrating a guest between files
  • VS-level hypervisor AIA CSRs (hvien, hvictl, vsiselect/vsireg, vstopei/vstopi)
  • A minimal, MSI-mode-only, machine-level APLIC domain (aplic0, 8 sources, msi-parent = imsic_s) that forwards this platform’s wired sources into the IMSIC S-file as MSIs – under Linux, the IOMMU’s and IOPMP’s interrupts are advertised against it (sources 2/3) instead of through plic0’s own S-mode context, which keeps a position-preserving placeholder entry; the PLIC retains its M-mode context for firmware and bare-metal use

IOPMP

The SoC implements RISC-V I/O Physical Memory Protection (IOPMP), which regulates physical-address accesses issued by non-hart bus requesters (the IOMMU’s translation path). Supported mechanisms:

  • 16 requester IDs, 8 memory domains, and 16 protection entries
  • TOR/NA4/NAPOT address matching with lowest-index-wins priority and per-entry r/w/x permissions
  • Memory-domain / source association gating (MDCFG/SRCMD_EN)
  • Locking of MD associations, MDCFG, and entries (W1SS/incremental-only)
  • First-violation error capture (requester ID, address, access type, denial reason) with interrupt reporting

Console UART

A genuine ns16550a-register-compatible serial console (rtl/uncore/uart.sv), build-time optional (UART_ENABLE; at 0 it is removed from the design entirely – registers read 0, interrupt tied low, TX held idle-high). Supported mechanisms:

  • Standard byte-addressed 8-register map with DLAB-banked offsets 0/1 (RBR/THR/DLL, IER/DLM, IIR/FCR, LCR, MCR, LSR, MSR, SCR) – the exact layout a stock Linux 8250 driver expects, no reg-shift/reg-io-width overrides
  • Real baud-rate divisor: one bit period = 16 x DLL/DLM core cycles; reset to 115200 at a 50 MHz clock so bare-metal firmware gets a known rate without programming it; reprogrammed via the standard DLAB sequence
  • Full 16550A hardware FIFOs: 16-byte TX and RX, enabled by sticky FCR.FE (any toggle clears both), four RX trigger levels (1/4/8/14 bytes) plus a real 4-character-time RX timeout interrupt so low-throughput links never stall below the trigger level; without FCR.FE, one physical shift register feeds single holding/latch registers instead (THR writes while busy are silently ignored, THRE and TEMT collapse to one condition)
  • Receiver error detection – framing error, BREAK, overrun – with per-byte error tags in the RX FIFO feeding LSR’s errors-in-FIFO bit; RBR reads clear DR/pop the FIFO while LSR reads clear OE/PE/FE/BI (two distinct read-to-clear conditions, matching real 16550 semantics)
  • Real interrupt priority chain: line status > data available / character timeout > THR-empty (one-shot – fires exactly once per emptying, acknowledged by an IIR read or a new THR write) > modem status, with standard IIR identification codes
  • MCR.LOOP internal loopback feeding the transmitter back into the receiver while the external TX pin is held idle-high; in loopback mode MSR’s CTS/DSR/RI/DCD mirror MCR’s DTR/RTS/OUT1/OUT2 one-to-one with delta bits latched and cleared on read
  • Modem status defaults to “always ready” (CTS=DSR=DCD=1, RI=0) since no real modem lines exist

The UART’s irq is wired to both controllers’ source 1 (source 2 = the IOMMU WSI, source 3 = the IOPMP); sources 2 and 3 are advertised in the device tree against aplic0, while the UART itself carries no interrupts property – a single honest compatible = "ns16550a" – so under Linux the stock driver falls back to polling (see Linux).

Disclosed simplifications. Not silent scope cuts:

  • Fixed 8N1 wire framing – LCR’s word-length/parity/stop-bit fields are stored and read back faithfully but not enforced on the wire
  • No 16750/16950 extensions (no 64-byte FIFO, no auto-flow-control beyond the plain MCR/MSR pins)