Architecture Overview

Relevant source files

This document provides a high-level view of the riscv_goldfish system architecture, showing how the RTC driver components integrate from the hardware layer up to application interfaces. It covers the overall system stack, component relationships, and data flow patterns without diving into implementation details.

For detailed API documentation, see API Reference. For hardware register specifics, see Hardware Interface. For time conversion implementation details, see Time Conversion.

System Stack Architecture

The riscv_goldfish driver operates within a layered architecture that spans from hardware registers to application-level time services:

flowchart TD
subgraph subGraph4["Hardware Platform"]
    GOLDFISH_HW["Goldfish RTC Hardware"]
end
subgraph subGraph3["Hardware Registers"]
    RTC_TIME_LOW_REG["RTC_TIME_LOW (0x00)"]
    RTC_TIME_HIGH_REG["RTC_TIME_HIGH (0x04)"]
end
subgraph subGraph2["Hardware Abstraction"]
    MMIO_READ["read()"]
    MMIO_WRITE["write()"]
    BASE_ADDR["base_address field"]
end
subgraph subGraph1["Driver Layer (src/lib.rs)"]
    RTC_STRUCT["Rtc struct"]
    API_NEW["new()"]
    API_GET["get_unix_timestamp()"]
    API_SET["set_unix_timestamp()"]
end
subgraph subGraph0["Application Layer"]
    APP["Application Code"]
    OS["ArceOS Operating System"]
end

API_GET --> MMIO_READ
API_SET --> MMIO_WRITE
APP --> OS
MMIO_READ --> BASE_ADDR
MMIO_READ --> RTC_TIME_HIGH_REG
MMIO_READ --> RTC_TIME_LOW_REG
MMIO_WRITE --> BASE_ADDR
MMIO_WRITE --> RTC_TIME_HIGH_REG
MMIO_WRITE --> RTC_TIME_LOW_REG
OS --> RTC_STRUCT
RTC_STRUCT --> API_GET
RTC_STRUCT --> API_NEW
RTC_STRUCT --> API_SET
RTC_TIME_HIGH_REG --> GOLDFISH_HW
RTC_TIME_LOW_REG --> GOLDFISH_HW

This architecture demonstrates the clear separation of concerns between application logic, driver abstraction, hardware interface, and physical hardware. The Rtc struct serves as the primary abstraction boundary, providing a safe interface to unsafe hardware operations.

Sources: src/lib.rs(L11 - L14)  src/lib.rs(L26 - L33)  src/lib.rs(L35 - L49) 

Component Architecture

The core driver architecture centers around the Rtc struct and its associated methods:

flowchart TD
subgraph subGraph3["Hardware Interface"]
    READ_VOLATILE["core::ptr::read_volatile"]
    WRITE_VOLATILE["core::ptr::write_volatile"]
end
subgraph Constants["Constants"]
    RTC_TIME_LOW_CONST["RTC_TIME_LOW = 0x00"]
    RTC_TIME_HIGH_CONST["RTC_TIME_HIGH = 0x04"]
    NSEC_PER_SEC_CONST["NSEC_PER_SEC = 1_000_000_000"]
end
subgraph subGraph1["Private Implementation"]
    READ_METHOD["read(reg: usize) -> u32"]
    WRITE_METHOD["write(reg: usize, value: u32)"]
    BASE_FIELD["base_address: usize"]
end
subgraph subGraph0["Public API (src/lib.rs)"]
    RTC["Rtc"]
    NEW["new(base_address: usize)"]
    GET_TS["get_unix_timestamp() -> u64"]
    SET_TS["set_unix_timestamp(unix_time: u64)"]
end

GET_TS --> NSEC_PER_SEC_CONST
GET_TS --> READ_METHOD
NEW --> BASE_FIELD
READ_METHOD --> BASE_FIELD
READ_METHOD --> READ_VOLATILE
READ_METHOD --> RTC_TIME_HIGH_CONST
READ_METHOD --> RTC_TIME_LOW_CONST
SET_TS --> NSEC_PER_SEC_CONST
SET_TS --> WRITE_METHOD
WRITE_METHOD --> BASE_FIELD
WRITE_METHOD --> RTC_TIME_HIGH_CONST
WRITE_METHOD --> RTC_TIME_LOW_CONST
WRITE_METHOD --> WRITE_VOLATILE

The component design follows a minimal surface area principle with only three public methods exposed. The private read and write methods encapsulate all unsafe hardware interactions, while constants define the register layout and time conversion factors.

Sources: src/lib.rs(L6 - L9)  src/lib.rs(L12 - L14)  src/lib.rs(L17 - L23)  src/lib.rs(L27 - L49) 

Data Flow Architecture

The driver implements bidirectional data flow between Unix timestamps and hardware nanosecond values:

flowchart TD
subgraph subGraph2["Hardware Layer"]
    HW_REGISTERS["64-bit nanosecond counter"]
end
subgraph subGraph1["Write Path (set_unix_timestamp)"]
    WRITE_START["set_unix_timestamp(unix_time)"]
    CONVERT_TO_NS["unix_time * NSEC_PER_SEC"]
    SPLIT_HIGH["(time_nanos >> 32) as u32"]
    SPLIT_LOW["time_nanos as u32"]
    WRITE_HIGH["write(RTC_TIME_HIGH, high)"]
    WRITE_LOW["write(RTC_TIME_LOW, low)"]
end
subgraph subGraph0["Read Path (get_unix_timestamp)"]
    READ_START["get_unix_timestamp()"]
    READ_LOW["read(RTC_TIME_LOW) -> u32"]
    READ_HIGH["read(RTC_TIME_HIGH) -> u32"]
    COMBINE["(high << 32) | low"]
    CONVERT_TO_SEC["result / NSEC_PER_SEC"]
    READ_RESULT["return u64"]
end

COMBINE --> CONVERT_TO_SEC
CONVERT_TO_NS --> SPLIT_HIGH
CONVERT_TO_NS --> SPLIT_LOW
CONVERT_TO_SEC --> READ_RESULT
READ_HIGH --> COMBINE
READ_HIGH --> HW_REGISTERS
READ_LOW --> COMBINE
READ_LOW --> HW_REGISTERS
READ_START --> READ_HIGH
READ_START --> READ_LOW
SPLIT_HIGH --> WRITE_HIGH
SPLIT_LOW --> WRITE_LOW
WRITE_HIGH --> HW_REGISTERS
WRITE_LOW --> HW_REGISTERS
WRITE_START --> CONVERT_TO_NS

The data flow demonstrates the critical conversion between user-space Unix timestamps (seconds) and hardware nanosecond representation. The 64-bit hardware value must be split across two 32-bit registers for write operations and reconstructed for read operations.

Sources: src/lib.rs(L36 - L40)  src/lib.rs(L43 - L49)  src/lib.rs(L9) 

Integration Architecture

The driver integrates within the broader ArceOS ecosystem and cross-platform build system:

flowchart TD
subgraph subGraph3["Driver Core"]
    RTC_DRIVER["riscv_goldfish::Rtc"]
end
subgraph subGraph2["Platform Integration"]
    DEVICE_TREE["Device Tree (base_addr: 0x101000)"]
    ARCEOS_OS["ArceOS"]
    COMPATIBLE["google,goldfish-rtc"]
end
subgraph subGraph1["Crate Features"]
    NO_STD["#![no_std]"]
    CARGO_TOML["Cargo.toml metadata"]
end
subgraph subGraph0["Build Targets"]
    X86_64_LINUX["x86_64-unknown-linux-gnu"]
    X86_64_NONE["x86_64-unknown-none"]
    RISCV64["riscv64gc-unknown-none-elf"]
    AARCH64["aarch64-unknown-none-softfloat"]
end

ARCEOS_OS --> RTC_DRIVER
CARGO_TOML --> NO_STD
COMPATIBLE --> RTC_DRIVER
DEVICE_TREE --> RTC_DRIVER
NO_STD --> AARCH64
NO_STD --> RISCV64
NO_STD --> X86_64_LINUX
NO_STD --> X86_64_NONE
RTC_DRIVER --> AARCH64
RTC_DRIVER --> RISCV64
RTC_DRIVER --> X86_64_LINUX
RTC_DRIVER --> X86_64_NONE

The integration architecture shows how the no_std design enables cross-compilation to multiple targets while maintaining compatibility with the ArceOS operating system. Device tree integration provides the necessary base_address configuration for hardware discovery.

Sources: src/lib.rs(L4)  README.md(L15 - L32)  README.md(L5)  README.md(L10 - L13)