Register Definitions

Relevant source files

This document details the PL011 UART register definitions implemented in the arm_pl011 crate, including the memory-mapped register structure, individual register specifications, and the type-safe abstractions provided by the tock-registers library. This covers the hardware abstraction layer that maps PL011 UART controller registers to Rust data structures.

For information about how these registers are used in UART operations, see UART Operations. For the complete API methods that interact with these registers, see Pl011Uart Methods.

Register Structure Overview

The PL011 UART registers are defined using the register_structs! macro from the tock-registers crate, which provides compile-time memory layout verification and type-safe register access. The Pl011UartRegs structure maps the complete PL011 register set to their hardware-defined memory offsets.

Register Memory Layout

flowchart TD
subgraph subGraph0["Pl011UartRegs Structure"]
    DR["dr: ReadWrite0x00 - Data Register"]
    RES0["_reserved00x04-0x17"]
    FR["fr: ReadOnly0x18 - Flag Register"]
    RES1["_reserved10x1C-0x2F"]
    CR["cr: ReadWrite0x30 - Control Register"]
    IFLS["ifls: ReadWrite0x34 - Interrupt FIFO Level"]
    IMSC["imsc: ReadWrite0x38 - Interrupt Mask Set Clear"]
    RIS["ris: ReadOnly0x3C - Raw Interrupt Status"]
    MIS["mis: ReadOnly0x40 - Masked Interrupt Status"]
    ICR["icr: WriteOnly0x44 - Interrupt Clear"]
    END["@END0x48"]
end

CR --> IFLS
DR --> RES0
FR --> RES1
ICR --> END
IFLS --> IMSC
IMSC --> RIS
MIS --> ICR
RES0 --> FR
RES1 --> CR
RIS --> MIS

Sources: src/pl011.rs(L9 - L32) 

Individual Register Definitions

The register structure defines eight functional registers with specific access patterns and purposes:

RegisterOffsetTypeDescription
dr0x00ReadWriteData Register - transmit/receive data
fr0x18ReadOnlyFlag Register - UART status flags
cr0x30ReadWriteControl Register - UART configuration
ifls0x34ReadWriteInterrupt FIFO Level Select Register
imsc0x38ReadWriteInterrupt Mask Set Clear Register
ris0x3CReadOnlyRaw Interrupt Status Register
mis0x40ReadOnlyMasked Interrupt Status Register
icr0x44WriteOnlyInterrupt Clear Register

Data Register (dr)

The Data Register at offset 0x00 provides bidirectional data access for character transmission and reception. It supports both read and write operations for handling UART data flow.

Flag Register (fr)

The Flag Register at offset 0x18 provides read-only status information about the UART state, including transmit/receive FIFO status and busy indicators.

Control Register (cr)

The Control Register at offset 0x30 configures UART operational parameters including enable/disable states for transmission, reception, and the overall UART controller.

Sources: src/pl011.rs(L9 - L32) 

Type Safety and Memory Mapping

The register definitions leverage the tock-registers library to provide compile-time guarantees about register access patterns and memory safety:

Register Access Type Safety

flowchart TD
subgraph subGraph2["Compile-time Safety"]
    TYPE_CHECK["Type Checking"]
    ACCESS_CONTROL["Access Control"]
    MEMORY_LAYOUT["Memory Layout Verification"]
end
subgraph subGraph1["Tock-Registers Traits"]
    READABLE["Readable Interface"]
    WRITEABLE["Writeable Interface"]
end
subgraph subGraph0["Access Patterns"]
    RO["ReadOnlyfr, ris, mis"]
    RW["ReadWritedr, cr, ifls, imsc"]
    WO["WriteOnlyicr"]
end

ACCESS_CONTROL --> MEMORY_LAYOUT
READABLE --> TYPE_CHECK
RO --> READABLE
RW --> READABLE
RW --> WRITEABLE
TYPE_CHECK --> MEMORY_LAYOUT
WO --> WRITEABLE
WRITEABLE --> ACCESS_CONTROL

The register_structs! macro ensures that:

  • Register offsets match PL011 hardware specifications
  • Reserved memory regions are properly handled
  • Access patterns prevent invalid operations (e.g., reading write-only registers)
  • Memory layout is validated at compile time

Sources: src/pl011.rs(L3 - L7)  src/pl011.rs(L9 - L32) 

Register Access Implementation

The Pl011Uart structure contains a NonNull<Pl011UartRegs> pointer that provides safe access to the memory-mapped registers. The regs() method returns a reference to the register structure for performing hardware operations.

Register Access Flow

flowchart TD
subgraph subGraph2["Hardware Interface"]
    MMIO["Memory-Mapped I/O"]
    PL011_HW["PL011 Hardware"]
end
subgraph subGraph1["Register Operations"]
    READ["Register Read Operations"]
    WRITE["Register Write Operations"]
    SET["Register Set Operations"]
    GET["Register Get Operations"]
end
subgraph subGraph0["Pl011Uart Structure"]
    BASE["base: NonNull"]
    REGS_METHOD["regs() -> &Pl011UartRegs"]
end

BASE --> REGS_METHOD
GET --> MMIO
MMIO --> PL011_HW
READ --> SET
REGS_METHOD --> READ
REGS_METHOD --> WRITE
SET --> MMIO
WRITE --> GET

The implementation ensures memory safety through:

  • Const construction via NonNull::new().unwrap().cast()
  • Unsafe register access contained within safe method boundaries
  • Type-safe register operations through tock-registers interfaces

Sources: src/pl011.rs(L42 - L59)