From 97335b9df1c018492e55703e2690ab42d54b2340 Mon Sep 17 00:00:00 2001 From: maksyuki Date: Sun, 9 Aug 2026 17:17:35 +0800 Subject: [PATCH] feat: add RNG support and update related configurations - Updated Makefile to include a check for the RNG metadata script and added a dependency for it. - Modified memory_map.json to change the user access level of APB_RNG to 'none'. - Updated clusterip filelist to include new RNG source files. - Adjusted generate_soc_topology.py to replace the reserved IRQ with the RNG IRQ. - Updated soc_topology.json to reflect the new RNG interrupt configuration. - Added RNG source files to software.mk for compilation. - Enhanced ip_apb_wrapper.sv to instantiate the RNG core and connect it to the APB interface. - Updated test_memory_map.py to ensure SOC_ADDR_IS_APB_RNG is not defined. - Modified test_script_tools.py to ensure dry runs do not write filelists. - Updated test_soc_topology.py to verify the new RNG IRQ and adjust the user IRQ mask. --- README.md | 6 +- app/README.md | 2 +- app/apps/ci_smoke/main.c | 29 +- app/apps/shell/main.c | 2 +- config/dependencies.lock.json | 2 +- crt/include/retrosoc/core/soc.h | 4 - crt/include/retrosoc/hal/rng.h | 24 +- crt/src/hal/rng.c | 115 +++- crt/src/service/booter.c | 3 +- docs/engineering.md | 12 +- docs/mini-soc-block-diagram.dot | 10 +- docs/mini-soc-block-diagram.svg | 510 +++++++++--------- rtl/mini/Makefile | 11 +- rtl/mini/address_map/memory_map.json | 2 +- rtl/mini/filelist/clusterip.fl | 3 + rtl/mini/integration/generate_soc_topology.py | 2 +- rtl/mini/integration/soc_topology.json | 2 +- rtl/mini/mk/software.mk | 4 + rtl/mini/top/ip_apb_wrapper.sv | 32 +- tests/test_memory_map.py | 4 + tests/test_script_tools.py | 10 +- tests/test_soc_topology.py | 5 +- 22 files changed, 510 insertions(+), 284 deletions(-) diff --git a/README.md b/README.md index 6613a3ca..ef165cab 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,9 @@ under the [Mulan Permissive Software License, Version 2](LICENSE). open-source CI coverage. - A memory-mapped peripheral subsystem with GPIO, UART, [dual general timers](docs/ip/timer.md), PWM, [dual I2C controllers](docs/ip/i2c.md), I2S, PS2, - WS2812, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, RNG, and CRC + WS2812, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, CRC, and a + management-only RNG V2 entropy controller. The current deterministic RNG integration source is + explicitly unqualified and intended only for diagnostics until a PDK-qualified entropy source is integrated. support. Available interfaces depend on the selected SoC configuration. - A standalone RISC-V runtime, HAL, board support, middleware, and `benchmark`, `bringup`, `coremark`, `debug`, and `shell` applications. @@ -74,7 +76,7 @@ user core. | [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | RV32IM | `bringup` | Compatibility profile for site-specific ICS55 runs. | CI Verilator firmware simulations explicitly select the `ci_smoke` -application, which checks UART, archinfo APB readback, and test-status +application, which checks UART, archinfo APB readback, RNG V2 fail-closed behavior, and test-status completion without the verbose startup report. ARCHINFO checks include its V2 ABI and the build/configuration identifiers generated for that variant. The profiles retain `bringup` as their default for manual diagnostics. To run the full report in Verilator, diff --git a/app/README.md b/app/README.md index 764f6157..2ce2eae0 100644 --- a/app/README.md +++ b/app/README.md @@ -29,7 +29,7 @@ The build selects an application with `APP=`. The supported profiles are: | --- | --- | | `benchmark` | Fixed-workload memory and DMA baseline with machine-readable wait counters and readback checksums. | | `bringup` | Manual startup diagnostic that prints complete application and archinfo details. | -| `ci_smoke` | Fast deterministic CI smoke test for UART, ARCHINFO V2 ABI/build identity, and test-status completion. | +| `ci_smoke` | Fast deterministic CI smoke test for UART, ARCHINFO V2 ABI/build identity, RNG V2 integration, and test-status completion. | | `coremark` | SRAM-resident Hazard3 CoreMark measurement; use the committed quick or standard profile. | | `debug` | Minimal SRAM image used only by the Hazard3 OpenOCD/GDB acceptance flow. | | `shell` | Interactive application that adds shell services, board drivers, media, FatFs, CoreMark, and UserIP integration. | diff --git a/app/apps/ci_smoke/main.c b/app/apps/ci_smoke/main.c index 39d06f9b..b81eed54 100644 --- a/app/apps/ci_smoke/main.c +++ b/app/apps/ci_smoke/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,28 @@ static bool rs_ci_smoke_archinfo_v2(void) { (rs_archinfo_read_device_id(device_id) == RS_ENOTSUP); } +static bool rs_ci_smoke_rng_v2(void) { + const rs_rng_config_t config = { + .fifo_watermark = 1U, + .interrupt_enable = 0U, + .lock_config = true, + }; + rs_rng_snapshot_t snapshot; + uint32_t first; + uint32_t second; + uint32_t entropy; + + if ((rs_rng_init(&config) != RS_OK) || + (rs_rng_read_diagnostic(&first, RS_TIMEOUT_DEFAULT) != RS_OK) || + (rs_rng_read_diagnostic(&second, RS_TIMEOUT_DEFAULT) != RS_OK) || (first == second) || + (rs_rng_get_status(&snapshot) != RS_OK) || snapshot.source_qualified || + snapshot.fatal_error) { + return false; + } + + return rs_rng_read_entropy(&entropy, RS_TIMEOUT_DEFAULT) == RS_ENOTSUP; +} + static bool rs_ci_smoke_clint_standard_map(void) { uint64_t first; uint64_t current; @@ -177,6 +200,10 @@ int main(void) { rs_test_finish(RS_TEST_FAILED, 1U); } printf("ci_smoke: archinfo passed\n"); + if (!rs_ci_smoke_rng_v2()) { + rs_test_finish(RS_TEST_FAILED, 8U); + } + printf("ci_smoke: RNG V2 passed\n"); if (!rs_ci_smoke_clint_standard_map()) { rs_test_finish(RS_TEST_FAILED, 2U); } @@ -193,7 +220,7 @@ int main(void) { rs_test_finish(RS_TEST_FAILED, 5U); } - printf("ci_smoke: UART, archinfo, CLINT, timer, and GPIO tests passed\n"); + printf("ci_smoke: UART, archinfo, RNG, CLINT, timer, and GPIO tests passed\n"); rs_test_finish(RS_TEST_PASSED, 0U); return 0; } diff --git a/app/apps/shell/main.c b/app/apps/shell/main.c index 4620ceb5..03073cf4 100644 --- a/app/apps/shell/main.c +++ b/app/apps/shell/main.c @@ -62,7 +62,7 @@ int main(void) { (void)rs_shell_register("pwm", "pwm test", true, ip_pwm_test); (void)rs_shell_register("rtc", "rtc test", true, ip_rtc_test); (void)rs_shell_register("wdg", "wdg test", true, ip_wdg_test); - (void)rs_shell_register("rng", "rng test", true, ip_rng_test); + (void)rs_shell_register("rng", "rng test", true, rs_rng_shell_test); (void)rs_shell_register("crc", "crc test", true, ip_crc_test); (void)rs_shell_register("ps2", "ps2 test", false, ip_ps2_test); (void)rs_shell_register("lcd", "lcd test", true, ip_lcd_test); diff --git a/config/dependencies.lock.json b/config/dependencies.lock.json index bf6008f6..2d77e356 100644 --- a/config/dependencies.lock.json +++ b/config/dependencies.lock.json @@ -69,7 +69,7 @@ "cluster_plic": {"url": "https://github.com/retroSoC/plic.git", "revision": "c851d93829d2e75b224003a058e718925855c0cc", "destination": "rtl/managed/clusterip/plic", "license": "NOASSERTION"}, "cluster_ps2": {"url": "https://github.com/retroSoC/ps2.git", "revision": "60921e0f72d6113f8615d03ce54567388fc2410f", "destination": "rtl/managed/clusterip/ps2", "license": "NOASSERTION"}, "cluster_pwm": {"url": "https://github.com/retroSoC/pwm.git", "revision": "c631ede87506d34f714167313ba69b196c0bea72", "destination": "rtl/managed/clusterip/pwm", "license": "NOASSERTION"}, - "cluster_rng": {"url": "https://github.com/retroSoC/rng.git", "revision": "7374e1e7f25bfd1ff9954ea99f19b77a583def29", "destination": "rtl/managed/clusterip/rng", "license": "NOASSERTION"}, + "cluster_rng": {"url": "https://github.com/retroSoC/rng.git", "revision": "36f3e0774d8f3c4b597d3db8a96ca3992532b61e", "destination": "rtl/managed/clusterip/rng", "license": "MulanPSL-2.0"}, "cluster_rtc": {"url": "https://github.com/retroSoC/rtc.git", "revision": "c6cc82f7530eea0b87ebe1d2cde2a67c9268c0db", "destination": "rtl/managed/clusterip/rtc", "license": "NOASSERTION"}, "cluster_spi": {"url": "https://github.com/retroSoC/spi.git", "revision": "515cb408806584525605b4747db5e890dbdf1928", "destination": "rtl/managed/clusterip/spi", "license": "NOASSERTION"}, "cluster_timer": {"url": "https://github.com/retroSoC/timer.git", "revision": "75fa45d786739e1d5ab6d1e10520be2c2f0d022a", "destination": "rtl/managed/clusterip/timer", "license": "NOASSERTION"}, diff --git a/crt/include/retrosoc/core/soc.h b/crt/include/retrosoc/core/soc.h index 7fdf3944..6217a362 100644 --- a/crt/include/retrosoc/core/soc.h +++ b/crt/include/retrosoc/core/soc.h @@ -183,10 +183,6 @@ #define reg_dvp_recven RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x00)) #define reg_dvp_rxdata RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x04)) #define reg_dvp_status RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x08)) -// rng -#define reg_rng_ctrl RS_SOC_REG32(RS_SOC_APB_RNG_BASE, UINT32_C(0x00)) -#define reg_rng_seed RS_SOC_REG32(RS_SOC_APB_RNG_BASE, UINT32_C(0x04)) -#define reg_rng_val RS_SOC_REG32(RS_SOC_APB_RNG_BASE, UINT32_C(0x08)) // uart #define reg_uart1_lcr RS_SOC_REG32(RS_SOC_APB_UART1_BASE, UINT32_C(0x00)) #define reg_uart1_div RS_SOC_REG32(RS_SOC_APB_UART1_BASE, UINT32_C(0x04)) diff --git a/crt/include/retrosoc/hal/rng.h b/crt/include/retrosoc/hal/rng.h index c3372428..edbf98e2 100644 --- a/crt/include/retrosoc/hal/rng.h +++ b/crt/include/retrosoc/hal/rng.h @@ -1,5 +1,27 @@ #ifndef RETROSOC_RNG_H #define RETROSOC_RNG_H -void ip_rng_test(int argc, char **argv); +#include +#include + +#include + +typedef rng_config_t rs_rng_config_t; +typedef rng_snapshot_t rs_rng_snapshot_t; + +#define RS_RNG_INTERRUPT_DATA_READY RNG_INTR_DATA_READY_MASK +#define RS_RNG_INTERRUPT_HEALTH_FAIL RNG_INTR_HEALTH_FAIL_MASK +#define RS_RNG_INTERRUPT_SOURCE_FAULT RNG_INTR_SOURCE_FAULT_MASK +#define RS_RNG_INTERRUPT_ALL RNG_INTR_ALL_MASK + +rs_status_t rs_rng_init(const rs_rng_config_t *config); +rs_status_t rs_rng_get_status(rs_rng_snapshot_t *snapshot); +rs_status_t rs_rng_read_entropy(uint32_t *word, rs_timeout_t timeout); +rs_status_t rs_rng_read_diagnostic(uint32_t *word, rs_timeout_t timeout); +rs_status_t rs_rng_recover(void); +rs_status_t rs_rng_interrupt_enable(uint32_t mask); +rs_status_t rs_rng_interrupt_clear(uint32_t mask); +rs_status_t rs_rng_interrupt_test(uint32_t mask); +void rs_rng_shell_test(int argc, char **argv); + #endif diff --git a/crt/src/hal/rng.c b/crt/src/hal/rng.c index 36371177..8df752a0 100644 --- a/crt/src/hal/rng.c +++ b/crt/src/hal/rng.c @@ -1,25 +1,110 @@ +#include #include #include -#include -void ip_rng_test(int argc, char **argv) { +static rs_status_t rs_rng_status(rng_status_t status) { + rs_status_t result; + + switch (status) { + case RNG_STATUS_OK: + result = RS_OK; + break; + case RNG_STATUS_INVALID_ARGUMENT: + result = RS_EINVAL; + break; + case RNG_STATUS_TIMEOUT: + result = RS_ETIMEOUT; + break; + case RNG_STATUS_UNAVAILABLE: + case RNG_STATUS_UNQUALIFIED: + result = RS_ENOTSUP; + break; + case RNG_STATUS_HEALTH_FAILURE: + result = RS_EIO; + break; + case RNG_STATUS_INCOMPATIBLE: + default: + result = RS_EFORMAT; + break; + } + + return result; +} + +rs_status_t rs_rng_init(const rs_rng_config_t *config) { + return rs_rng_status(rng_init((uintptr_t)RS_SOC_APB_RNG_BASE, config)); +} + +rs_status_t rs_rng_get_status(rs_rng_snapshot_t *snapshot) { + return rs_rng_status(rng_get_status((uintptr_t)RS_SOC_APB_RNG_BASE, snapshot)); +} + +rs_status_t rs_rng_read_entropy(uint32_t *word, rs_timeout_t timeout) { + return rs_rng_status(rng_read_entropy((uintptr_t)RS_SOC_APB_RNG_BASE, word, timeout)); +} + +rs_status_t rs_rng_read_diagnostic(uint32_t *word, rs_timeout_t timeout) { + return rs_rng_status(rng_read_diagnostic((uintptr_t)RS_SOC_APB_RNG_BASE, word, timeout)); +} + +rs_status_t rs_rng_recover(void) { + return rs_rng_status(rng_recover((uintptr_t)RS_SOC_APB_RNG_BASE)); +} + +rs_status_t rs_rng_interrupt_enable(uint32_t mask) { + return rs_rng_status(rng_interrupt_enable((uintptr_t)RS_SOC_APB_RNG_BASE, mask)); +} + +rs_status_t rs_rng_interrupt_clear(uint32_t mask) { + return rs_rng_status(rng_interrupt_clear((uintptr_t)RS_SOC_APB_RNG_BASE, mask)); +} + +rs_status_t rs_rng_interrupt_test(uint32_t mask) { + return rs_rng_status(rng_interrupt_test((uintptr_t)RS_SOC_APB_RNG_BASE, mask)); +} + +void rs_rng_shell_test(int argc, char **argv) { + const rs_rng_config_t config = { + .fifo_watermark = 1U, + .interrupt_enable = 0U, + .lock_config = true, + }; + rs_rng_snapshot_t snapshot; + uint32_t word; + rs_status_t status; + (void)argc; (void)argv; - printf("[APB IP] rng test\n"); - - reg_rng_ctrl = (uint32_t)1; // en the core - reg_rng_seed = (uint32_t)0xFE1C; // set the init seed - printf("[rng seed] %x\n", reg_rng_seed); - - for (int i = 0; i < 5; ++i) { - printf("[rng val] %x\n", reg_rng_val); + status = rs_rng_init(&config); + if (status != RS_OK) { + printf("[RNG] initialization failed: %d\n", status); + return; } - printf("reset the seed\n"); - reg_rng_seed = (uint32_t)0; - printf("[rng seed] %x\n", reg_rng_seed); - for (int i = 0; i < 5; ++i) { - printf("[rng val] %x\n", reg_rng_val); + printf("[APB IP] RNG V2 diagnostic source\n"); + for (uint32_t index = 0U; index < 5U; ++index) { + status = rs_rng_read_diagnostic(&word, RS_TIMEOUT_DEFAULT); + if (status != RS_OK) { + printf("[RNG] diagnostic read failed: %d\n", status); + return; + } + printf("[RNG diagnostic] %x\n", word); + } + + status = rs_rng_get_status(&snapshot); + if (status != RS_OK) { + printf("[RNG] status read failed: %d\n", status); + return; + } + printf("[RNG status] qualified=%u level=%u errors=%x accepted=%u discarded=%u\n", + snapshot.source_qualified ? 1U : 0U, (uint32_t)snapshot.fifo_level, + snapshot.error_status, snapshot.accepted_count, snapshot.discard_count); + + status = rs_rng_read_entropy(&word, RS_TIMEOUT_DEFAULT); + if (status == RS_ENOTSUP) { + printf("[RNG] security entropy unavailable: integration source is unqualified\n"); + } else { + printf("[RNG] unexpected entropy status: %d\n", status); } } diff --git a/crt/src/service/booter.c b/crt/src/service/booter.c index e8e7cee8..ebf26a60 100644 --- a/crt/src/service/booter.c +++ b/crt/src/service/booter.c @@ -118,7 +118,8 @@ void rs_app_info(void) { (void *)(uintptr_t)RS_SOC_RIBP_I2C1_BASE); printf(" 1 x ARCHINFO @%p\n", (void *)(uintptr_t)RS_SOC_APB_ARCHINFO_BASE); - printf(" 1 x RNG @%p\n", (void *)®_rng_ctrl); + printf(" 1 x RNG @%p\n", + (void *)(uintptr_t)RS_SOC_APB_RNG_BASE); printf(" 1 x UART1(ADV) @%p\n", (void *)®_uart1_lcr); printf(" 1 x PWM(4CHNL) @%p\n", (void *)®_pwm_ctrl); printf(" 1 x PS2 @%p\n", (void *)®_ps2_ctrl); diff --git a/docs/engineering.md b/docs/engineering.md index 5a66b124..ac2d202a 100644 --- a/docs/engineering.md +++ b/docs/engineering.md @@ -15,7 +15,7 @@ Regression Verilator firmware simulations override the profiles' manual `bringup` default with `APP=ci_smoke`. This application verifies UART output, -archinfo APB readback, and test-status completion within the CI time budget; +archinfo APB readback, RNG V2 integration, and test-status completion within the CI time budget; `bringup` retains the full automatic application-information report for manual runs. @@ -28,6 +28,16 @@ dependency lock, and canonical configuration digest. Normal builds clear the release flag; an audited release flow sets `BUILD_RELEASE=YES`, which is part of the canonical configuration digest. +RNG V2 is a management-only APB entropy-controller integration. Its register +specification, portable driver, standalone simulation, synthesis, formal +properties, security boundary, and delivery checklist are owned by the +[RNG IP repository](https://github.com/retroSoC/rng). The SoC currently feeds +it from an explicitly unqualified deterministic source for reproducible +bring-up and regression. Consequently `rs_rng_read_entropy()` fails closed +with `RS_ENOTSUP`; only the diagnostic API returns words. Production use +requires replacing that source with a PDK-qualified entropy macro and +completing the source-specific characterization and NIST SP 800-90B evidence. + OpenSTA runs a reproducible core-STA baseline for every CI PDK: IHP130 uses `slow_1p08V_125C`, GF180 uses `ss_125C_4v50`, ICS55 uses the H7CR `ss_1p08_125C` view, and SKY130 uses `ss_100C_1v40`. diff --git a/docs/mini-soc-block-diagram.dot b/docs/mini-soc-block-diagram.dot index fe96d527..07212001 100644 --- a/docs/mini-soc-block-diagram.dot +++ b/docs/mini-soc-block-diagram.dot @@ -152,12 +152,16 @@ digraph mini_soc_block_diagram { ]; apb_targets [ fillcolor="#E6F4EA", - label="APB target wrapper\nRNG, UART1, PWM, PS/2, RTC\nwatchdog, CRC, advanced timer and user IP" + label="APB target wrapper\nUART1, PWM, PS/2, RTC\nwatchdog, CRC, advanced timer and user IP" ]; archinfo [ fillcolor="#E6F4EA", label="ARCHINFO V2\nread-only build, topology and technology identity\nlifecycle-gated 128-bit device ID" ]; + rng [ + fillcolor="#E6F4EA", + label="RNG V2 entropy controller\n8-word FIFO, fail-closed monitoring, IRQ16\nmanagement-only, deterministic source unqualified" + ]; gpio_bridge [ fillcolor="#E5E7EB", label="GPIO pad bridge\nPDK capability-adapted controls" @@ -173,7 +177,7 @@ digraph mini_soc_block_diagram { { rank=same; user_core; dma; } { rank=same; fault; fabric; sram; } { rank=same; ribp_adapter; apb_adapter; } - { rank=same; sysctrl; clint; ribp_targets; uart0; i2c_controllers; gpio_controller; timers; ws2812; archinfo; apb_targets; } + { rank=same; sysctrl; clint; ribp_targets; uart0; i2c_controllers; gpio_controller; timers; ws2812; archinfo; rng; apb_targets; } { rank=same; gpio_bridge; irq; } ext_clock -> rcu [label="clock / reset"]; @@ -204,6 +208,7 @@ digraph mini_soc_block_diagram { ribp_adapter -> timers [label="RIBP"]; ribp_adapter -> ws2812 [label="RIBP"]; apb_adapter -> archinfo [label="APB"]; + apb_adapter -> rng [label="APB"]; apb_adapter -> apb_targets [label="APB"]; ribp_targets -> gpio_controller [label="alternate functions"]; @@ -219,6 +224,7 @@ digraph mini_soc_block_diagram { i2c_controllers -> gpio_controller [label="GPIO3/4 ALT1\nGPIO7/8 ALT0"]; dma -> i2c_controllers [label="DATA_CMD / RXDATA", style=dashed]; i2c_controllers -> irq [label="IRQ7 / IRQ19"]; + rng -> irq [label="IRQ16"]; apb_targets -> gpio_controller [label="user_gpio"]; ribp_targets -> ext_io [dir=both, label="device interfaces"]; uart0 -> ext_io [dir=both, label="UART pads"]; diff --git a/docs/mini-soc-block-diagram.svg b/docs/mini-soc-block-diagram.svg index e2b0ab9c..9939125d 100644 --- a/docs/mini-soc-block-diagram.svg +++ b/docs/mini-soc-block-diagram.svg @@ -4,19 +4,19 @@ - + mini_soc_block_diagram retroSoC Mini SoC Architecture cluster_asic - + retrosoc_asic cluster_soc - + retrosoc @@ -44,490 +44,512 @@ ext_io - -External I/O and memory -GPIO, UART0, XPI Flash, SDRAM, PSRAM -SD card, I2C, I2S, DVP and WS2812 + +External I/O and memory +GPIO, UART0, XPI Flash, SDRAM, PSRAM +SD card, I2C, I2S, DVP and WS2812 ext_jtag - -Management JTAG -TCK, TMS, TDI, TRST_n, TDO + +Management JTAG +TCK, TMS, TDI, TRST_n, TDO jtag_dtm - -Hazard3 JTAG DTM -10 MHz asynchronous TCK domain + +Hazard3 JTAG DTM +10 MHz asynchronous TCK domain ext_jtag->jtag_dtm - - -JTAG pads + + +JTAG pads fabric - -RIB fabric -3-master round-robin arbitration -INCR1 / INCR4, access policy, fault reporting + +RIB fabric +3-master round-robin arbitration +INCR1 / INCR4, access policy, fault reporting rcu->fabric - - -system clock / reset + + +system clock / reset clint - -CLINT -standard 64 KiB register map -mtime, mtimecmp and MSIP + +CLINT +standard 64 KiB register map +mtime, mtimecmp and MSIP rcu->clint - - -1 MHz tick + + +1 MHz tick mgmt_core - -Management core -Fixed Hazard3, branch predictor -JTAG Debug Module always present + +Management core +Fixed Hazard3, branch predictor +JTAG Debug Module always present mgmt_adapter - -RIBP2RIB + +RIBP2RIB mgmt_core->mgmt_adapter - - -RIBP + + +RIBP debug_module - -Hazard3 Debug Module -abstract commands, no SBA -management-hart-only reset + +Hazard3 Debug Module +abstract commands, no SBA +management-hart-only reset jtag_dtm->debug_module - - -DMI, asynchronous CDC + + +DMI, asynchronous CDC debug_module->mgmt_core - - -halt, resume, abstract commands + + +halt, resume, abstract commands debug_module->mgmt_adapter - - -reset after bridge idle + + +reset after bridge idle timers - -General timers 0/1 -32-bit counter, 16-bit prescaler -periodic / one-shot, compare, debug freeze + +General timers 0/1 +32-bit counter, 16-bit prescaler +periodic / one-shot, compare, debug freeze debug_module->timers - - -halted + + +halted mgmt_adapter->fabric - - -RIB + + +RIB user_core - -Selected user core -C0-C5, one active -PicoRV32 at C5 + +Selected user core +C0-C5, one active +PicoRV32 at C5 user_core->fabric - - -RIB + + +RIB dma - -DMA -RIB master and RIBP target + +DMA +RIB master and RIBP target dma->fabric - - -RIB + + +RIB uart0 - -UART0 V2 -64-byte TX/RX FIFOs, fractional baud -framing/errors, IRQ2, DMA-paced + +UART0 V2 +64-byte TX/RX FIFOs, fractional baud +framing/errors, IRQ2, DMA-paced - + dma->uart0 - - -TX/RX data + + +TX/RX data i2c_controllers - -I2C0 / I2C1 V2 -16-entry command/RX FIFOs, Sm/Fm/Fm+ -7/10-bit, IRQ7/19, DMA-paced + +I2C0 / I2C1 V2 +16-entry command/RX FIFOs, Sm/Fm/Fm+ +7/10-bit, IRQ7/19, DMA-paced - + dma->i2c_controllers - - -DATA_CMD / RXDATA + + +DATA_CMD / RXDATA ws2812 - -WS2812 TX -24-bit MSB-first serializer -16-word FIFO, IRQ17, DMA-fed + +WS2812 TX +24-bit MSB-first serializer +16-word FIFO, IRQ17, DMA-fed - + dma->ws2812 - - -TXDATA writes + + +TXDATA writes fault - -Error slave -access and protocol faults + +Error slave +access and protocol faults fabric->fault - - - -invalid / denied + + + +invalid / denied sram - -On-chip SRAM -optional RIB2RAM path + +On-chip SRAM +optional RIB2RAM path fabric->sram - - -RIB + + +RIB ribp_adapter - -RIB2RIBP + +RIB2RIBP fabric->ribp_adapter - - -RIB + + +RIB apb_adapter - -RIB2APB -direct APB bridge + +RIB2APB +direct APB bridge fabric->apb_adapter - - -RIB + + +RIB sysctrl - -SYSCTRL -PLL, user-core select/reset/bus enable -fault and performance control + +SYSCTRL +PLL, user-core select/reset/bus enable +fault and performance control ribp_adapter->sysctrl - - -RIBP + + +RIBP ribp_adapter->clint - - -RIBP + + +RIBP ribp_targets - -RIBP target wrapper -XPI/Flash, SDRAM, PSRAM, SPI-SD and DVP -I2S + +RIBP target wrapper +XPI/Flash, SDRAM, PSRAM, SPI-SD and DVP +I2S ribp_adapter->ribp_targets - - -RIBP + + +RIBP ribp_adapter->uart0 - - -RIBP + + +RIBP ribp_adapter->i2c_controllers - - -RIBP + + +RIBP gpio_controller - -GPIO V2 -user + management RIBP windows -atomic I/O, filter, locks, IRQ18 + +GPIO V2 +user + management RIBP windows +atomic I/O, filter, locks, IRQ18 ribp_adapter->gpio_controller - - -RIBP -user/admin + + +RIBP +user/admin ribp_adapter->timers - - -RIBP + + +RIBP ribp_adapter->ws2812 - - -RIBP + + +RIBP apb_targets - -APB target wrapper -RNG, UART1, PWM, PS/2, RTC -watchdog, CRC, advanced timer and user IP + +APB target wrapper +UART1, PWM, PS/2, RTC +watchdog, CRC, advanced timer and user IP - + apb_adapter->apb_targets - - -APB + + +APB archinfo - -ARCHINFO V2 -read-only build, topology and technology identity -lifecycle-gated 128-bit device ID + +ARCHINFO V2 +read-only build, topology and technology identity +lifecycle-gated 128-bit device ID apb_adapter->archinfo - - -APB + + +APB + + + +rng + +RNG V2 entropy controller +8-word FIFO, fail-closed monitoring, IRQ16 +management-only, deterministic source unqualified + + + +apb_adapter->rng + + +APB - + irq - -Interrupt aggregation -RIBP and APB target IRQs to management core + +Interrupt aggregation +RIBP and APB target IRQs to management core - + clint->irq - - -machine IRQ0 / IRQ1 + + +machine IRQ0 / IRQ1 - + ribp_targets->ext_io - - - -device interfaces + + + +device interfaces - + ribp_targets->gpio_controller - - -alternate functions + + +alternate functions - + uart0->ext_io - - - -UART pads + + + +UART pads - + uart0->irq - - -IRQ2 + + +IRQ2 - + i2c_controllers->gpio_controller - - -GPIO3/4 ALT1 -GPIO7/8 ALT0 + + +GPIO3/4 ALT1 +GPIO7/8 ALT0 - + i2c_controllers->irq - - -IRQ7 / IRQ19 + + +IRQ7 / IRQ19 - + gpio_bridge - -GPIO pad bridge -PDK capability-adapted controls + +GPIO pad bridge +PDK capability-adapted controls - + gpio_controller->gpio_bridge - - -pad control + + +pad control - + gpio_controller->irq - - -IRQ18 + + +IRQ18 - + timers->irq - - -IRQ3 / IRQ4 + + +IRQ3 / IRQ4 - + ws2812->gpio_bridge - - -GPIO2 ALT1 + + +GPIO2 ALT1 - + ws2812->irq - - -IRQ17 + + +IRQ17 - + apb_targets->gpio_controller - - -user_gpio + + +user_gpio + + + +rng->irq + + +IRQ16 - + gpio_bridge->ext_io - - - -pad control + + + +pad control diff --git a/rtl/mini/Makefile b/rtl/mini/Makefile index d60af566..0806f2ac 100644 --- a/rtl/mini/Makefile +++ b/rtl/mini/Makefile @@ -23,6 +23,7 @@ USER_EXTENSIONS_DIR := $(VARIANT_ROOT)/generated/user_extensions USER_EXTENSIONS_STAMP := $(USER_EXTENSIONS_DIR)/.stamp USER_EXTENSIONS_FILELIST := $(USER_EXTENSIONS_DIR)/user_extensions.fl ARCHINFO_METADATA_SCRIPT := $(ROOT_PATH)/rtl/managed/clusterip/archinfo/scripts/generate_metadata.py +ARCHINFO_METADATA_DEPS := $(wildcard $(ARCHINFO_METADATA_SCRIPT)) ARCHINFO_METADATA_DIR := $(VARIANT_ROOT)/generated/archinfo ARCHINFO_METADATA_STAMP := $(ARCHINFO_METADATA_DIR)/.stamp ARCHINFO_METADATA_SV := $(ARCHINFO_METADATA_DIR)/archinfo_integration_metadata.svh @@ -101,7 +102,13 @@ user-extensions: $(USER_EXTENSIONS_STAMP) check-user-extensions: $(FLOW_PYTHON) $(USER_EXTENSIONS_SCRIPT) --map $(USER_EXTENSIONS_SOURCE) --check -$(ARCHINFO_METADATA_STAMP): $(ARCHINFO_METADATA_SCRIPT) $(LOCK_FILE) +check-archinfo-source: + @test -f $(ARCHINFO_METADATA_SCRIPT) || { \ + echo "missing $(ARCHINFO_METADATA_SCRIPT); run 'make setup-clusterip' first" >&2; \ + exit 1; \ + } + +$(ARCHINFO_METADATA_STAMP): $(ARCHINFO_METADATA_DEPS) $(LOCK_FILE) | check-archinfo-source $(FLOW_PYTHON) $(ARCHINFO_METADATA_SCRIPT) --repo-root $(ROOT_PATH) --lock $(LOCK_FILE) \ --config-digest $(CONFIG_DIGEST) $(if $(filter YES,$(BUILD_RELEASE)),--release) \ --output-sv $(ARCHINFO_METADATA_SV) --output-c $(ARCHINFO_METADATA_C) @@ -173,4 +180,4 @@ endif .PHONY: gen_mpw_code generate_filelist memory-map check-memory-map pin-map check-pin-map \ soc-topology check-soc-topology user-extensions check-user-extensions \ - archinfo-metadata check-clock-reset-domains firmware \ No newline at end of file + archinfo-metadata check-archinfo-source check-clock-reset-domains firmware \ No newline at end of file diff --git a/rtl/mini/address_map/memory_map.json b/rtl/mini/address_map/memory_map.json index 53d06ac6..937cef36 100644 --- a/rtl/mini/address_map/memory_map.json +++ b/rtl/mini/address_map/memory_map.json @@ -57,7 +57,7 @@ {"symbol": "RIBP_APU", "base": "0x10013000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"}, {"symbol": "RIBP_GPIO_ADMIN", "base": "0x10014000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"}, {"symbol": "APB_ARCHINFO", "base": "0x20000000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "ro"}, - {"symbol": "APB_RNG", "base": "0x20001000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"}, + {"symbol": "APB_RNG", "base": "0x20001000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "none"}, {"symbol": "APB_UART1", "base": "0x20002000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"}, {"symbol": "APB_PWM", "base": "0x20003000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"}, {"symbol": "APB_PS2", "base": "0x20004000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"}, diff --git a/rtl/mini/filelist/clusterip.fl b/rtl/mini/filelist/clusterip.fl index 1771e7d5..dad8f5ec 100644 --- a/rtl/mini/filelist/clusterip.fl +++ b/rtl/mini/filelist/clusterip.fl @@ -1,5 +1,8 @@ /clusterip/archinfo/rtl/archinfo_reg.sv /clusterip/archinfo/rtl/apb4_archinfo.sv +/clusterip/rng/rtl/rng_core.sv +/clusterip/rng/rtl/rng_reg.sv +/clusterip/rng/rtl/rng_deterministic_source.sv /clusterip/rng/rtl/apb4_rng.sv /clusterip/uart/rtl/uart_if.sv /clusterip/uart/rtl/uart_tx.sv diff --git a/rtl/mini/integration/generate_soc_topology.py b/rtl/mini/integration/generate_soc_topology.py index 1d75dc48..9e962f58 100644 --- a/rtl/mini/integration/generate_soc_topology.py +++ b/rtl/mini/integration/generate_soc_topology.py @@ -43,7 +43,7 @@ COMPATIBILITY_IRQ_BINDINGS = ( ("rtc", "apb", 3, 13, "u_rtc_if.irq_o"), ("watchdog_reset", "apb", 4, 14, "u_wdg_if.rst_o"), ("advanced_timer", "apb", 5, 15, "u_tmr_if.irq_o"), - ("reserved", "apb", 6, 16, "1'b0"), + ("rng", "apb", 6, 16, "s_rng_irq"), ("ws2812", "ribp", 10, 17, "ws2812.irq_o"), ("gpio", "ribp", 11, 18, "gpio.irq_o"), ("i2c1", "ribp", 12, 19, "i2c1.irq_o"), diff --git a/rtl/mini/integration/soc_topology.json b/rtl/mini/integration/soc_topology.json index eae0bffd..31389ca4 100644 --- a/rtl/mini/integration/soc_topology.json +++ b/rtl/mini/integration/soc_topology.json @@ -23,7 +23,7 @@ {"name": "rtc", "description": "APB RTC interrupt", "group": "apb", "group_bit": 3, "core_bit": 13, "signal": "u_rtc_if.irq_o"}, {"name": "watchdog_reset", "description": "APB watchdog reset request", "group": "apb", "group_bit": 4, "core_bit": 14, "signal": "u_wdg_if.rst_o"}, {"name": "advanced_timer", "description": "APB advanced timer interrupt", "group": "apb", "group_bit": 5, "core_bit": 15, "signal": "u_tmr_if.irq_o"}, - {"name": "reserved", "description": "Reserved interrupt slot", "group": "apb", "group_bit": 6, "core_bit": 16, "signal": "1'b0"}, + {"name": "rng", "description": "APB RNG data/error interrupt", "group": "apb", "group_bit": 6, "core_bit": 16, "signal": "s_rng_irq", "user_visible": false}, {"name": "ws2812", "description": "WS2812 transmitter interrupt", "group": "ribp", "group_bit": 10, "core_bit": 17, "signal": "ws2812.irq_o"}, {"name": "gpio", "description": "RIBP GPIO combined interrupt", "group": "ribp", "group_bit": 11, "core_bit": 18, "signal": "gpio.irq_o"}, {"name": "i2c1", "description": "RIBP I2C1 interrupt", "group": "ribp", "group_bit": 12, "core_bit": 19, "signal": "i2c1.irq_o"} diff --git a/rtl/mini/mk/software.mk b/rtl/mini/mk/software.mk index c45b54ac..0972bd69 100644 --- a/rtl/mini/mk/software.mk +++ b/rtl/mini/mk/software.mk @@ -62,6 +62,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \ $(ROOT_PATH)/crt/src/lib/console.c \ $(ROOT_PATH)/crt/src/lib/printf.c \ $(ROOT_PATH)/rtl/managed/clusterip/archinfo/sw/src/archinfo.c \ + $(ROOT_PATH)/rtl/managed/clusterip/rng/sw/src/rng.c \ $(ROOT_PATH)/crt/src/core/archinfo.c \ $(ROOT_PATH)/crt/src/service/bench.c \ $(ROOT_PATH)/crt/src/service/booter.c \ @@ -129,6 +130,7 @@ INC_PATH := -I$(SW_BUILD_DIR)/include \ -I$(USER_EXTENSIONS_DIR)/include \ -I$(ARCHINFO_METADATA_DIR) \ -I$(ROOT_PATH)/rtl/managed/clusterip/archinfo/sw/include \ + -I$(ROOT_PATH)/rtl/managed/clusterip/rng/sw/include \ -I$(ROOT_PATH)/crt/include \ $(addprefix -I,$(APP_INC_DIRS)) SRC_PATH := $(CRT_SRCS) $(APP_SRCS) @@ -141,6 +143,8 @@ SW_HEADERS := $(shell find $(ROOT_PATH)/crt/include $(ROOT_PATH)/app -typ \( -name '*.h' -o -name '*.hpp' \) 2>/dev/null) SW_HEADERS += $(shell find $(ROOT_PATH)/rtl/managed/clusterip/archinfo/sw/include \ -type f -name '*.h' 2>/dev/null) +SW_HEADERS += $(shell find $(ROOT_PATH)/rtl/managed/clusterip/rng/sw/include \ + -type f -name '*.h' 2>/dev/null) $(VERSION_HEADER): FORCE_VERSION $(ROOT_PATH)/crt/ver.py $(ROOT_PATH)/crt/ver.tmpl @mkdir -p $(dir $@) diff --git a/rtl/mini/top/ip_apb_wrapper.sv b/rtl/mini/top/ip_apb_wrapper.sv index d5901079..c7a85aab 100644 --- a/rtl/mini/top/ip_apb_wrapper.sv +++ b/rtl/mini/top/ip_apb_wrapper.sv @@ -63,6 +63,14 @@ module ip_apb_wrapper ( 32'h0000_FFF8 | {31'd0, ARCHINFO_HAVE_PLL} | ({31'd0, ARCHINFO_HAVE_SRAM_IF} << 1) | ({31'd0, ARCHINFO_HAVE_SRAM_MACRO} << 2); + logic s_rng_entropy_enable; + logic s_rng_entropy_ready; + logic s_rng_entropy_valid; + logic [31:0] s_rng_entropy_data; + logic s_rng_entropy_qualified; + logic s_rng_entropy_fault; + logic s_rng_irq; + `ifdef PDK_IHP130 localparam logic [31:0] ARCHINFO_TECHNOLOGY = 32'h0201_0082; `elsif PDK_GF180 @@ -110,7 +118,29 @@ module ip_apb_wrapper ( ); // verilog_format: on - apb4_rng u_apb4_rng (.apb4(u_rng_apb_if)); + rng_deterministic_source u_rng_deterministic_source ( + .clk_i (clk_i), + .rst_n_i (rst_n_i), + .enable_i (s_rng_entropy_enable), + .ready_i (s_rng_entropy_ready), + .valid_o (s_rng_entropy_valid), + .data_o (s_rng_entropy_data), + .qualified_o(s_rng_entropy_qualified), + .fault_o (s_rng_entropy_fault) + ); + + apb4_rng #( + .FIFO_DEPTH(8) + ) u_apb4_rng ( + .entropy_enable_o (s_rng_entropy_enable), + .entropy_ready_o (s_rng_entropy_ready), + .entropy_valid_i (s_rng_entropy_valid), + .entropy_data_i (s_rng_entropy_data), + .entropy_qualified_i(s_rng_entropy_qualified), + .entropy_fault_i (s_rng_entropy_fault), + .irq_o (s_rng_irq), + .apb4 (u_rng_apb_if) + ); apb4_uart #( .FIFO_DEPTH(32) diff --git a/tests/test_memory_map.py b/tests/test_memory_map.py index 5c1a0754..c8eda6e0 100644 --- a/tests/test_memory_map.py +++ b/tests/test_memory_map.py @@ -69,6 +69,10 @@ def test_generated_artifacts_share_the_capacity_baseline(tmp_path: Path) -> None assert "SOC_SYSCTRL_TEST_STATUS_OFFSET 32'h00000084" in rtl assert "SOC_ADDR_IS_RIBP(addr)" in rtl assert "SOC_ADDR_IS_NMI" not in rtl + user_policy = rtl.split("`define SOC_USER_ADDR_READABLE", 1)[1].split( + "`define SOC_ADDR_INCR4_CAPABLE", 1 + )[0] + assert "SOC_ADDR_IS_APB_RNG" not in user_policy assert "RS_SOC_SYSCTRL_PLL_CFG_OFFSET UINT32_C(0x00000008)" in header assert "RS_SOC_SYSCTRL_PLL_STATUS_OFFSET UINT32_C(0x0000001C)" in header assert "RS_SOC_SYSCTRL_TEST_STATUS_OFFSET UINT32_C(0x00000084)" in header diff --git a/tests/test_script_tools.py b/tests/test_script_tools.py index b06174ab..a305d481 100644 --- a/tests/test_script_tools.py +++ b/tests/test_script_tools.py @@ -505,7 +505,7 @@ def test_dependency_helper_limits_recursive_submodules(monkeypatch, tmp_path: Pa ) -def test_make_dry_run_and_validation_do_not_write_filelists() -> None: +def test_make_dry_run_and_validation_do_not_write_filelists(tmp_path: Path) -> None: def build_state() -> dict[str, tuple[int, int]]: build = ROOT / "build" if not build.exists(): @@ -518,7 +518,13 @@ def test_make_dry_run_and_validation_do_not_write_filelists() -> None: before = build_state() run("make", "-n", "help") - run("make", "-n", "SIMU=IVERILOG", "comp") + run( + "make", + "-n", + f"ARCHINFO_METADATA_SCRIPT={tmp_path / 'missing-generate-metadata.py'}", + "SIMU=IVERILOG", + "comp", + ) run( "make", "-n", diff --git a/tests/test_soc_topology.py b/tests/test_soc_topology.py index 7ea2f737..f10fba06 100644 --- a/tests/test_soc_topology.py +++ b/tests/test_soc_topology.py @@ -97,7 +97,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) - assert ".apb_rib(u_apb_rib_if)" in bus_fabric assert ".rib(u_rib_if)" in bus_fabric assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config - assert "`define SOC_USER_IRQ_MASK 32'h000FFFFC" in irq_config + assert "`define SOC_USER_IRQ_MASK 32'h000EFFFC" in irq_config assert "`define SOC_IRQ_RIBP_WIDTH 13" in irq_config assert "`define SOC_IRQ_APB_WIDTH 7" in irq_config assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq @@ -105,6 +105,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) - assert "assign irq_o[11] = gpio.irq_o;" in rib_irq assert "assign irq_o[12] = i2c1.irq_o;" in rib_irq assert "assign irq_o[5] = u_tmr_if.irq_o;" in apb_irq + assert "assign irq_o[6] = s_rng_irq;" in apb_irq assert "s_irq[16] = s_apb_irq[6];" in irq_wiring assert "irq_i[31] == 1'b0" in irq_sva assert "bind retrosoc soc_irq_topology_sva" in irq_sva @@ -141,7 +142,7 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None: ("rtc", "apb", 3, 13, "u_rtc_if.irq_o"), ("watchdog_reset", "apb", 4, 14, "u_wdg_if.rst_o"), ("advanced_timer", "apb", 5, 15, "u_tmr_if.irq_o"), - ("reserved", "apb", 6, 16, "1'b0"), + ("rng", "apb", 6, 16, "s_rng_irq"), ("ws2812", "ribp", 10, 17, "ws2812.irq_o"), ("gpio", "ribp", 11, 18, "gpio.irq_o"), ("i2c1", "ribp", 12, 19, "i2c1.irq_o"),