From 62b6c51e9509131340d1a14781c36f3fe7fae12a Mon Sep 17 00:00:00 2001 From: Afonso Oliveira Date: Wed, 1 Apr 2026 09:57:41 +0100 Subject: [PATCH 1/2] [sw-sysemu] fix Boot ROM address in memory map comment --- sw-sysemu/memory/erbium/main_memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sw-sysemu/memory/erbium/main_memory.h b/sw-sysemu/memory/erbium/main_memory.h index 644bff3d8..2a861b297 100644 --- a/sw-sysemu/memory/erbium/main_memory.h +++ b/sw-sysemu/memory/erbium/main_memory.h @@ -28,7 +28,7 @@ namespace bemu { // +----------------+----------------+----------+-------------------+ // | 0x00_0200_0000 | 0x00_0200_0FFF | 4KiB | SystemRegisters | // | 0x00_0200_4000 | 0x00_0200_4FFF | 4KiB | UART | -// | 0x00_0200_A000 | 0x00_0200_BFFF | 8KiB | Boot ROM | +// | 0x00_0200_8000 | 0x00_0200_9FFF | 8KiB | Boot ROM | // | 0x00_0200_C000 | 0x00_0200_CFFF | 4KiB | Scratch SRAM | // | 0x00_4000_0000 | 0x00_40FF_FFFF | 16MiB | MRAM | // | 0x00_7FFF_D000 | 0x00_7FFF_FFFF | 12KiB | OTP (read-only) | From 8a9b8100736747a94a535c25e69ea27dc370e93a Mon Sep 17 00:00:00 2001 From: Afonso Oliveira Date: Wed, 1 Apr 2026 09:59:03 +0100 Subject: [PATCH 2/2] [sw-sysemu] add placeholder regions for Erbium I2C, QSPI, xSPI and NIC --- sw-sysemu/memory/erbium/main_memory.cpp | 4 +++ sw-sysemu/memory/erbium/main_memory.h | 17 +++++++++ sw-sysemu/pma_er.cpp | 48 ++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/sw-sysemu/memory/erbium/main_memory.cpp b/sw-sysemu/memory/erbium/main_memory.cpp index 5da708d54..94cc3b521 100644 --- a/sw-sysemu/memory/erbium/main_memory.cpp +++ b/sw-sysemu/memory/erbium/main_memory.cpp @@ -18,13 +18,17 @@ void MainMemory::reset() { regions[erbreg_idx].reset(new SysregsEr()); regions[mram_bridge_idx].reset(new DenseRegion()); + regions[i2c_idx].reset(new DenseRegion()); + regions[qspi_idx].reset(new DenseRegion()); regions[uart_idx].reset(new ShaktiUart()); regions[bootrom_idx].reset(new DenseRegion()); regions[sram_idx].reset(new DenseRegion()); + regions[xspi_idx].reset(new DenseRegion()); regions[dram_idx].reset(new DenseRegion()); regions[otp_idx].reset(new DenseRegion()); regions[sysreg_idx].reset(new SysregRegion()); regions[plic_idx].reset(new ER_PLIC()); + regions[nic_idx].reset(new DenseRegion()); } void MainMemory::wdt_clock_tick(const Agent& agent, uint64_t cycle) diff --git a/sw-sysemu/memory/erbium/main_memory.h b/sw-sysemu/memory/erbium/main_memory.h index 2a861b297..f67db562e 100644 --- a/sw-sysemu/memory/erbium/main_memory.h +++ b/sw-sysemu/memory/erbium/main_memory.h @@ -27,13 +27,18 @@ namespace bemu { // | From | To | Size | Maps to | // +----------------+----------------+----------+-------------------+ // | 0x00_0200_0000 | 0x00_0200_0FFF | 4KiB | SystemRegisters | +// | 0x00_0200_1000 | 0x00_0200_1FFF | 4KiB | MRAM Bridge | +// | 0x00_0200_2000 | 0x00_0200_2FFF | 4KiB | I2C | +// | 0x00_0200_3000 | 0x00_0200_3FFF | 4KiB | QSPI | // | 0x00_0200_4000 | 0x00_0200_4FFF | 4KiB | UART | // | 0x00_0200_8000 | 0x00_0200_9FFF | 8KiB | Boot ROM | // | 0x00_0200_C000 | 0x00_0200_CFFF | 4KiB | Scratch SRAM | +// | 0x00_0200_F000 | 0x00_0200_FFFF | 4KiB | xSPI | // | 0x00_4000_0000 | 0x00_40FF_FFFF | 16MiB | MRAM | // | 0x00_7FFF_D000 | 0x00_7FFF_FFFF | 12KiB | OTP (read-only) | // | 0x00_8000_0000 | 0x00_80FF_FFFF | 16MiB | ESR Registers | // | 0x00_A000_0000 | 0x00_A3FF_FFFF | 64MiB | PLIC | +// | 0x00_FE00_0000 | 0x00_FE01_5FFF | 88KiB | NIC config | // +----------------+----------------+----------+-------------------+ // @@ -48,13 +53,17 @@ struct MainMemory { enum : unsigned { erbreg_idx, mram_bridge_idx, + i2c_idx, + qspi_idx, uart_idx, bootrom_idx, sram_idx, + xspi_idx, dram_idx, otp_idx, sysreg_idx, plic_idx, + nic_idx, REGION_COUNT }; @@ -62,25 +71,33 @@ struct MainMemory { constexpr static uint64_t region_bases[REGION_COUNT] = { /* erbreg */ ERBIUM_TOP_SYSTEM_REGISTERS_BASE, /* mram_bridge */ ERBIUM_TOP_MRAM_REGISTERS_BASE, + /* i2c */ ERBIUM_TOP_I2C_REGISTERS_BASE, + /* qspi */ ERBIUM_TOP_QSPI_REGISTERS_BASE, /* uart */ ERBIUM_TOP_UART_REGISTERS_BASE, /* bootrom */ ERBIUM_TOP_BOOTROM_BASE, /* sram */ ERBIUM_TOP_SRAM_BASE, + /* xspi */ ERBIUM_TOP_XSPI_REGISTERS_BASE, /* dram */ ERBIUM_TOP_MRAM_BASE, /* otp */ 0x007FFFD000ull, /* sysreg */ ERBIUM_TOP_CPU_REGISTERS_BASE, /* plic */ ERBIUM_TOP_PLIC_BASE, + /* nic */ ERBIUM_TOP_NIC_CONFIG_BASE, }; constexpr static size_t region_sizes[REGION_COUNT] = { /* erbreg */ ERBIUM_TOP_MRAM_REGISTERS_BASE - ERBIUM_TOP_SYSTEM_REGISTERS_BASE, /* mram_bridge */ ERBIUM_TOP_I2C_REGISTERS_BASE - ERBIUM_TOP_MRAM_REGISTERS_BASE, + /* i2c */ ERBIUM_TOP_QSPI_REGISTERS_BASE - ERBIUM_TOP_I2C_REGISTERS_BASE, + /* qspi */ ERBIUM_TOP_UART_REGISTERS_BASE - ERBIUM_TOP_QSPI_REGISTERS_BASE, /* uart */ 4_KiB, /* bootrom */ ERBIUM_TOP_BOOTROM_SIZE, /* sram */ ERBIUM_TOP_SRAM_SIZE, + /* xspi */ 4_KiB, /* dram */ ERBIUM_TOP_MRAM_SIZE, /* otp */ 12_KiB, /* sysreg */ 16_MiB, /* plic */ 64_MiB, + /* nic */ ERBIUM_TOP_NIC_CONFIG_SIZE, }; public: diff --git a/sw-sysemu/pma_er.cpp b/sw-sysemu/pma_er.cpp index b8bf90a0b..2e8ac0dae 100644 --- a/sw-sysemu/pma_er.cpp +++ b/sw-sysemu/pma_er.cpp @@ -19,7 +19,8 @@ namespace bemu { // // 0x0200_0000 - 0x0200_0FFF: System registers (4K) // 0x0200_1000 - 0x0200_1FFF: MRAM registers (4K) -// 0x0200_2000 - 0x0200_2FFF: Periph registers (4K) +// 0x0200_2000 - 0x0200_2FFF: I2C registers (4K) +// 0x0200_3000 - 0x0200_3FFF: QSPI registers (4K) // 0x0200_F000 - 0x0200_FFFF: xSPI registers (4K) // 0x0200_4000 - 0x0200_4FFF: UART registers (4K) // 0x0200_8000 - 0x0200_9FFF: Bootrom (8K) @@ -28,6 +29,7 @@ namespace bemu { // 0x7FFF_D000 - 0x7FFF_FFFF: OTP (12K, read-only) // 0x8000_0000 - 0x9FFF_FFFF: ESR/CPU registers (512M) // 0xA000_0000 - 0xA3FF_FFFF: PLIC (64M) +// 0xFE00_0000 - 0xFE01_5FFF: NIC config (88K) // // Bases come from hwinc/top.h (regenerated from the top-level RDL); // upper bounds either come from the next region's base or, where the @@ -39,11 +41,14 @@ static inline bool paddr_is_sysreg(uint64_t addr) static inline bool paddr_is_mramreg(uint64_t addr) { return (addr >= ERBIUM_TOP_MRAM_REGISTERS_BASE) && (addr < ERBIUM_TOP_I2C_REGISTERS_BASE); } -static inline bool paddr_is_periph(uint64_t addr) +static inline bool paddr_is_i2c(uint64_t addr) { return (addr >= ERBIUM_TOP_I2C_REGISTERS_BASE) && (addr < ERBIUM_TOP_QSPI_REGISTERS_BASE); } +static inline bool paddr_is_qspi(uint64_t addr) +{ return (addr >= ERBIUM_TOP_QSPI_REGISTERS_BASE) && (addr < ERBIUM_TOP_UART_REGISTERS_BASE); } + static inline bool paddr_is_xspi(uint64_t addr) -{ return (addr >= ERBIUM_TOP_XSPI_REGISTERS_BASE) && (addr < ERBIUM_TOP_XSPI_REGISTERS_END); } +{ return (addr >= ERBIUM_TOP_XSPI_REGISTERS_BASE) && (addr < ERBIUM_TOP_XSPI_REGISTERS_BASE + 0x1000ull); } static inline bool paddr_is_uart(uint64_t addr) { return (addr >= ERBIUM_TOP_UART_REGISTERS_BASE) && (addr < ERBIUM_TOP_UART_REGISTERS_END); } @@ -68,6 +73,9 @@ static inline bool paddr_is_mram(uint64_t addr) static inline bool paddr_is_esr(uint64_t addr) { return (addr >= ERBIUM_TOP_CPU_REGISTERS_BASE) && (addr < ERBIUM_TOP_PLIC_BASE); } +static inline bool paddr_is_nic(uint64_t addr) +{ return (addr >= ERBIUM_TOP_NIC_CONFIG_BASE) && (addr < ERBIUM_TOP_NIC_CONFIG_END); } + static inline bool paddr_is_plic(uint64_t addr) { return (addr >= ERBIUM_TOP_PLIC_BASE) && (addr < ERBIUM_TOP_PLIC_END); } @@ -275,8 +283,8 @@ uint64_t pma_check_data_access(const Hart& cpu, uint64_t vaddr, return addr; } - if (paddr_is_periph(addr)) { - // Periph registers: 32-bit aligned, 32-bit access, M/S privilege, + if (paddr_is_i2c(addr)) { + // I2C registers: 32-bit aligned, 32-bit access, M/S privilege, // no AMO/TensorOp/CacheOp Privilege mode = effective_execution_mode(cpu, macc); if (amo @@ -305,6 +313,21 @@ uint64_t pma_check_data_access(const Hart& cpu, uint64_t vaddr, return addr; } + if (paddr_is_qspi(addr)) { + // QSPI registers: 64-bit aligned, 32-bit access, M/S privilege, + // no AMO/TensorOp/CacheOp + Privilege mode = effective_execution_mode(cpu, macc); + if (amo + || ts_tl_co + || (size != 4) + || !addr_is_size_aligned(addr, 8) + || (mode == Privilege::U)) + { + throw_access_fault(vaddr, macc); + } + return addr; + } + if (paddr_is_uart(addr)) { // UART registers: 64-bit aligned, 32-bit access, M/S privilege, // no AMO/TensorOp/CacheOp @@ -320,6 +343,21 @@ uint64_t pma_check_data_access(const Hart& cpu, uint64_t vaddr, return addr; } + if (paddr_is_nic(addr)) { + // NIC config: 64-bit aligned, 32-bit access, M-mode only, + // no AMO/TensorOp/CacheOp + Privilege mode = effective_execution_mode(cpu, macc); + if (amo + || ts_tl_co + || (size != 4) + || !addr_is_size_aligned(addr, 8) + || (mode != Privilege::M)) + { + throw_access_fault(vaddr, macc); + } + return addr; + } + // Unknown/reserved region - access fault throw_access_fault(vaddr, macc); }