Merge branch 'feat/sw' into dev

# Conflicts:
#	Makefile
#	README.md
#	app/README.md
#	app/apps/hp_boot/main.c
#	configs/README.md
#	dependencies/dependencies.lock.json
#	publications/datasheets/sections/architecture.typ
#	publications/datasheets/sections/boot-bundle-format.typ
#	publications/datasheets/sections/linux-runtime.typ
#	publications/datasheets/sections/overview.typ
#	publications/datasheets/system-reference.json
#	publications/software_reference.py
#	scripts/build_hp_smoke.py
#	scripts/run_flow.py
This commit is contained in:
maksyuki committed 2026-09-26 16:28:39 +08:00
commit 50b7c47916
81 files changed
+2423 -974

No files matched your search

+7
View File
@@ -1,5 +1,12 @@
# Third-party attribution
The optional HP RT-Thread kernel is official RT-Thread v5.3.0, commit
`99428a1e7f7447955aa860f7c969273a12095b8f`, from
[RT-Thread/rt-thread](https://github.com/RT-Thread/rt-thread). It is licensed
under Apache-2.0. Its original copyright/license files remain in the locked
managed checkout; only the retroSoC BSP is repository-owned. Redistribution of
built RT-Thread images must retain the applicable upstream notices.
This repository contains RTL source files that retain copyright and attribution information from third-party open-source projects in their original file headers. The following projects are explicitly referenced in the RTL sources currently present in this repository.
## 1. ETH Zurich and University of Bologna
+53 -26
View File
@@ -45,7 +45,7 @@ PDK_BEHAV ?= NO
HAVE_SVA ?= NO
APU_ENABLE_P7 ?= NO
HAVE_HP ?= YES
HP_CONFIG ?= rv32imafdc_zicbom_max
HP_CONFIG ?= rv64imafdc_zicbom_max
BUILD_RELEASE ?= NO
JTAG_IDCODE ?= DEADBEEF
EXT_CLK_HZ ?= 72000000
@@ -80,6 +80,7 @@ NPU_P5_ACCEPTANCE ?= NO
NPU_P6_ACCEPTANCE ?= NO
NPU_P6_WORKLOAD ?= kws
HP_PERF_MIN_RATIO ?= 2.5
HP_CROSS ?= $(shell $(PYTHON) $(ROOT_PATH)/scripts/hp_tools.py --root $(ROOT_PATH))
LP_COREMARK_REPORT ?=
HP_COREMARK_REPORT ?=
@@ -178,7 +179,7 @@ HP_BOOT_BUNDLE_NAME ?= retrosoc_hp_linux
HP_BOOT_BUNDLE_BIN := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).bin
HP_BOOT_BUNDLE_HEX := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).hex
HP_BOOT_BUNDLE_MANIFEST := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).json
HP_LINUX_SIM_TIME ?= 7200
HP_LINUX_SIM_TIME ?= 0
HP_SMOKE_SIM_TIME ?= 300
HP_SMOKE_BUILD_DIR := $(VARIANT_ROOT)/hp-smoke
HP_SMOKE_STAMP := $(HP_SMOKE_BUILD_DIR)/images/.stamp
@@ -192,6 +193,11 @@ HP_APU_BUNDLE_NAME ?= retrosoc_hp_apu
HP_APU_BUNDLE_BIN := $(SW_BUILD_DIR)/$(HP_APU_BUNDLE_NAME).bin
HP_APU_BUNDLE_HEX := $(SW_BUILD_DIR)/$(HP_APU_BUNDLE_NAME).hex
HP_APU_MANIFEST := $(SW_BUILD_DIR)/$(HP_APU_BUNDLE_NAME).json
HP_RTTHREAD_BUILD_DIR := $(VARIANT_ROOT)/hp-rtthread
HP_RTTHREAD_STAMP := $(HP_RTTHREAD_BUILD_DIR)/images/.stamp
HP_RTTHREAD_SIM_TIME ?= 1800
HP_RTTHREAD_BUNDLE_NAME ?= retrosoc_hp_rtthread
HP_RTTHREAD_BUNDLE_BIN := $(SW_BUILD_DIR)/$(HP_RTTHREAD_BUNDLE_NAME).bin
HP_BUILDRT_ROOT := $(ROOT_PATH)/.cache/retrosoc/sources/buildroot-hp
HP_LINUX_ROOT := $(ROOT_PATH)/.cache/retrosoc/sources/linux-hp
HP_OPENSBI_ROOT := $(ROOT_PATH)/.cache/retrosoc/sources/opensbi-hp
@@ -220,7 +226,7 @@ VALID_SYNTH_RECIPE := balanced area speed
VALID_STA := NONE OPENSTA
VALID_PDK := ICS55 IHP130 SKY130 GF180
VALID_BOOL := YES NO
VALID_HP_CONFIG := rv32imafdc_zicbom_max
VALID_HP_CONFIG := rv64imafdc_zicbom_max
VALID_ISA := RV32E RV32I RV32IM
VALID_APP := benchmark bringup ci_smoke coremark debug hp_boot shell xpi_flash_loader apu_release
VALID_LINK_TYPE := xip jtag_sram ld2_all_sram ld2_sram ld2_psram ld2_sdram
@@ -539,12 +545,14 @@ help:
' npu-p6-qualify execute all required P6 qualification gates' \
' setup-regression install pinned dependencies for all PR PDK profiles' \
' setup-hp-linux install pinned Buildroot, Linux, and OpenSBI sources' \
' hp-linux build the pinned RV32 HP Linux image set' \
' hp-linux build the pinned RV64 HP Linux image set' \
' hp-bundle package LP firmware and HP Linux images for flash' \
' hp-linux-sim run the fast-flash HP Linux userspace acceptance test' \
' hp-smoke-sim run LP release, HP MMIO, and mailbox RTL smoke test' \
' hp-apu-bundle package the APU release LP firmware and HP payload' \
' hp-apu-sim run the LP/HP APU ownership evidence simulation' \
' setup-hp-rtthread install locked RT-Thread, RV64 compiler and SCons' \
' hp-rtthread-sim run RV64 RT-Thread kernel/platform acceptance' \
' doctor check tools, paths, and selected configuration' \
' config | manifest print/write the effective configuration' \
' memory-map generate the selected address-map artifacts' \
@@ -860,7 +868,10 @@ apu-p5-corpus: setup-apu-reference $(APU_P5_BUNDLE)
setup-hp-linux:
python3 $(ROOT_PATH)/scripts/setup_hp_linux.py
$(HP_LINUX_STAMP): $(ROOT_PATH)/scripts/build_hp_linux.py \
setup-hp-rtthread:
python3 $(ROOT_PATH)/scripts/setup_hp_rtthread.py
$(HP_LINUX_STAMP): $(ROOT_PATH)/scripts/build_hp_linux.py $(ROOT_PATH)/scripts/hp_tools.py \
$(ROOT_PATH)/app/ports/linux/configs/retrosoc_hp_defconfig \
$(ROOT_PATH)/app/ports/linux/busybox/retrosoc_hp.config \
$(ROOT_PATH)/app/ports/linux/linux/retrosoc_hp.config \
@@ -869,7 +880,7 @@ $(HP_LINUX_STAMP): $(ROOT_PATH)/scripts/build_hp_linux.py \
$(ROOT_PATH)/app/ports/linux/opensbi/retrosoc_hp/configs/defconfig \
$(ROOT_PATH)/app/ports/linux/opensbi/retrosoc_hp/objects.mk \
$(ROOT_PATH)/app/ports/linux/opensbi/retrosoc_hp/platform.c \
$(ROOT_PATH)/app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp
$(ROOT_PATH)/app/ports/linux/init $(ROOT_PATH)/app/ports/linux/hp_ready.c
@test '$(HAVE_HP)' = YES
python3 $(ROOT_PATH)/scripts/build_hp_linux.py --root $(ROOT_PATH) \
--buildroot $(HP_BUILDRT_ROOT) --linux $(HP_LINUX_ROOT) --opensbi $(HP_OPENSBI_ROOT) \
@@ -892,15 +903,9 @@ hp-bundle: $(HP_BOOT_BUNDLE_BIN) $(HP_BOOT_BUNDLE_HEX)
hp-linux-sim: hp-bundle comp
@test '$(SIMU)' = VERILATOR
$(MAKE) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) SIM_FIRMWARE_NAME=$(HP_BOOT_BUNDLE_NAME) \
SOC_SIM_TIME=$(HP_LINUX_SIM_TIME) VERILATOR_SIM_ARGS=--fast-flash sim
python3 $(ROOT_PATH)/scripts/check_simulation.py \
--log $(SIM_BUILD_ROOT)/sim.log \
--result $(SIM_BUILD_ROOT)/result-hp-linux-sim-check.json \
--require 'VERILATOR_FAST_FLASH=enabled' \
--require 'retroSoC HP Linux ready' \
--require 'HP_LINUX_READY' \
--require 'SIM_TEST_PASS code=0'
python3 $(ROOT_PATH)/scripts/run_hp_sim.py --emulator $(VERILATOR_EMU) \
--image $(HP_BOOT_BUNDLE_BIN) --output $(SIM_BUILD_ROOT)/hp-linux \
--workload linux --timeout $(HP_LINUX_SIM_TIME)
HP_SMOKE_NPU_DEPS :=
HP_SMOKE_NPU_ARGS :=
@@ -938,13 +943,14 @@ HP_SMOKE_NPU_ARGS += --define=-DRS_NPU_P6_ACCEPTANCE \
endif
$(HP_SMOKE_STAMP): $(ROOT_PATH)/scripts/build_hp_smoke.py \
$(ROOT_PATH)/scripts/hp_tools.py \
$(ROOT_PATH)/app/ports/linux/smoke/start.S \
$(ROOT_PATH)/app/ports/linux/smoke/linker.ld $(HP_SMOKE_NPU_DEPS) \
$(MEMORY_MAP_STAMP) $(USER_EXTENSIONS_STAMP) $(SOC_TOPOLOGY_STAMP)
python3 $(ROOT_PATH)/scripts/build_hp_smoke.py \
--source $(ROOT_PATH)/app/ports/linux/smoke/start.S \
--linker $(ROOT_PATH)/app/ports/linux/smoke/linker.ld \
--output $(HP_SMOKE_BUILD_DIR) --cross $(CROSS) $(HP_SMOKE_NPU_ARGS)
--output $(HP_SMOKE_BUILD_DIR) --cross $(HP_CROSS) $(HP_SMOKE_NPU_ARGS)
@touch $@
$(HP_SMOKE_BUNDLE_BIN): $(FIRMWARE_ELF) $(HP_SMOKE_STAMP) \
@@ -952,24 +958,45 @@ $(HP_SMOKE_BUNDLE_BIN): $(FIRMWARE_ELF) $(HP_SMOKE_STAMP) \
python3 $(ROOT_PATH)/scripts/package_hp_boot.py \
--firmware $(SW_BUILD_DIR)/$(FIRMWARE_NAME).bin \
--images $(HP_SMOKE_BUILD_DIR)/images --output $@ \
--manifest $(HP_SMOKE_MANIFEST)
--manifest $(HP_SMOKE_MANIFEST) --workload smoke
$(HP_SMOKE_BUNDLE_HEX): $(HP_SMOKE_BUNDLE_BIN)
$(OBJC) -I binary -O verilog $< $@
hp-smoke-bundle: $(HP_SMOKE_BUNDLE_BIN) $(HP_SMOKE_BUNDLE_HEX)
$(HP_RTTHREAD_STAMP): $(wildcard $(ROOT_PATH)/app/ports/rtthread/*) \
$(ROOT_PATH)/scripts/build_hp_rtthread.py $(ROOT_PATH)/scripts/hp_tools.py \
$(ROOT_PATH)/app/apps/hp_boot/hp_boot_bundle.h $(ROOT_PATH)/requirements/rtthread.txt $(LOCK_FILE)
@test '$(HAVE_HP)' = YES
python3 $(ROOT_PATH)/scripts/build_hp_rtthread.py --root $(ROOT_PATH) \
--output $(HP_RTTHREAD_BUILD_DIR) --jobs $(JOBS)
@touch $@
hp-rtthread: $(HP_RTTHREAD_STAMP)
$(HP_RTTHREAD_BUNDLE_BIN): $(FIRMWARE_ELF) $(HP_RTTHREAD_STAMP) \
$(ROOT_PATH)/scripts/package_hp_boot.py
python3 $(ROOT_PATH)/scripts/package_hp_boot.py \
--firmware $(SW_BUILD_DIR)/$(FIRMWARE_NAME).bin \
--images $(HP_RTTHREAD_BUILD_DIR)/images --output $@ \
--manifest $(SW_BUILD_DIR)/$(HP_RTTHREAD_BUNDLE_NAME).json --workload rtthread
hp-rtthread-bundle: $(HP_RTTHREAD_BUNDLE_BIN)
hp-rtthread-sim: hp-rtthread-bundle comp
@test '$(SIMU)' = VERILATOR
python3 $(ROOT_PATH)/scripts/run_hp_sim.py --emulator $(VERILATOR_EMU) \
--image $(HP_RTTHREAD_BUNDLE_BIN) --output $(SIM_BUILD_ROOT)/hp-rtthread \
--workload rtthread --timeout $(HP_RTTHREAD_SIM_TIME)
.PHONY: setup-hp-rtthread hp-rtthread hp-rtthread-bundle hp-rtthread-sim
hp-smoke-sim: hp-smoke-bundle comp
@test '$(SIMU)' = VERILATOR
$(MAKE) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) SIM_FIRMWARE_NAME=$(HP_SMOKE_BUNDLE_NAME) \
SOC_SIM_TIME=$(HP_SMOKE_SIM_TIME) VERILATOR_SIM_ARGS=--fast-flash sim
python3 $(ROOT_PATH)/scripts/check_simulation.py \
--log $(SIM_BUILD_ROOT)/sim.log \
--result $(SIM_BUILD_ROOT)/result-hp-smoke-sim-check.json \
--require 'SIM_TEST_PASS code=0' \
--require 'HP_LINUX_READY' \
--require 'HP_GA2D_PASS' \
--require 'HP_GA2D_CACHE_CLEAN'
python3 $(ROOT_PATH)/scripts/run_hp_sim.py --emulator $(VERILATOR_EMU) \
--image $(HP_SMOKE_BUNDLE_BIN) --output $(SIM_BUILD_ROOT)/hp-smoke \
--workload smoke --timeout $(HP_SMOKE_SIM_TIME)
$(HP_APU_STAMP): $(ROOT_PATH)/scripts/build_hp_apu.py \
$(ROOT_PATH)/app/ports/hp-apu/start.S \
$(ROOT_PATH)/app/ports/hp-apu/main.c \
+265 -172
View File
@@ -1,228 +1,321 @@
# retroSoC
An open-source RISC-V SoC platform, from SystemVerilog RTL and firmware to reproducible verification and release artifacts.
[![License](https://img.shields.io/badge/License-Mulan%20PSL%20v2-d4a72c?style=flat-square&labelColor=3b301a&logo=github&logoColor=f6d365)](LICENSE)
[![RTL](https://img.shields.io/badge/RTL-SystemVerilog-d4a72c?style=flat-square&labelColor=3b301a&logo=devbox&logoColor=f6d365)](rtl)
[![ISA](https://img.shields.io/badge/ISA-RV32IMAC+RV32GC-d4a72c?style=flat-square&labelColor=3b301a&logo=riscv&logoColor=f6d365)](configs/ci/ihp130.mk)
[![ISA](https://img.shields.io/badge/ISA-RV32IM-d4a72c?style=flat-square&labelColor=3b301a&logo=riscv&logoColor=f6d365)](configs/ci/ihp130.mk)
[![RISC-V GCC](https://img.shields.io/badge/RISC--V%20GCC-2025.05.01-d4a72c?style=flat-square&labelColor=3b301a&logo=c&logoColor=f6d365)](dependencies/dependencies.lock.json)<br>
[![IHP130 regression](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/regression-ihp130.yml?branch=main&style=flat-square&label=IHP130&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/regression-ihp130.yml)
[![GF180 regression](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/regression-gf180.yml?branch=main&style=flat-square&label=GF180&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/regression-gf180.yml)
[![ICS55 regression](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/regression-ics55.yml?branch=main&style=flat-square&label=ICS55&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/regression-ics55.yml)
[![SKY130 regression](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/regression-sky130.yml?branch=main&style=flat-square&label=SKY130&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml)<br>
[![SKY130 regression](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/regression-sky130.yml?branch=main&style=flat-square&label=SKY130&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml)
[![Quality](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/quality.yml?branch=main&style=flat-square&label=Quality&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/quality.yml)
[![Nightly](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/nightly.yml?branch=main&style=flat-square&label=Nightly&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/nightly.yml)
[![Nix/Docker](https://img.shields.io/github/actions/workflow/status/retroSoC/retroSoC/development-environment.yml?branch=main&style=flat-square&label=Nix%20Docker&labelColor=3b301a&logo=githubactions&logoColor=f6d365)](https://github.com/retroSoC/retroSoC/actions/workflows/development-environment.yml?query=branch%3Amain)
retroSoC is a fully open-source RISC-V SoC project. The repository brings together
SystemVerilog RTL, a freestanding embedded C SDK and applications, simulation, synthesis,
static timing analysis, reproducible dependencies, and release packaging. It is licensed
under the [Mulan Permissive Software License, Version 2](LICENSE).
## Highlights
[Overview](#platform-overview) · [Quick start](#quick-start) · [Configurations](#configurations-and-common-flows) · [Documentation](#documentation-and-repository) · [Validation](#validation-and-reproducibility) · [Contributing](#contributing)
- A fixed asymmetric dual-core Mini product: Hazard3 is the LP management hart
and generated dual-issue RV64IMAFDC VexiiRiscv is the HP application hart.
The C0-C3 selectable cores remain only in the explicit Mini MPW profile.
- A product [LP/HP architecture](docs/lp-hp-architecture.md) with independent
AON, LP, HP, PCLK, memory, audio, pixel, JTAG, and ULPI clock/reset contracts,
a native AXI64 HP data plane, fixed EXT-L/EXT-H slots,
HP CLINT/PLIC, UART1, mailbox, locked OpenSBI/Linux/Buildroot inputs, and a
CRC-checked direct-Linux boot bundle. Linux boot and performance evidence are
release gates, not yet baseline CI claims.
- A documented [Tiny/Mini/Std/Pro product direction](docs/soc-family-positioning.md)
anchored by Mini and a trusted Hazard3 management model. The higher Linux,
graphics, AI, and RV64 configurations are roadmap targets, not supported
build profiles.
- A standard five-pad JTAG Debug Transport Module for the Hazard3 management
core, with a reproducible Verilator, OpenOCD, and GDB acceptance flow.
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets with
open-source CI coverage.
- A memory-mapped peripheral subsystem with GPIO, UART,
[dual general timers](docs/ip/timer.md),
[PWM V2](rtl/managed/clusterip/pwm/doc/datasheet.md),
[dual I2C controllers](docs/ip/i2c.md), I2S,
[bidirectional PS/2](docs/ip/ps2.md),
WS2812, SPI/QSPI, SDIO, PSRAM/[OPI-PSRAM](docs/ip/opipsram.md), SDRAM, DMA, LCD, RTC, an
independent-clock window watchdog, CRC, and a
management-only RNG entropy controller. The P5 [GA2D](docs/ip/ga2d.md) is an
ownership-routed, PCLK-controlled, direct single-job private-AXI64 2D engine
with FILL, COPY, bit-exact CONVERT, opaque alpha BLEND, A8 fixed-color
foreground masks, and exact equal background/destination in-place composition.
Color surfaces are RGB565, RGB888, XRGB8888, and ARGB8888; A8 is BLEND
foreground-only. It retains pitch, byte-edge, snapshot, and IRQ support at
the existing APB4_GA2D window. It does not provide transparent-background or
premultiplied-alpha modes, a scaler or renderer, descriptors/rings/queues,
cache coherency, or a Linux graphics driver.
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.
- Open-source behavioral simulation with Icarus Verilog and Verilator,
synthesis with Yosys, netlist simulation with Icarus Verilog, and timing
analysis with OpenSTA.
- Read-only ARCHINFO ABI discovery for build/configuration provenance, SoC
topology, technology capabilities, and lifecycle-gated device identity.
- Checksum-verified dependency and toolchain locks, structured flow results, warning
baselines, metrics collection, SBOM generation, and checksummed release packages.
## Platform overview
## Repository Layout
**Mini is the active implementation.** The product configuration combines a
low-power (LP) management hart and a high-performance (HP) application hart.
The separate Mini MPW profile retains the legacy selectable-core integration.
[Tiny, Std, and Pro](docs/soc-family-positioning.md) are product-roadmap targets,
not additional supported build profiles.
| Area | Mini platform |
| Path | Contents |
| --- | --- |
| Compute | Hazard3 LP management hart; generated dual-issue VexiiRiscv HP application hart. Baseline profiles compile LP firmware for RV32IM and select an RV32IMAFDC HP core with Zicbom cache maintenance. |
| Memory and interconnect | Native AXI4 data plane, APB4 control, configurable on-chip SRAM, SDRAM, PSRAM/OPI-PSRAM, and XPI flash integration. |
| Control and I/O | GPIO, timers, UART, I2C, I2S, PWM, RTC, watchdog, storage interfaces, DMA, interrupt routing, and fixed EXT-L/EXT-H extension slots. |
| Software | Freestanding C runtime and HAL, board support, diagnostic and shell applications, CoreMark, and HP boot/bundle tooling. |
| Development | Locked toolchains and dependencies; Icarus Verilog and Verilator simulation, Yosys synthesis, OpenSTA timing analysis, and structured verification artifacts. |
| [`rtl/`](rtl) | SoC RTL, CPU integration, peripherals, interfaces, testbenches, and technology wrappers. |
| [`dependencies/`](dependencies) | Locked external repositories, archives, toolchains, and environment inputs. |
| [`crt/`](crt) | Freestanding RISC-V startup code, linker scripts, runtime library, core services, and HAL headers. |
| [`app/`](app) | Applications, board support, media, middleware, networking, ports, and benchmarks. |
| [`configs/`](configs) | Versioned build profiles for CI, nightly, and cluster flows. |
| [`physical/`](physical) | Physical-design entry points, managed PDK integration, and smoke synthesis/STA flows. |
| [`scripts/`](scripts) and [`quality/`](quality) | Build helpers, regression orchestration, checks, warning baselines, and metric policy. |
| [`.github/`](.github) | GitHub automation, Dependabot configuration, and CI/release workflows; see [`GUIDE.md`](.github/GUIDE.md). |
| [`docs/`](docs) | Engineering workflow and release-process documentation. |
| [`publications/`](publications) | Manually built Typst datasheets and versioned publication media. |
The accelerator integrations include:
## Supported Configurations
- **[APU](docs/ip/apu.md)** — LP-loaded audio microcode, WAV/PCM and native FLAC
decoding, I2S streaming, and optional keyword spotting (KWS). MP3 decoding
is deferred.
- **[NPU](docs/ip/npu.md)** — an INT8 inference engine with 64 dense MAC lanes,
64 KiB of private banked SRAM, offline compilation, and bare-metal deployment.
- **[GA2D](docs/ip/ga2d.md)** — 2D fill, copy, pixel conversion, and alpha
blending with opaque output and A8 foreground masks; no scaler or Linux driver.
- **[JPEG](docs/ip/jpeg.md) and [crypto](docs/ip/crypto.md)** — dedicated image
and cryptographic blocks with their own interface and verification contracts.
The committed profiles are the supported starting points. They select an ISA,
PDK, application, linker layout, and optional features as one reproducible
configuration. Product profiles set `MINI_MODE=PRODUCT`, fix both CPU harts,
and report zero selectable user cores. `configs/cluster/mini-mpw.mk` is the
separate `MINI_MODE=MPW` compatibility profile for C0-C3.
`SRAM_SIZE_KIB` selects a generated 4/16/32/64/128 KiB native-AXI4 on-chip
SRAM window. The IHP130, GF180, and SKY130 CI profiles enable a 32 KiB macro-backed
window; committed ICS55 regression profiles deliberately keep SRAM and PLL
disabled. `configs/local/ics55.example.mk` documents the ignored local profile
used with commercial 32 KiB SRAM and PLL simulation models.
Capabilities depend on the selected profile and each IP's implementation and
qualification status. Linux boot and performance qualification remain separate
from baseline CI coverage. The integrated RNG uses an unqualified deterministic
source for diagnostics; it does not provide production entropy. See the
[architecture](docs/lp-hp-architecture.md) and [engineering guide](docs/engineering.md)
for these boundaries.
| Profile | ISA | Application | Coverage |
| --- | --- | --- | --- |
| [`configs/ci/ihp130.mk`](configs/ci/ihp130.mk) | RV32IM | `bringup` | Firmware and behavioral regression with a 32 KiB IHP SRAM; local full-flow commands also support Yosys, netlist Icarus, and OpenSTA. |
| [`configs/ci/gf180.mk`](configs/ci/gf180.mk) | RV32IM | `bringup` | Firmware and behavioral regression with a 32 KiB SRAM assembled from GF180 macros; local full-flow commands support synthesis and timing. |
| [`configs/ci/ics55.mk`](configs/ci/ics55.mk) | RV32IM | `bringup` | Firmware and behavioral regression without a public SRAM macro; local full-flow commands support synthesis and core timing. |
| [`configs/ci/sky130.mk`](configs/ci/sky130.mk) | RV32IM | `bringup` | Firmware and behavioral regression with a 32 KiB OpenRAM SRAM; local full-flow commands support synthesis and timing. |
| [`configs/ci/ihp130-shell.mk`](configs/ci/ihp130-shell.mk) | RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
| [`configs/ci/ihp130-debug.mk`](configs/ci/ihp130-debug.mk) | RV32IM | `debug` | Verilator remote-bitbang acceptance of the Hazard3 JTAG DTM, Debug Module, OpenOCD, and GDB. |
| [`configs/ci/ihp130-hp.mk`](configs/ci/ihp130-hp.mk) | LP RV32IM / HP RV64IMAFDC | `hp_boot` | Linux image/bundle flow and HP RTL validation on the fixed product topology. |
| [`configs/ci/ihp130-rtthread.mk`](configs/ci/ihp130-rtthread.mk) | LP RV32IM / HP RV64IMAFDC | `hp_boot` | Locked RT-Thread v5.3.0 M-mode kernel/platform acceptance on HP hart 1. |
| [`configs/benchmark/ihp130-hazard3-coremark.mk`](configs/benchmark/ihp130-hazard3-coremark.mk) | LP RV32IM / HP RV64IMAFDC+Zicbom | `coremark` | Fixed four-iteration LP SRAM CoreMark measurement with the product HP core present. |
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | LP RV32IM / HP RV64IMAFDC+Zicbom | `bringup` | Site profile with PLL/SRAM intentionally disabled for regression compatibility. |
| [`configs/cluster/mini-mpw.mk`](configs/cluster/mini-mpw.mk) | RV32IM | `bringup` | Legacy MPW C0-C3/user-IP selection profile; not part of the Mini product ABI. |
## Quick start
### 1. Prepare the development environment
Use the [development environment guide](docs/development-environment.md) to
prepare the locked tools before building. The native environment targets
Linux x86_64. Docker supports a Linux/amd64 environment, including emulation
on Apple Silicon; Nix support is Linux x86_64 only.
| Environment | Setup instructions |
| --- | --- |
| Docker | [Build and enter the development image](docs/development-environment.md#docker). |
| Nix | [Open the repository development shell](docs/development-environment.md#nix). |
| Manual Ubuntu 22.04 | [Bootstrap and activate the locked tools](docs/development-environment.md#shared-bootstrap). |
For manual Ubuntu installs, first install the host packages from the
`apt-get install` list in [docker/Dockerfile](docker/Dockerfile), including
Java 17. The bootstrap checks these tools but does not install OS packages.
Tools and checkout inputs are separate: the environment provides compilers and
EDA tools, while `make setup` retrieves the profile's managed sources, PDK,
and application inputs. Tool versions come from the
[dependency lock](dependencies/dependencies.lock.json).
### 2. Build and simulate Mini
From the repository root, inside the prepared environment:
CI Verilator firmware simulations explicitly select the `ci_smoke`
application, which checks UART, archinfo APB readback, macro-backed on-chip SRAM,
the GA2D direct 2D route including CONVERT/BLEND/A8 in-place acceptance, RNG
fail-closed behavior, and test-status completion without the verbose startup
report. ARCHINFO checks include its
ABI and the build/configuration identifiers generated for that variant. The
IHP130 PR run links this image into the 32 KiB SRAM, explicitly enables the
fast-flash backend, and allows 360 seconds; Icarus keeps the real serial XPI
boot-model check. The profiles retain `bringup`
as their default for manual diagnostics. To run the full report in Verilator,
use:
```sh
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG setup
make CONFIG=configs/ci/ihp130.mk APP=bringup SIMU=VERILATOR SOC_SIM_TIME=300 firmware sim
# Firmware, RTL lint, debug, and behavioral simulation without synthesis/STA
make regress-rtl
```
## Prerequisites
The open-source development environment contains the exact Ubuntu 22.04 tool bundles, Python
quality tools, compiler, formatters, simulators, synthesis, STA, and formal tools used by the
current regression. It does not contain PDKs, managed RTL, or application archives; those remain
checkout-local inputs installed and verified through the existing setup targets. Linux x86_64 is
the supported host for the full native environment. On macOS, use Docker with linux/amd64
emulation. Nix support is Linux x86_64 only.
Choose one of the following installation methods. Each uses the locked versions in
[dependencies/dependencies.lock.json](dependencies/dependencies.lock.json) and creates or reuses the local
cache at .cache/retrosoc/development.
### Nix
Install Nix with flakes enabled, then run the development application from the repository root.
It builds a Linux FHS environment and invokes the same locked bootstrap script as Docker and the
manual method.
~~~sh
nix run .#dev -- make setup-regression
nix run .#dev -- make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG doctor
nix run .#dev -- make regress-pr
~~~
Use nix run .#dev without a command to open an interactive shell. The pinned nixpkgs revision is
recorded in flake.lock and cross-checked against the dependency lock.
### Docker
Build the local image once. The base image is immutable by digest and the image bootstrap installs
the same locked tools into an image-local cache. Mount the checkout so generated files, PDKs, and
managed sources remain on the host volume.
~~~sh
docker build --tag retrosoc-dev --file docker/Dockerfile .
docker run --rm --init --platform linux/amd64 --user "$(id -u):$(id -g)" -it \
-v "$PWD:/workspace/retrosoc" retrosoc-dev \
make setup-regression
docker run --rm --init --platform linux/amd64 --user "$(id -u):$(id -g)" -it \
-v "$PWD:/workspace/retrosoc" retrosoc-dev \
make regress-pr
~~~
### Manual Installation
On Ubuntu 22.04, install the host packages used by CI, then run the shared bootstrap script. It
downloads only checksum-verified tool bundles and Python packages pinned by the repository.
~~~sh
sudo apt-get update
sudo apt-get install --no-install-recommends --yes \
bzip2 ca-certificates ccache clang-format-14 g++ git libfl2 libgoogle-perftools4 \
libunwind8 make mold numactl python3 python3-pip python3-venv xz-utils zlib1g
python3 scripts/development_environment.py bootstrap
source .cache/retrosoc/development/activate.sh
make setup-regression
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG doctor
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG firmware sim
```
~~~
This runs the IHP130 profile's manual `bringup` application. It is not the
exact PR regression: automated Verilator runs select `ci_smoke`, while Icarus
regressions use the assembly self-test. See
[supported flows](docs/engineering.md#supported-profiles) for the overrides.
Run python3 scripts/development_environment.py check after a lock update or when diagnosing a
local tool issue. The lock file also pins external RTL, PDK, benchmark, and application sources.
Their setup scripts verify full Git revisions or SHA-256 checksums before use. See the
[engineering workflow](docs/engineering.md#reproducible-inputs) for the dependency update
procedure.
Keep `firmware sim` in the same Make invocation so both use one build variant.
Outputs live under `build/<profile>-<YYYY-MM-DD-HH-MM>-<config-hash>/`.
Check the flow logs and result JSON; UART startup text alone is not a pass.
## Quick Start
## Configurations and common flows
Start with the CI-verified IHP130 `bringup` profile. `setup` retrieves the pinned
source dependencies, and `doctor` reports any missing local executables or setup inputs.
Start from a [committed profile](configs/README.md). These are selected entry
points, not the complete profile or application inventory.
```sh
make CONFIG=configs/ci/ihp130.mk setup
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG doctor
make CONFIG=configs/ci/ihp130.mk firmware
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG sim
```
| Profile | Purpose |
| --- | --- |
| [IHP130 Mini](configs/ci/ihp130.mk) | Manual bring-up with 32 KiB macro-backed SRAM. |
| [GF180](configs/ci/gf180.mk) / [SKY130](configs/ci/sky130.mk) | Alternative PDK profiles with 32 KiB macro-backed SRAM. |
| [ICS55](configs/ci/ics55.mk) | Regression-compatible profile with SRAM and PLL disabled. |
| [Interactive shell](configs/ci/ihp130-shell.mk) | Shell firmware with CSR support enabled. |
| [Hazard3 debug](configs/ci/ihp130-debug.mk) | JTAG acceptance using Verilator, OpenOCD, and GDB. |
| [HP Linux](configs/ci/ihp130-hp.mk) | HP image/bundle flow; outside the supported PR matrix. |
| [APU LP/HP](configs/ci/ihp130-apu.mk) | Audio and KWS evidence flow with ownership handoff to HP. |
| [CoreMark](configs/benchmark/ihp130-hazard3-coremark.mk) | Fixed LP SRAM benchmark with the product HP core present. |
| [Mini MPW](configs/cluster/mini-mpw.mk) | Legacy C0-C3/user-IP compatibility, separate from the product ABI. |
After the corresponding setup, use these common commands:
Select the interactive shell application without editing source files:
```sh
# Build the interactive shell firmware
make CONFIG=configs/ci/ihp130-shell.mk firmware
# Inspect the effective configuration and available targets
make CONFIG=configs/ci/ihp130.mk config
make help
# Check source formatting and embedded C policy/host tests
make format-check
make sw-policy-check sw-host-test
```
| Validation flow | Command |
| --- | --- |
| IHP130 smoke: RTL lint, firmware, SVA compilation, Icarus self-test | `make regress-smoke` |
| IHP130 behavioral flows, including debug acceptance | `make regress-rtl` |
| Full local PR matrix across four PDKs | `make regress-pr` |
| Extended local regression | `make regress-nightly` |
## Common Flows
Prepare the multi-PDK inputs with `make setup-regression` before the full PR
matrix. Profile setup does not install every optional reference corpus; follow
any additional prerequisites in the affected IP or test guide. For debugging,
benchmarks, and HP software, use the dedicated guides linked below.
All commands use a committed profile. `make config` prints the effective configuration and
variant identifier; `make help` lists all available targets. Netlist simulation and timing
analysis consume the Yosys netlist, so run the synthesis command first. The CI-proven netlist
regression uses the assembly self-test image:
<details>
<summary>Advanced local flows: netlist simulation and licensed VCS</summary>
Verilator simulations run for 180 seconds by default. The IHP130 `ci_smoke`
regression explicitly uses 360 seconds because its LP memory accesses traverse
the asynchronous data gateway. Set `SOC_SIM_TIME` explicitly only when an
exploratory local run needs a different limit.
These flows require the relevant synthesis/timing tools and PDK inputs, or a
licensed VCS environment. Keep one timestamp across dependent commands:
VCS flow commands use `bsub -Is` by default: this includes parse-time Python helpers used to
calculate the variant and dependency-lock digest, generated-flow Python helpers, VCS, `simv`, and
Verdi. In a licensed local VCS environment, run without LSF submission using `VCS_USE_LSF=NO`; an
explicit `VCS_RUNNER` takes precedence when a site-specific queue or wrapper is required:
```sh
make CONFIG=configs/ci/ihp130.mk SIMU=VCS VCS_USE_LSF=NO sim
make CONFIG=configs/ci/ihp130.mk SIMU=VCS VCS_RUNNER='bsub -q vcs -Is' sim
```
```sh
export BUILD_TIMESTAMP=$(date +%Y-%m-%d-%H-%M)
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG RTL_SIM_TIMEOUT=5200000 sim-asm
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG \
SIM_FIRMWARE_NAME=retrosoc_asm RTL_SIM_TIMEOUT=5200000 netsim
make CONFIG=configs/ci/ihp130.mk STA=OPENSTA sta
SIM_FIRMWARE_NAME=retrosoc_asm \
RTL_SIM_TIMEOUT=5200000 netsim
```
VCS defaults to `bsub -Is` for licensed cluster runs. Disable LSF for a licensed
local run, or set `VCS_RUNNER` to the site's wrapper:
| Goal | Command |
| --- | --- |
| Icarus behavioral simulation | `make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG sim` |
| Verilator behavioral simulation | `make CONFIG=configs/ci/ihp130.mk SIMU=VERILATOR sim` |
| Hazard3 JTAG debug acceptance | `make CONFIG=configs/ci/ihp130-debug.mk SIMU=VERILATOR debug-sim` |
| Assembly self-test with Icarus | `make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG RTL_SIM_TIMEOUT=5200000 sim-asm` |
| Yosys synthesis | `make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth` |
| Icarus netlist simulation after synthesis | `make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG netsim` |
| OpenSTA core timing analysis after synthesis | `make CONFIG=configs/ci/ihp130.mk STA=OPENSTA sta` |
| Strict Verilator RTL lint | `make CONFIG=configs/ci/ihp130.mk SIMU=VERILATOR HAVE_SVA=YES check-rtl-lint` |
| Hazard3 CoreMark quick report | `make CONFIG=configs/benchmark/ihp130-hazard3-coremark.mk SIMU=VERILATOR SOC_SIM_TIME=7200 coremark-report` |
| Generate the untracked HP core RTL | `make CONFIG=configs/ci/ihp130-hp.mk vexii-generate` |
| Build and package the HP Linux flash image | `make setup-hp-linux && make CONFIG=configs/ci/ihp130-hp.mk hp-bundle` |
| IHP130 fast smoke suite | `make regress-smoke` |
| Pull-request regression suite | `make regress-pr` |
| Nightly regression suite | `make regress-nightly` |
| Format C, Makefile, and RTL sources | `make format` |
| Check C, Makefile, and RTL formatting | `make format-check` |
| Script and policy checks | `make sw-policy-check sw-host-test` |
`make regress-smoke` builds the IHP130 firmware, compiles the Verilator SVA
configuration, and runs the Icarus assembly self-test. It runs strict RTL lint
before those flows and omits synthesis,
timing, and netlist simulation for fast feedback. `make regress-pr` runs the
supported IHP130, GF180, ICS55, and SKY130 PR matrices in sequence, including
slow-corner OpenSTA core timing analysis for each PDK.
GitHub-hosted regression workflows currently pass `--behavioral-only` to avoid
the unresolved JPEG Yosys memory peak. They retain RTL lint, firmware, Verilator,
and Icarus behavioral coverage; local `make regress-pr` remains the complete
synthesis, netlist simulation, and OpenSTA flow.
Build outputs are isolated below `build/<profile>-<YYYY-MM-DD-HH-MM>-<config-hash>/`. Each variant keeps its
firmware, generated sources, simulator output, synthesis and timing reports, manifest, warning
analysis, and metrics separate from other configurations. Use `make clean` to remove the
selected backend, `make clean-all` to remove all build output, and `make purge-cache` to remove
download and compiler caches.
`BUILD_TIMESTAMP` defaults to the local build-start time. Set it explicitly when separate Make
commands must reuse one variant:
```sh
make CONFIG=configs/ci/ihp130.mk SIMU=VCS VCS_USE_LSF=NO firmware sim
export BUILD_TIMESTAMP=2026-07-21-10-39
make CONFIG=configs/ci/ihp130.mk firmware
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG sim
```
After this sequence, `unset BUILD_TIMESTAMP` to restore automatic timestamps.
See [build layout](docs/engineering.md#build-layout) and
[result policy](docs/engineering.md#result-policy) for artifacts and verdicts.
## Reproducibility And CI
</details>
[`dependencies/dependencies.lock.json`](dependencies/dependencies.lock.json) is the source of truth for
external repositories, application archives, and Ubuntu 22.04 toolchain bundles. The lock digest
is part of each build variant, and every download is checksum verified. GitHub Actions pins its
actions by commit, validates the lock and engineering scripts, and runs pull-request and nightly
regression matrices.
## Documentation and repository
Every EDA command is recorded with a log and a machine-readable result JSON. The regression
policy checks warning deltas against committed baselines and collects metrics for later gate
promotion. Tags matching `v*` produce a flattened SystemVerilog export, source archive, build
manifest, dependency lock, CycloneDX SBOM, and `SHA256SUMS`. Run `make package` to create the
same local deliverables under `dist/<variant>/`.
| Start here | Guides |
| --- | --- |
| Understand the platform | [LP/HP architecture](docs/lp-hp-architecture.md), [IP specifications](docs/ip/README.md), [datasheet workflow](publications/README.md). |
| Develop firmware | [SDK](crt/README.md), [applications](app/README.md), [HP software](app/ports/linux/README.md). |
| Debug and measure | [Hazard3 debug](docs/hazard3-debug.md), [CoreMark](docs/coremark.md), [engineering workflow](docs/engineering.md). |
| Change RTL or tooling | [RTL conventions](docs/rtl-coding-style.md), [MISRA policy](docs/misra-c-2012.md), [agent contract](AGENTS.md). |
| Explore further | [Documentation index](docs/README.md), [build profiles](configs/README.md), [contribution process](CONTRIBUTING.md). |
| Directory | Contents |
| --- | --- |
| [rtl/](rtl/README.md) | SoC integration, IP, interfaces, simulation, and technology wrappers. |
| [crt/](crt/README.md) / [app/](app/README.md) | Freestanding SDK, firmware applications, and software integrations. |
| [configs/](configs/README.md) / [dependencies/](dependencies/README.md) | Reproducible profiles and locked external inputs. |
| [tests/](tests/README.md) / [scripts/](scripts/README.md) / [quality/](quality/README.md) | Verification, build helpers, and executable quality policy. |
| [physical/](physical/README.md) / [fpga/](fpga/README.md) | Physical-design flows and FPGA integration. |
| [docs/](docs/README.md) / [publications/](publications/README.md) | Engineering specifications and manually built datasheets. |
| [.github/](.github/GUIDE.md) / [docker/](docker/README.md) | Automation and the container development environment. |
## Validation and reproducibility
The status badges above track **`main`**, not the current checkout. Other runs:
[GF180](https://github.com/retroSoC/retroSoC/actions/workflows/regression-gf180.yml),
[ICS55](https://github.com/retroSoC/retroSoC/actions/workflows/regression-ics55.yml),
[SKY130](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml),
and [nightly](https://github.com/retroSoC/retroSoC/actions/workflows/nightly.yml).
The quality gate checks source policy and runs script/RTL fixture tests.
Hosted SoC regression and development-environment workflows use
`--behavioral-only`: they do not run the full SoC synthesis, netlist simulation,
or OpenSTA stages. Local full-flow commands retain those stages. Neither CI
status nor core timing analysis establishes physical or silicon signoff.
Dependencies and tool archives are pinned by revision or checksum. Each build
variant records its configuration and lock digest, and EDA flows produce logs
and structured results. Warning and metric policies remain defined by the
[engineering guide](docs/engineering.md); no performance claim is implied by
a badge. Maintainer-published `v*` tags trigger
[release packaging](docs/engineering.md#ci-and-releases), including the source
archive, manifest, dependency lock, SBOM, and checksums.
See [`docs/engineering.md`](docs/engineering.md) for supported-flow details, artifact layout,
warning and metric policy, CI behavior, and release contents.
## Contributing
Start with the [contribution guide](CONTRIBUTING.md), follow the
[Git workflow](docs/git-workflow.md), and use the
[PR template](.github/pull_request_template.md). Ordinary contributions target
`dev` and preserve meaningful commits through merge-commit integration.
Please follow the [Code of Conduct](CODE_OF_CONDUCT.md).
Contributions are welcome. If you want to improve the RTL, software, verification,
documentation, or development flows, open an issue or submit a pull request after
reading [`CONTRIBUTING.md`](CONTRIBUTING.md).
retroSoC is licensed under [Mulan PSL v2](LICENSE). Third-party terms are
recorded in [NOTICE](NOTICE), [ATTRIBUTIONS](ATTRIBUTIONS.md), and
[licenses/](licenses/README.md). See the existing [security policy](Security.md)
for its current reporting information.
- Report vulnerabilities according to [`Security.md`](Security.md).
- Review retained third-party notices in [`NOTICE`](NOTICE) and
[`ATTRIBUTIONS.md`](ATTRIBUTIONS.md).
- The project is distributed under [Mulan PSL v2](LICENSE).
Thanks to everyone contributing to retroSoC.
A big **thank you** goes out to everyone who has contributed to retroSoC:
[![retroSoC contributors](https://contrib.rocks/image?repo=retroSoC/retroSoC)](https://github.com/retroSoC/retroSoC/graphs/contributors)
<a href="https://github.com/retroSoC/retroSoC/graphs/contributors">
<img src="https://contrib.rocks/image?repo=retroSoC/retroSoC" alt="retroSoC contributors" />
</a>
+5 -21
View File
@@ -32,8 +32,7 @@ The build selects an application with `APP=<name>`. The supported profiles are:
| `ci_smoke` | Fast deterministic CI smoke test for UART, ARCHINFO V2, LP external IRQ dispatch when CSR-enabled, RNG, crypto AES/SHA, SDRAM mapped access, 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. |
| `hp_boot` | SRAM-resident LP loader that validates the HP Linux flash bundle, loads SDRAM, releases HP, and monitors the mailbox verdict. |
| `apu_release` | PSRAM-resident LP/HP APU evidence flow: LP-only microcode/KWS model load, ownership handoff to HP, HP-submitted WAV/KWS jobs with Zicbom maintenance, and LP-only register fault probe. |
| `hp_boot` | SRAM-resident LP loader that validates typed V2 Linux, smoke or RT-Thread bundles, loads SDRAM, releases HP, and monitors the workload-specific mailbox verdict. |
| `shell` | Interactive application that adds shell services, board drivers, media, FatFs, CoreMark, and UserIP integration. |
| `xpi_flash_loader` | SRAM-resident, GDB-called service image for sector-preserving JTAG programming of the qualified NSS0 NOR. |
@@ -41,25 +40,6 @@ The application manifest is loaded from `app/apps/<name>/app.mk`. It appends
`APP_SRCS` and, when necessary, `APP_INC_DIRS` to the SDK sources selected by
the central build.
NPU-P5 acceptance extends existing compositions rather than adding an APP.
`NPU_P5_ACCEPTANCE=YES` is valid only with `ci_smoke` or `hp_boot` and is part
of the reproducible variant key. The LP path links the generated KWS plan into
`ci_smoke`, uses the real LP completion interrupt, and writes the normal
SYSCTRL verdict. The HP smoke bundle assigns resource 9 to hart 1, runs the
same plan with polling and 64-byte Zicbom maintenance, then returns ownership
before LP publishes the final verdict. The option defaults to `NO`, preserving
normal PR firmware size and behavior.
NPU-P6 likewise reuses `APP=hp_boot`; it does not add an application profile
or public ABI. `NPU_P6_ACCEPTANCE=YES` selects a private qualification payload,
and `NPU_P6_WORKLOAD=kws|vww` selects one frozen generated plan. The payload
reads a CRC-protected 100-case shard from the existing HP `Image` slot, runs
the portable C and production NPU paths through CPU Softmax, measures both
with HP `rdcycle`, and emits fail-closed per-case records. The first ten global
cases also overlap an identical GA2D DMA copy with both measured paths.
Normal and P5 builds remain unchanged because P5 and P6 acceptance flags are
mutually exclusive and both default to `NO`.
Build and simulate the supported profiles from the repository root:
```sh
@@ -86,6 +66,10 @@ make CONFIG=configs/ci/ihp130-debug.mk SIMU=VERILATOR debug-sim
make setup-hp-linux
make CONFIG=configs/ci/ihp130-hp.mk hp-bundle
# Build and test the pinned RV64 M-mode RT-Thread payload on HP hart 1
make setup-hp-rtthread
make CONFIG=configs/ci/ihp130-rtthread.mk SIMU=VERILATOR hp-rtthread-sim
# Build the SRAM-resident XPI NOR loader used by the host JTAG tool
make CONFIG=configs/ci/ihp130-xpi-flash-loader.mk firmware
```
+2 -1
View File
@@ -1,2 +1,3 @@
APP_SRCS += $(ROOT_PATH)/app/apps/hp_boot/main.c
APP_INC_DIRS += $(ROOT_PATH)/app/apps/hp_boot
APP_SRCS += $(ROOT_PATH)/app/apps/hp_boot/hp_boot_bundle.c
APP_INC_DIRS += $(ROOT_PATH)/app/apps/hp_boot
+79
View File
@@ -0,0 +1,79 @@
#include "hp_boot_bundle.h"
#include <stddef.h>
uint32_t rs_hp_boot_message_status(uint32_t code, uint32_t argument, uint32_t sequence,
uint32_t expected_code, uint32_t expected_argument,
uint32_t expected_sequence) {
if ((sequence > expected_sequence) || ((sequence != 0U) && (code == 3U))) {
return 2U;
}
if (sequence == expected_sequence) {
return ((code == expected_code) && (argument == expected_argument)) ? 1U : 2U;
}
return 0U;
}
uint32_t rs_hp_boot_crc32_byte(uint32_t crc, uint8_t value) {
crc ^= value;
for (uint32_t bit = 0U; bit < 8U; ++bit) {
uint32_t mask = UINT32_C(0) - (crc & UINT32_C(1));
crc = (crc >> 1U) ^ (UINT32_C(0xEDB88320) & mask);
}
return crc;
}
uint32_t rs_hp_boot_crc32(const uint8_t *data, uint32_t size) {
uint32_t crc = UINT32_C(0xFFFFFFFF);
for (uint32_t index = 0U; index < size; ++index) {
crc = rs_hp_boot_crc32_byte(crc, data[index]);
}
return ~crc;
}
bool rs_hp_boot_header_valid(const rs_hp_boot_header_t *header) {
static const uint32_t addresses[4] = {RS_HP_BOOT_OPENSBI_ADDRESS, RS_HP_BOOT_DTB_ADDRESS,
RS_HP_BOOT_LINUX_ADDRESS, RS_HP_BOOT_INITRAMFS_ADDRESS};
static const uint32_t maxima[4] = {RS_HP_BOOT_OPENSBI_MAX_SIZE, RS_HP_BOOT_DTB_MAX_SIZE,
RS_HP_BOOT_LINUX_MAX_SIZE, RS_HP_BOOT_INITRAMFS_MAX_SIZE};
rs_hp_boot_header_t copy;
uint32_t previous_end = RS_HP_BOOT_BUNDLE_OFFSET + (uint32_t)sizeof(copy);
uint32_t count;
if (header == NULL) {
return false;
}
copy = *header;
copy.header_crc32 = 0U;
count = (header->workload == RS_HP_BOOT_WORKLOAD_LINUX) ? 4U : 1U;
if ((header->magic != RS_HP_BOOT_BUNDLE_MAGIC) ||
(header->version != RS_HP_BOOT_BUNDLE_VERSION) || (header->header_size != sizeof(copy)) ||
(header->entry_count != count) || (header->workload < RS_HP_BOOT_WORKLOAD_LINUX) ||
(header->workload > RS_HP_BOOT_WORKLOAD_RTTHREAD) ||
(header->flags != RS_HP_BOOT_BUNDLE_REQUIRED) || (header->total_size < sizeof(copy)) ||
(header->total_size > UINT32_C(0x00F00000)) ||
(rs_hp_boot_crc32((const uint8_t *)&copy, sizeof(copy)) != header->header_crc32)) {
return false;
}
for (uint32_t index = 0U; index < RS_HP_BOOT_BUNDLE_ENTRY_COUNT; ++index) {
const rs_hp_boot_entry_t *entry = &header->entries[index];
if (index >= count) {
if ((entry->type | entry->flash_offset | entry->load_address | entry->size |
entry->crc32 | entry->flags) != 0U) {
return false;
}
} else {
uint32_t type = (count == 4U) ? index + 1U : RS_HP_BOOT_TYPE_EXECUTABLE;
uint32_t bundle_end = RS_HP_BOOT_BUNDLE_OFFSET + header->total_size;
if ((entry->type != type) || (entry->load_address != addresses[index]) ||
(entry->size == 0U) || (entry->size > maxima[index]) ||
(entry->flags != RS_HP_BOOT_BUNDLE_REQUIRED) ||
((entry->flash_offset & UINT32_C(0xFFF)) != 0U) ||
(entry->flash_offset < previous_end) || (entry->flash_offset >= bundle_end) ||
(entry->size > (bundle_end - entry->flash_offset))) {
return false;
}
previous_end = entry->flash_offset + entry->size;
}
}
return true;
}
+18 -2
View File
@@ -2,10 +2,11 @@
#define RETROSOC_HP_BOOT_BUNDLE_H
#include <stdint.h>
#include <stdbool.h>
#define RS_HP_BOOT_BUNDLE_OFFSET UINT32_C(0x00100000)
#define RS_HP_BOOT_BUNDLE_MAGIC UINT32_C(0x50485352)
#define RS_HP_BOOT_BUNDLE_VERSION UINT32_C(1)
#define RS_HP_BOOT_BUNDLE_VERSION UINT32_C(2)
#define RS_HP_BOOT_BUNDLE_ENTRY_COUNT UINT32_C(4)
#define RS_HP_BOOT_BUNDLE_REQUIRED UINT32_C(1)
@@ -13,6 +14,13 @@
#define RS_HP_BOOT_TYPE_DTB UINT32_C(2)
#define RS_HP_BOOT_TYPE_LINUX UINT32_C(3)
#define RS_HP_BOOT_TYPE_INITRAMFS UINT32_C(4)
#define RS_HP_BOOT_TYPE_EXECUTABLE UINT32_C(5)
#define RS_HP_BOOT_WORKLOAD_LINUX UINT32_C(1)
#define RS_HP_BOOT_WORKLOAD_SMOKE UINT32_C(2)
#define RS_HP_BOOT_WORKLOAD_RTTHREAD UINT32_C(3)
#define RS_HP_RTTHREAD_READY_ARG UINT32_C(0x52545401)
#define RS_HP_RTTHREAD_IRQ_COMMAND UINT32_C(0x52545402)
#define RS_HP_RTTHREAD_IRQ_ARG UINT32_C(0x12345678)
#define RS_HP_BOOT_OPENSBI_ADDRESS UINT32_C(0x38000000)
#define RS_HP_BOOT_OPENSBI_MAX_SIZE UINT32_C(0x00080000)
@@ -40,8 +48,16 @@ typedef struct {
uint32_t total_size;
uint32_t header_crc32;
uint32_t flags;
uint32_t reserved;
uint32_t workload;
rs_hp_boot_entry_t entries[RS_HP_BOOT_BUNDLE_ENTRY_COUNT];
} rs_hp_boot_header_t;
uint32_t rs_hp_boot_crc32_byte(uint32_t crc, uint8_t value);
uint32_t rs_hp_boot_crc32(const uint8_t *data, uint32_t size);
bool rs_hp_boot_header_valid(const rs_hp_boot_header_t *header);
/* 0: wait for publication, 1: expected message, 2: invalid/failure message. */
uint32_t rs_hp_boot_message_status(uint32_t code, uint32_t argument, uint32_t sequence,
uint32_t expected_code, uint32_t expected_argument,
uint32_t expected_sequence);
#endif
+40 -87
View File
@@ -41,30 +41,6 @@ static bool s_hp_boot_ga2d_owned_by_hp;
_Static_assert(sizeof(rs_hp_boot_header_t) == RS_HP_BOOT_HEADER_SIZE,
"HP boot bundle header ABI mismatch");
static uint32_t rs_hp_boot_crc32_byte(uint32_t crc, uint8_t value) {
crc ^= value;
for (uint32_t bit = 0U; bit < 8U; ++bit) {
uint32_t mask = UINT32_C(0) - (crc & UINT32_C(1));
crc = (crc >> 1U) ^ (UINT32_C(0xEDB88320) & mask);
}
return crc;
}
static uint32_t rs_hp_boot_crc32(const uint8_t *data, uint32_t size) {
uint32_t crc = UINT32_C(0xFFFFFFFF);
for (uint32_t index = 0U; index < size; ++index) {
crc = rs_hp_boot_crc32_byte(crc, data[index]);
}
return ~crc;
}
static bool rs_hp_boot_range_valid(uint32_t address, uint32_t size, uint32_t base,
uint32_t capacity) {
return (size != 0U) && (address >= base) && (address < (base + capacity)) &&
((size - 1U) <= ((base + capacity - 1U) - address));
}
static void rs_hp_boot_read_header(rs_hp_boot_header_t *header) {
volatile const uint8_t *source =
(volatile const uint8_t *)(uintptr_t)(RS_SOC_FLASH_BASE + RS_HP_BOOT_BUNDLE_OFFSET);
@@ -75,60 +51,6 @@ static void rs_hp_boot_read_header(rs_hp_boot_header_t *header) {
}
}
static bool rs_hp_boot_entry_expected(const rs_hp_boot_entry_t *entry, uint32_t index,
uint32_t bundle_size) {
static const uint32_t types[RS_HP_BOOT_BUNDLE_ENTRY_COUNT] = {
RS_HP_BOOT_TYPE_OPENSBI,
RS_HP_BOOT_TYPE_DTB,
RS_HP_BOOT_TYPE_LINUX,
RS_HP_BOOT_TYPE_INITRAMFS,
};
static const uint32_t addresses[RS_HP_BOOT_BUNDLE_ENTRY_COUNT] = {
RS_HP_BOOT_OPENSBI_ADDRESS,
RS_HP_BOOT_DTB_ADDRESS,
RS_HP_BOOT_LINUX_ADDRESS,
RS_HP_BOOT_INITRAMFS_ADDRESS,
};
static const uint32_t maximum_sizes[RS_HP_BOOT_BUNDLE_ENTRY_COUNT] = {
RS_HP_BOOT_OPENSBI_MAX_SIZE,
RS_HP_BOOT_DTB_MAX_SIZE,
RS_HP_BOOT_LINUX_MAX_SIZE,
RS_HP_BOOT_INITRAMFS_MAX_SIZE,
};
return (entry->type == types[index]) && (entry->load_address == addresses[index]) &&
(entry->size <= maximum_sizes[index]) &&
((entry->flags & RS_HP_BOOT_BUNDLE_REQUIRED) != 0U) &&
((entry->flash_offset & UINT32_C(3)) == 0U) &&
((entry->load_address & UINT32_C(3)) == 0U) &&
rs_hp_boot_range_valid(entry->flash_offset, entry->size, RS_HP_BOOT_BUNDLE_OFFSET,
bundle_size) &&
rs_hp_boot_range_valid(entry->load_address, entry->size, RS_SOC_SDRAM_BASE,
RS_SOC_SDRAM_SIZE);
}
static bool rs_hp_boot_header_valid(rs_hp_boot_header_t *header) {
uint32_t expected_crc = header->header_crc32;
header->header_crc32 = 0U;
if ((header->magic != RS_HP_BOOT_BUNDLE_MAGIC) ||
(header->version != RS_HP_BOOT_BUNDLE_VERSION) ||
(header->header_size != sizeof(*header)) ||
(header->entry_count != RS_HP_BOOT_BUNDLE_ENTRY_COUNT) ||
((header->flags & RS_HP_BOOT_BUNDLE_REQUIRED) == 0U) ||
(header->total_size < sizeof(*header)) ||
(header->total_size > (RS_SOC_FLASH_SIZE - RS_HP_BOOT_BUNDLE_OFFSET)) ||
(rs_hp_boot_crc32((const uint8_t *)header, sizeof(*header)) != expected_crc)) {
return false;
}
for (uint32_t index = 0U; index < RS_HP_BOOT_BUNDLE_ENTRY_COUNT; ++index) {
if (!rs_hp_boot_entry_expected(&header->entries[index], index, header->total_size)) {
return false;
}
}
return true;
}
static bool rs_hp_boot_copy_entry(const rs_hp_boot_entry_t *entry) {
volatile const uint32_t *source_words =
(volatile const uint32_t *)(uintptr_t)(RS_SOC_FLASH_BASE + entry->flash_offset);
@@ -263,11 +185,18 @@ static bool rs_hp_boot_wait_message(uint32_t code, uint32_t argument, uint32_t s
rs_hp_mailbox_message_t message;
for (uint32_t timeout = 0U; timeout < RS_HP_BOOT_EVENT_TIMEOUT; ++timeout) {
uint32_t status;
if (rs_hp_mailbox_receive_from_hp(&message) != RS_OK) {
return false;
}
if (message.sequence == sequence) {
return (message.code == code) && (message.argument == argument);
status = rs_hp_boot_message_status(message.code, message.argument, message.sequence, code,
argument, sequence);
if (status == 2U) {
printf("HP_PAYLOAD_FAILED:%u\n", (unsigned int)message.argument);
return false;
}
if (status == 1U) {
return true;
}
}
return false;
@@ -336,7 +265,7 @@ int main(void) {
if (!rs_hp_boot_header_valid(&header)) {
rs_hp_boot_fail(UINT8_C(4));
}
for (uint32_t index = 0U; index < RS_HP_BOOT_BUNDLE_ENTRY_COUNT; ++index) {
for (uint32_t index = 0U; index < header.entry_count; ++index) {
printf("HP_BOOT_LOAD:%u:%u\n", (unsigned int)header.entries[index].type,
(unsigned int)header.entries[index].size);
if (!rs_hp_boot_dma_copy_entry(&header.entries[index]) &&
@@ -345,20 +274,25 @@ int main(void) {
}
}
if ((rs_hp_mailbox_probe() != RS_OK) || !rs_hp_boot_wait_ga2d_idle(RS_RESOURCE_OWNER_LP) ||
(rs_resource_set_owner(RS_RESOURCE_GA2D, RS_RESOURCE_OWNER_HP, false) != RS_OK)) {
if (rs_hp_mailbox_probe() != RS_OK) {
rs_hp_boot_fail(UINT8_C(9));
}
s_hp_boot_ga2d_owned_by_hp = true;
if (header.workload == RS_HP_BOOT_WORKLOAD_SMOKE) {
if (!rs_hp_boot_wait_ga2d_idle(RS_RESOURCE_OWNER_LP) ||
(rs_resource_set_owner(RS_RESOURCE_GA2D, RS_RESOURCE_OWNER_HP, false) != RS_OK)) {
rs_hp_boot_fail(UINT8_C(9));
}
s_hp_boot_ga2d_owned_by_hp = true;
if (!rs_hp_boot_wait_ga2d_idle(RS_RESOURCE_OWNER_HP)) {
rs_hp_boot_fail(UINT8_C(9));
}
}
#if defined(RS_NPU_P5_ACCEPTANCE) || defined(RS_NPU_P6_ACCEPTANCE)
if (!rs_hp_boot_wait_npu_idle(RS_RESOURCE_OWNER_LP) ||
(rs_resource_set_owner(RS_RESOURCE_NPU, RS_RESOURCE_OWNER_HP, false) != RS_OK)) {
rs_hp_boot_fail(UINT8_C(18));
}
#endif
if (!rs_hp_boot_wait_ga2d_idle(RS_RESOURCE_OWNER_HP)) {
rs_hp_boot_fail(UINT8_C(9));
}
#if defined(RS_NPU_P5_ACCEPTANCE) || defined(RS_NPU_P6_ACCEPTANCE)
if (!rs_hp_boot_wait_npu_idle(RS_RESOURCE_OWNER_HP)) {
rs_hp_boot_fail(UINT8_C(18));
@@ -372,11 +306,30 @@ int main(void) {
}
printf("HP_BOOT_RELEASED\n");
if (header.workload == RS_HP_BOOT_WORKLOAD_RTTHREAD) {
if (!rs_hp_boot_wait_message(RS_HP_BOOT_READY_EVENT, RS_HP_RTTHREAD_READY_ARG, 1U)) {
rs_hp_boot_fail(UINT8_C(18));
}
printf("HP_RTTHREAD_READY\n");
message.code = RS_HP_RTTHREAD_IRQ_COMMAND;
message.argument = RS_HP_RTTHREAD_IRQ_ARG;
message.sequence = 1U;
if ((rs_hp_mailbox_send_to_hp(&message) != RS_OK) ||
!rs_hp_boot_wait_message(2U, RS_HP_RTTHREAD_READY_ARG, 2U)) {
rs_hp_boot_fail(UINT8_C(19));
}
printf("HP_RTTHREAD_PASS\n");
rs_test_finish(RS_TEST_PASSED, UINT8_C(0));
}
if (!rs_hp_boot_wait_message(RS_HP_BOOT_READY_EVENT, RS_HP_BOOT_READY_ARG,
RS_HP_BOOT_MAILBOX_READY_SEQUENCE)) {
rs_hp_boot_fail(UINT8_C(11));
}
printf("HP_LINUX_READY\n");
if (header.workload == RS_HP_BOOT_WORKLOAD_LINUX) {
rs_test_finish(RS_TEST_PASSED, UINT8_C(0));
}
message.code = RS_HP_BOOT_GA2D_START_COMMAND;
message.argument = RS_HP_BOOT_GA2D_START_ARG;
message.sequence = RS_HP_BOOT_MAILBOX_READY_SEQUENCE;
+23 -1
View File
@@ -1,7 +1,7 @@
# HP Linux Port
This directory owns the Buildroot external tree, device tree, kernel config,
and integration metadata for the fixed RV32 VexiiRiscv HP core. Linux,
and integration metadata for the fixed RV64 VexiiRiscv HP core. Linux,
OpenSBI, Buildroot, toolchains, and all generated images remain below `.cache/`
or `build/` and are not tracked.
@@ -19,3 +19,25 @@ Run `make setup-hp-linux` to install the locked sources, then use the
console uses SBI; the UART1 and mailbox nodes reserve their stable platform
ABI for the native drivers.
The RV64/Sv39 acceptance image uses musl and static BusyBox with a dedicated
`/init`. It mounts procfs, sysfs, devtmpfs and tmpfs, verifies file I/O and child
execution, then publishes the Linux-ready mailbox message. The kernel effective
configuration and all executable ELF classes are checked during the build.
`rootfs.cpio` is a small uncompressed archive; the DTB uses its actual length.
The DT reserves the resident 512 KiB OpenSBI window with `no-map`; Linux must
not allocate it. The custom platform does not apply the generic OpenSBI FDT fixups.
It does not start the full Buildroot service sequence.
```sh
make CONFIG=configs/ci/ihp130-hp.mk hp-linux
make CONFIG=configs/ci/ihp130-hp.mk SIMU=VERILATOR hp-linux-sim
```
The V2 bundle uses workload 1 and four typed payloads. V1 images must be rebuilt.
Linux success goes directly to LP TEST_STATUS; GA2D/cache lifecycle is tested
by `hp-smoke-sim`. Logs and verdicts live in `sim/verilator/hp-linux/` below
the selected variant. `HP_LINUX_SIM_TIME=0` means no emulator wall-clock timeout;
successful TEST_STATUS ends the run. Interrupted/running results are not passes.
See [HP platform](../../../docs/ip/hp-platform.md) for the ABI and
[RT-Thread BSP](../rtthread/README.md) for the separate M-mode workload.
+16 -1
View File
@@ -1 +1,16 @@
CONFIG_DEVMEM=y
CONFIG_STATIC=y
CONFIG_BUSYBOX=y
CONFIG_FEATURE_PREFER_APPLETS=y
CONFIG_ASH=y
CONFIG_SH_IS_ASH=y
CONFIG_ASH_ECHO=y
CONFIG_ASH_TEST=y
CONFIG_ECHO=y
CONFIG_TRUE=y
CONFIG_FALSE=y
CONFIG_TEST=y
CONFIG_MOUNT=y
CONFIG_FEATURE_MOUNT_FLAGS=y
CONFIG_MKDIR=y
CONFIG_CAT=y
CONFIG_SLEEP=y
@@ -1,18 +1,15 @@
BR2_riscv=y
BR2_RISCV_32=y
BR2_RISCV_64=y
BR2_RISCV_ISA_RVM=y
BR2_RISCV_ISA_RVA=y
BR2_RISCV_ISA_RVF=y
BR2_RISCV_ISA_RVD=y
BR2_RISCV_ISA_RVC=y
BR2_RISCV_ABI_ILP32D=y
BR2_TOOLCHAIN_BUILDROOT_GLIBC=y
BR2_RISCV_ABI_LP64D=y
BR2_TOOLCHAIN_BUILDROOT_MUSL=y
BR2_STATIC_LIBS=y
BR2_TARGET_GENERIC_HOSTNAME="retrosoc-hp"
BR2_TARGET_GENERIC_ISSUE="retroSoC HP Linux"
BR2_INIT_BUSYBOX=y
BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_RETROSOC_HP_PATH)/busybox/retrosoc_hp.config"
BR2_TARGET_GENERIC_GETTY=y
BR2_TARGET_GENERIC_GETTY_PORT="hvc0"
BR2_INIT_NONE=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_RETROSOC_HP_PATH)/busybox/retrosoc_hp.config"
BR2_TARGET_ROOTFS_CPIO=y
BR2_TARGET_ROOTFS_CPIO_GZIP=y
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_RETROSOC_HP_PATH)/rootfs-overlay"
+49
View File
@@ -0,0 +1,49 @@
/* Linux-only acceptance helper; the freestanding SDK does not depend on libc. */
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
int main(int argc, char **argv) {
uint32_t error = 0U;
int descriptor;
void *mapping;
volatile uint32_t *mailbox;
if (argc == 2) {
if ((argv[1][0] == '1') && (argv[1][1] >= '1') && (argv[1][1] <= '7') &&
(argv[1][2] == '\0')) {
error = 10U + (uint32_t)(argv[1][1] - '0');
} else {
error = 20U;
}
} else if (argc != 1) {
error = 21U;
}
descriptor = open("/dev/mem", O_RDWR | O_SYNC);
if (descriptor < 0) {
(void)puts("HP_LINUX_INIT_FAILED devmem");
return 1;
}
mapping = mmap(NULL, 4096U, PROT_READ | PROT_WRITE, MAP_SHARED, descriptor, 0x10019000);
if (mapping == MAP_FAILED) {
(void)puts("HP_LINUX_INIT_FAILED mmap");
(void)close(descriptor);
return 1;
}
mailbox = (volatile uint32_t *)mapping;
if (error == 0U) {
(void)puts("retroSoC HP Linux ready");
} else {
(void)printf("HP_LINUX_INIT_FAILED code=%u\n", error);
}
(void)fflush(stdout);
mailbox[8] = (error == 0U) ? 1U : 3U;
mailbox[9] = (error == 0U) ? UINT32_C(0x4C4E5801) : error;
mailbox[10] = 1U;
__asm__ volatile("fence iorw, iorw" ::: "memory");
mailbox[11] = 1U;
for (;;) {
(void)pause();
}
}
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
# This bounded acceptance image deliberately has no service manager or getty.
export PATH=/bin
mount -t proc proc /proc || exec /bin/hp-ready 11
mount -t sysfs sysfs /sys || exec /bin/hp-ready 12
mount -t devtmpfs devtmpfs /dev || exec /bin/hp-ready 13
mount -t tmpfs tmpfs /tmp || exec /bin/hp-ready 14
test -c /dev/mem || exec /bin/hp-ready 15
test -r /proc/meminfo || exec /bin/hp-ready 16
test -d /sys/devices || exec /bin/hp-ready 17
echo rv64-initramfs > /tmp/probe || exec /bin/hp-ready 17
test "$(cat /tmp/probe)" = rv64-initramfs || exec /bin/hp-ready 17
/bin/busybox true || exec /bin/hp-ready 17
echo "HP_LINUX_INIT_PASS"
exec /bin/hp-ready
+12 -2
View File
@@ -1,17 +1,27 @@
CONFIG_ARCH_RV32I=y
CONFIG_ARCH_RV64I=y
CONFIG_64BIT=y
CONFIG_MMU=y
CONFIG_OF_RESERVED_MEM=y
CONFIG_NONPORTABLE=y
CONFIG_RISCV_ISA_M=y
CONFIG_RISCV_ISA_A=y
CONFIG_RISCV_ISA_C=y
CONFIG_FPU=y
CONFIG_SMP=n
CONFIG_PRINTK=y
CONFIG_TTY=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_HVC_RISCV_SBI=y
CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
CONFIG_SIFIVE_PLIC=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_GZIP=y
CONFIG_RD_GZIP=n
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DEVMEM=y
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
CONFIG_SHMEM=y
CONFIG_TMPFS=y
CONFIG_PRINTK_TIME=y
+15 -3
View File
@@ -6,7 +6,7 @@
#size-cells = <1>;
chosen {
bootargs = "console=hvc0 earlycon=sbi rdinit=/sbin/init";
bootargs = "console=hvc0 earlycon=sbi rdinit=/init";
linux,initrd-start = <0x39000000>;
/* build_hp_linux.py replaces this with the actual rootfs end. */
linux,initrd-end = <0x39000000>;
@@ -22,8 +22,8 @@
device_type = "cpu";
reg = <1>;
clock-frequency = <72000000>;
mmu-type = "riscv,sv32";
riscv,isa-base = "rv32i";
mmu-type = "riscv,sv39";
riscv,isa-base = "rv64i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicbom",
"zicsr", "zifencei";
riscv,cbom-block-size = <64>;
@@ -42,6 +42,18 @@
reg = <0x38000000 0x04000000>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
/* OpenSBI remains resident for every supervisor SBI call. */
opensbi@38000000 {
reg = <0x38000000 0x00080000>;
no-map;
};
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -104,7 +104,7 @@ static const struct sbi_platform_operations s_platform_operations = {
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(1U, 0U),
.name = "retroSoC RV32 HP",
.name = "retroSoC RV64 HP",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = 1U,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
@@ -1,11 +0,0 @@
#!/bin/sh
case "$1" in
start)
echo "retroSoC HP Linux ready"
devmem 0x10019020 32 0x00000001
devmem 0x10019024 32 0x4C4E5801
devmem 0x10019028 32 0x00000001
devmem 0x1001902C 32 0x00000001
;;
esac
+14 -14
View File
@@ -87,7 +87,7 @@ write_character:
lbu a1, 0(a0)
beqz a1, publish_ready
wait_tx_space:
lw a2, UART_STATUS(t0)
lwu a2, UART_STATUS(t0)
andi a2, a2, UART_TX_FULL
bnez a2, wait_tx_space
sw a1, UART_TXDATA(t0)
@@ -109,13 +109,13 @@ wait_start_command:
li s1, GA2D_WAIT_POLLS
wait_start_command_loop:
li t0, MAILBOX_BASE
lw t1, LP_SEQUENCE(t0)
lwu t1, LP_SEQUENCE(t0)
li t2, 1
bne t1, t2, wait_start_command_next
lw t1, LP_COMMAND(t0)
lwu t1, LP_COMMAND(t0)
li t2, HP_GA2D_START
bne t1, t2, wait_start_command_next
lw t1, LP_ARG0(t0)
lwu t1, LP_ARG0(t0)
li t2, HP_GA2D_ARG
beq t1, t2, start_ga2d
wait_start_command_next:
@@ -167,7 +167,7 @@ wait_cache_request:
li s1, GA2D_WAIT_POLLS
wait_cache_request_loop:
li t0, RESOURCE_CTRL_BASE
lw t1, RESOURCE_CACHE_CONTROL(t0)
lwu t1, RESOURCE_CACHE_CONTROL(t0)
andi t1, t1, 2
bnez t1, clean_cache_request
addi s1, s1, -1
@@ -351,7 +351,7 @@ ga2d_copy:
ga2d_wait:
li t1, GA2D_WAIT_POLLS
ga2d_wait_loop:
lw t2, GA2D_STATUS(t0)
lwu t2, GA2D_STATUS(t0)
andi t3, t2, 0x60
bnez t3, ga2d_wait_failed
andi t3, t2, 0x10
@@ -372,16 +372,16 @@ check_fill:
li t1, 0xff123456
li t2, 8
check_fill_pixels:
lw t3, 0(t0)
lwu t3, 0(t0)
bne t3, t1, check_failed
addi t0, t0, 4
addi t2, t2, -1
bnez t2, check_fill_pixels
lw t3, 0(t0)
lwu t3, 0(t0)
li t1, 0xc7c7c7c7
bne t3, t1, check_failed
la t0, hp_destination_guard
lw t3, 0(t0)
lwu t3, 0(t0)
li t1, 0xd3d3d3d3
bne t3, t1, check_failed
li a0, 1
@@ -392,22 +392,22 @@ check_copy:
la t1, hp_destination_line
li t2, 8
check_copy_pixels:
lw t3, 0(t0)
lw t4, 0(t1)
lwu t3, 0(t0)
lwu t4, 0(t1)
bne t3, t4, check_failed
addi t0, t0, 4
addi t1, t1, 4
addi t2, t2, -1
bnez t2, check_copy_pixels
lw t3, 0(t1)
lwu t3, 0(t1)
li t4, 0xc7c7c7c7
bne t3, t4, check_failed
la t0, hp_source_guard
lw t3, 0(t0)
lwu t3, 0(t0)
li t4, 0xa5a5a5a5
bne t3, t4, check_failed
la t0, hp_destination_guard
lw t3, 0(t0)
lwu t3, 0(t0)
li t4, 0xd3d3d3d3
bne t3, t4, check_failed
li a0, 1
+18
View File
@@ -0,0 +1,18 @@
# HP RT-Thread BSP
This directory owns the single-hart RV64 M-mode BSP and deterministic kernel
acceptance application. Upstream RT-Thread is installed at the revision in the
dependency lock under `.cache/`; it is not edited or copied into project source.
SCons runs on a staged BSP below `build/<variant>/hp-rtthread/`.
Run `make setup-hp-rtthread`, then `make CONFIG=configs/ci/ihp130-rtthread.mk
SIMU=VERILATOR hp-rtthread-sim`. The test uses UART1, hart-1 CLINT and PLIC
machine context 0/source 2. Peripheral accesses remain 32 bits. Static threads
exercise RV64 integer state, timer preemption, semaphore/message queue behavior,
timeouts, and an LP-to-HP mailbox interrupt. LP validates the final mailbox
response and owns SYSCTRL TEST_STATUS. A banner alone is not a pass.
The authoritative contract is [HP platform](../../../docs/ip/hp-platform.md).
RT-Smart, networking, filesystems, floating-point task qualification, and PPA
are outside this test. Self-owned C follows the repository C policy; the locked
upstream OS is third-party material. No operating-system dependency enters crt.
+8
View File
@@ -0,0 +1,8 @@
from building import DefineGroup, GetCurrentDir
group = DefineGroup('RetroSoC', ['board.c', 'selftest.c', 'start.S'], depend=[''],
CPPPATH=[GetCurrentDir()], LOCAL_CFLAGS=' -Wextra -Werror')
# PrepareBuilding extends the returned list with kernel objects. Keep it separate
# from DefineGroup's per-group source list used for LOCAL_CFLAGS.
objects = list(group)
Return('objects')
+20
View File
@@ -0,0 +1,20 @@
import os
import sys
import rtconfig
RTT_ROOT = os.environ['RTT_ROOT']
sys.path.insert(0, os.path.join(RTT_ROOT, 'tools'))
from building import PrepareBuilding, DoBuilding
DefaultEnvironment(tools=[])
env = Environment(tools=['gcc', 'g++', 'gnulink', 'ar', 'gas'],
CC=rtconfig.CC, CXX=rtconfig.CXX, AS=rtconfig.AS, AR=rtconfig.AR,
LINK=rtconfig.LINK, CFLAGS=rtconfig.CFLAGS, ASFLAGS=rtconfig.AFLAGS,
LINKFLAGS=rtconfig.LFLAGS, LIBS=['gcc'])
env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
env.Append(CPPPATH=[Dir('.').abspath,
os.path.join(os.environ['RETROSOC_ROOT'], 'app/apps/hp_boot')])
env['ASCOM'] = env['ASPPCOM']
Export('RTT_ROOT', 'rtconfig')
objects = PrepareBuilding(env, RTT_ROOT)
DoBuilding('rtthread.elf', objects)
+185
View File
@@ -0,0 +1,185 @@
#include "board.h"
#include "hp_boot_bundle.h"
#include <rthw.h>
#define RS_RTT_UART UINT32_C(0x10018000)
#define RS_RTT_CLINT UINT32_C(0x02000000)
#define RS_RTT_PLIC UINT32_C(0x0C000000)
#define RS_RTT_MAILBOX UINT32_C(0x10019000)
static struct rt_semaphore s_mailbox_sem;
static volatile uint32_t s_irq_command;
static volatile uint32_t s_irq_argument;
static volatile uint32_t s_irq_sequence;
static uint64_t s_next_tick;
static uint32_t rs_read32(uint32_t address) {
return *(volatile const uint32_t *)(uintptr_t)address;
}
static void rs_write32(uint32_t address, uint32_t value) {
*(volatile uint32_t *)(uintptr_t)address = value;
}
static uint64_t rs_time(void) {
uint32_t high;
uint32_t low;
do {
high = rs_read32(RS_RTT_CLINT + UINT32_C(0xBFFC));
low = rs_read32(RS_RTT_CLINT + UINT32_C(0xBFF8));
} while (high != rs_read32(RS_RTT_CLINT + UINT32_C(0xBFFC)));
return ((uint64_t)high << 32U) | low;
}
static void rs_set_timer(uint64_t value) {
rs_write32(RS_RTT_CLINT + UINT32_C(0x4008), UINT32_MAX);
rs_write32(RS_RTT_CLINT + UINT32_C(0x400C), (uint32_t)(value >> 32U));
rs_write32(RS_RTT_CLINT + UINT32_C(0x4008), (uint32_t)value);
__asm__ volatile("fence iorw, iorw" ::: "memory");
}
void rt_hw_console_output(const char *text) {
while (*text != '\0') {
uint32_t budget = UINT32_C(1000000);
while ((rs_read32(RS_RTT_UART + UINT32_C(0x18)) & UINT32_C(0x20)) != 0U) {
if (--budget == 0U) {
(void)rt_hw_interrupt_disable();
rs_rtt_publish(3U, 90U, 2U);
/* Keep the failure publication stable until LP terminates. */
for (;;) {
__asm__ volatile("wfi");
}
}
}
rs_write32(RS_RTT_UART + UINT32_C(0x10), (uint8_t)*text);
++text;
}
}
void rs_rtt_publish(uint32_t event, uint32_t argument, uint32_t sequence) {
rs_write32(RS_RTT_MAILBOX + UINT32_C(0x20), event);
rs_write32(RS_RTT_MAILBOX + UINT32_C(0x24), argument);
rs_write32(RS_RTT_MAILBOX + UINT32_C(0x28), sequence);
__asm__ volatile("fence iorw, iorw" ::: "memory");
rs_write32(RS_RTT_MAILBOX + UINT32_C(0x2C), 1U);
}
void rs_rtt_fail(uint32_t code) {
(void)rt_hw_interrupt_disable();
rt_kprintf("RTTHREAD_TEST_FAIL code=%u\n", code);
rs_rtt_publish(3U, code, 2U);
for (;;) {
__asm__ volatile("wfi");
}
}
static void rs_assert(const char *expression, const char *function, rt_size_t line) {
(void)expression;
(void)function;
(void)line;
rs_rtt_fail(91U);
}
void rt_trigger_software_interrupt(void) {
rs_write32(RS_RTT_CLINT + UINT32_C(4), 1U);
}
void rt_hw_do_after_save_above(void) {
rs_write32(RS_RTT_CLINT + UINT32_C(4), 0U);
}
void handle_trap(rt_ubase_t cause, rt_ubase_t epc, void *frame) {
(void)frame;
if ((cause >> 63U) == 0U) {
rt_kprintf("RTTHREAD_TRAP cause=%lx epc=%lx\n", cause, epc);
rs_rtt_fail(92U);
}
switch (cause & UINT64_C(0x7FFFFFFFFFFFFFFF)) {
case 3U:
rt_hw_do_after_save_above();
break;
case 7U:
s_next_tick += UINT64_C(1000);
if (s_next_tick <= rs_time()) {
s_next_tick = rs_time() + UINT64_C(1000);
}
rs_set_timer(s_next_tick);
rt_tick_increase();
break;
case 11U: {
uint32_t claim = rs_read32(RS_RTT_PLIC + UINT32_C(0x200004));
if (claim != 2U) {
rs_rtt_fail(93U);
}
s_irq_command = rs_read32(RS_RTT_MAILBOX + UINT32_C(0x10));
s_irq_argument = rs_read32(RS_RTT_MAILBOX + UINT32_C(0x14));
s_irq_sequence = rs_read32(RS_RTT_MAILBOX + UINT32_C(0x18));
rs_write32(RS_RTT_MAILBOX + UINT32_C(0x40), 1U);
__asm__ volatile("fence iorw, iorw" ::: "memory");
rs_write32(RS_RTT_PLIC + UINT32_C(0x200004), claim);
if (rt_sem_release(&s_mailbox_sem) != RT_EOK) {
rs_rtt_fail(94U);
}
break;
}
default:
rs_rtt_fail(95U);
break;
}
}
rt_err_t rs_rtt_wait_mailbox(rt_int32_t timeout) {
rt_err_t result = rt_sem_take(&s_mailbox_sem, timeout);
if (result != RT_EOK) {
return result;
}
return ((s_irq_command == RS_HP_RTTHREAD_IRQ_COMMAND) &&
(s_irq_argument == RS_HP_RTTHREAD_IRQ_ARG) && (s_irq_sequence == 1U))
? RT_EOK
: -RT_ERROR;
}
void rt_hw_board_init(void) {
rs_write32(RS_RTT_UART + UINT32_C(0x0C), 0U);
rs_write32(RS_RTT_UART + UINT32_C(0x20), 3U);
rs_write32(RS_RTT_UART + UINT32_C(0x30), UINT32_C(0x7F));
rs_write32(RS_RTT_UART + UINT32_C(0x38), 0U);
rs_write32(RS_RTT_UART, 78U);
rs_write32(RS_RTT_UART + UINT32_C(4), 32U);
rs_write32(RS_RTT_UART + UINT32_C(8), 3U);
rs_write32(RS_RTT_UART + UINT32_C(0x0C), 3U);
rs_write32(RS_RTT_CLINT + UINT32_C(4), 0U);
rs_write32(RS_RTT_MAILBOX + UINT32_C(0x40), 1U);
rs_write32(RS_RTT_MAILBOX + UINT32_C(0x44), 1U);
rs_write32(RS_RTT_PLIC + UINT32_C(8), 1U);
rs_write32(RS_RTT_PLIC + UINT32_C(0x2000), 4U);
rs_write32(RS_RTT_PLIC + UINT32_C(0x200000), 0U);
s_next_tick = rs_time() + UINT64_C(1000);
rs_set_timer(s_next_tick);
__asm__ volatile("csrw mie, %0" : : "r"(UINT64_C(0x888)) : "memory");
}
void rt_hw_cpu_shutdown(void) {
rs_rtt_fail(96U);
}
void rs_rtt_start(void) {
uint64_t hart;
_Static_assert(sizeof(rt_ubase_t) == 8U, "RT-Thread must use RV64 contexts");
_Static_assert(IDLE_THREAD_STACK_SIZE >= 1024, "Idle stack must fit RV64+D frame and calls");
__asm__ volatile("csrr %0, mhartid" : "=r"(hart));
rt_assert_set_hook(rs_assert);
rt_system_timer_init();
rt_system_scheduler_init();
if ((hart != 1U) || (rt_sem_init(&s_mailbox_sem, "hp_irq", 0U, RT_IPC_FLAG_FIFO) != RT_EOK)) {
rs_rtt_fail(97U);
}
rt_hw_board_init();
rt_show_version();
rt_kprintf("HP_RTTHREAD_BOOT hart=1 xlen=64 mode=M\n");
rs_rtt_selftest_init();
rt_thread_idle_init();
rt_system_scheduler_start();
rs_rtt_fail(98U);
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef RETROSOC_RTTHREAD_BOARD_H
#define RETROSOC_RTTHREAD_BOARD_H
#include <stdint.h>
#include <rtthread.h>
void rs_rtt_start(void);
void rs_rtt_selftest_init(void);
void rs_rtt_fail(uint32_t code);
void rs_rtt_publish(uint32_t event, uint32_t argument, uint32_t sequence);
uint32_t rs_rtt_context_probe(uint64_t value);
rt_err_t rs_rtt_wait_mailbox(rt_int32_t timeout);
void handle_trap(rt_ubase_t cause, rt_ubase_t epc, void *frame);
void rt_trigger_software_interrupt(void);
void rt_hw_do_after_save_above(void);
void rt_hw_console_output(const char *text);
void rt_hw_board_init(void);
void rt_hw_cpu_shutdown(void);
#endif
+16
View File
@@ -0,0 +1,16 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
MEMORY { RAM (rwx) : ORIGIN = 0x38000000, LENGTH = 512K }
PHDRS { text PT_LOAD FLAGS(5); data PT_LOAD FLAGS(6); }
SECTIONS {
.text : { KEEP(*(.text.start)) *(.text*) *(.rodata*) } > RAM :text
.data : { . = ALIGN(16); __global_pointer$ = . + 0x800; *(.sdata*) *(.data*) } > RAM :data
.bss (NOLOAD) : {
. = ALIGN(16); __bss_start = .;
*(.sbss*) *(.bss*) *(COMMON)
. = ALIGN(16); __bss_end = .;
} > RAM
.stack (NOLOAD) : { . = ALIGN(16); . += 8192; __rt_rvstack = .; } > RAM
/DISCARD/ : { *(.eh_frame*) *(.comment*) }
ASSERT(. <= ORIGIN(RAM) + LENGTH(RAM), "RT-Thread exceeds HP RAM budget")
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef RETROSOC_RTTHREAD_CONFIG_H
#define RETROSOC_RTTHREAD_CONFIG_H
#define ARCH_CPU_64BIT
#define RT_CPUS_NR 1
#define RT_NAME_MAX 12
#define RT_ALIGN_SIZE 16
#define RT_THREAD_PRIORITY_MAX 32
#define RT_TICK_PER_SECOND 1000
#define RT_USING_OVERFLOW_CHECK
#define RT_DEBUG
#define RT_DEBUGING_ASSERT
#define RT_BACKTRACE_LEVEL_MAX_NR 32
#define RT_USING_SEMAPHORE
#define RT_USING_MESSAGEQUEUE
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 256
#define IDLE_THREAD_STACK_SIZE 2048
#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
/* No scanf caller is linked; avoid the heap-dependent internal scanner. */
#define RT_KLIBC_USING_LIBC_VSSCANF
#endif
+17
View File
@@ -0,0 +1,17 @@
"""Board-specific settings consumed by the locked RT-Thread build system."""
import os
ARCH = 'risc-v'
CPU = 'retrosoc'
CROSS_TOOL = PLATFORM = 'gcc'
EXEC_PATH = os.environ['RTT_EXEC_PATH']
PREFIX = 'riscv64-unknown-elf-'
CC = AS = LINK = PREFIX + 'gcc'
CXX = PREFIX + 'g++'
AR = PREFIX + 'ar'
TARGET_EXT = 'elf'
DEVICE = '-march=rv64imafdc_zicbom_zicsr_zifencei -mabi=lp64d -mcmodel=medany'
CFLAGS = DEVICE + ' -O2 -g -ffreestanding -fno-builtin -ffunction-sections -fdata-sections -Wall'
AFLAGS = DEVICE + ' -g -x assembler-with-cpp'
LFLAGS = DEVICE + ' -nostdlib -nostartfiles -Wl,--gc-sections,-Map=rtthread.map -T linker.ld'
POST_ACTION = PREFIX + 'objcopy -O binary $TARGET rtthread.bin'
+100
View File
@@ -0,0 +1,100 @@
#include "board.h"
#include "hp_boot_bundle.h"
#include <rthw.h>
static struct rt_thread s_controller;
static struct rt_thread s_producer;
static struct rt_thread s_consumer;
static struct rt_semaphore s_done;
static struct rt_messagequeue s_queue;
static uint8_t s_controller_stack[4096] __attribute__((aligned(16)));
static uint8_t s_producer_stack[4096] __attribute__((aligned(16)));
static uint8_t s_consumer_stack[4096] __attribute__((aligned(16)));
static uint8_t s_queue_pool[128] __attribute__((aligned(16)));
static volatile uint32_t s_busy_iterations;
static volatile uint32_t s_preempted;
static volatile uint64_t s_memory_probe;
static void rs_require(bool condition, uint32_t code) {
if (!condition) {
rs_rtt_fail(code);
}
}
static void rs_producer(void *argument) {
rt_tick_t start = rt_tick_get();
(void)argument;
while (s_preempted == 0U) {
++s_busy_iterations;
rs_require((rt_tick_get() - start) < 100U, 10U);
}
rs_require(rs_rtt_context_probe(UINT64_C(0xFEDCBA9876543210)) == 0U, 11U);
for (uint64_t index = 0U; index < 8U; ++index) {
uint64_t value = UINT64_C(0x1234567800000000) | index;
rs_require(rt_mq_send_wait(&s_queue, &value, sizeof(value), 100) == RT_EOK, 12U);
}
rs_require(rt_sem_release(&s_done) == RT_EOK, 13U);
}
static void rs_consumer(void *argument) {
(void)argument;
rs_require(rt_thread_delay(2) == RT_EOK, 20U);
rs_require(s_busy_iterations != 0U, 21U);
s_preempted = 1U;
rs_require(rs_rtt_context_probe(UINT64_C(0x13579BDF2468ACE0)) == 0U, 22U);
for (uint64_t index = 0U; index < 8U; ++index) {
uint64_t value = 0U;
rs_require(rt_mq_recv(&s_queue, &value, sizeof(value), 100) == (rt_ssize_t)sizeof(value),
23U);
rs_require(value == (UINT64_C(0x1234567800000000) | index), 24U);
}
rs_require(rt_sem_release(&s_done) == RT_EOK, 25U);
}
static void rs_controller(void *argument) {
uint64_t input = UINT64_C(0x123456789ABCDEF0);
uint64_t value = 0U;
rt_tick_t start;
(void)argument;
s_memory_probe = input;
rs_require(((s_memory_probe >> 32U) == UINT64_C(0x12345678)) &&
((s_memory_probe * 3U) / 3U == input),
1U);
rt_kprintf("RTTHREAD_RV64_PASS\n");
rs_require(rt_sem_init(&s_done, "done", 0U, RT_IPC_FLAG_FIFO) == RT_EOK, 2U);
rs_require(rt_mq_init(&s_queue, "mq", s_queue_pool, sizeof(value), sizeof(s_queue_pool),
RT_IPC_FLAG_FIFO) == RT_EOK,
3U);
start = rt_tick_get();
rs_require(rt_sem_take(&s_done, 2) == -RT_ETIMEOUT, 4U);
rs_require((rt_tick_get() - start) >= 2U, 5U);
rs_require(rt_mq_recv(&s_queue, &value, sizeof(value), 2) == -RT_ETIMEOUT, 6U);
rt_kprintf("RTTHREAD_TIMEOUT_PASS\n");
rs_require(rt_thread_startup(&s_consumer) == RT_EOK, 7U);
rs_require(rt_thread_startup(&s_producer) == RT_EOK, 8U);
rs_require(rt_sem_take(&s_done, 200) == RT_EOK, 30U);
rs_require(rt_sem_take(&s_done, 200) == RT_EOK, 31U);
rs_require(s_preempted == 1U, 32U);
rt_kprintf("RTTHREAD_PREEMPT_PASS\nRTTHREAD_CONTEXT_PASS\nRTTHREAD_IPC_PASS\n");
rs_rtt_publish(1U, RS_HP_RTTHREAD_READY_ARG, 1U);
rs_require(rs_rtt_wait_mailbox(1000) == RT_EOK, 33U);
rt_kprintf("RTTHREAD_MAILBOX_IRQ_PASS\nRTTHREAD_TEST_PASS\n");
rs_rtt_publish(2U, RS_HP_RTTHREAD_READY_ARG, 2U);
for (;;) {
(void)rt_thread_delay(100);
}
}
void rs_rtt_selftest_init(void) {
rs_require(rt_thread_init(&s_controller, "test", rs_controller, RT_NULL, s_controller_stack,
sizeof(s_controller_stack), 5U, 1U) == RT_EOK,
40U);
rs_require(rt_thread_init(&s_consumer, "recv", rs_consumer, RT_NULL, s_consumer_stack,
sizeof(s_consumer_stack), 10U, 1U) == RT_EOK,
41U);
rs_require(rt_thread_init(&s_producer, "send", rs_producer, RT_NULL, s_producer_stack,
sizeof(s_producer_stack), 20U, 1U) == RT_EOK,
42U);
rs_require(rt_thread_startup(&s_controller) == RT_EOK, 43U);
}
+66
View File
@@ -0,0 +1,66 @@
.section .text.start
.global _start
_start:
csrw mie, zero
csrw satp, zero
li t0, 0x6000
csrw mstatus, t0
.option push
.option norelax
la gp, __global_pointer$
.option pop
la sp, __rt_rvstack
la t0, __bss_start
la t1, __bss_end
1:
bgeu t0, t1, 2f
sd zero, 0(t0)
addi t0, t0, 8
j 1b
2:
la t0, trap_entry
csrw mtvec, t0
csrw mscratch, sp
call rs_rtt_start
3:
wfi
j 3b
.section .text
.global rs_rtt_context_probe
rs_rtt_context_probe:
addi sp, sp, -48
sd ra, 0(sp)
sd s0, 8(sp)
sd s1, 16(sp)
sd s2, 24(sp)
sd s3, 32(sp)
sd a0, 40(sp)
mv s0, a0
mv s2, a0
not s3, a0
li s1, 8
1:
li a0, 1
call rt_thread_delay
# Compare against memory, so identical truncation of saved registers cannot
# accidentally satisfy a register-to-register comparison.
ld t1, 40(sp)
bne s0, t1, 2f
bne s2, t1, 2f
not t0, t1
bne t0, s3, 2f
addi s1, s1, -1
bnez s1, 1b
li a0, 0
j 3f
2:
li a0, 1
3:
ld ra, 0(sp)
ld s0, 8(sp)
ld s1, 16(sp)
ld s2, 24(sp)
ld s3, 32(sp)
addi sp, sp, 48
ret
+4 -5
View File
@@ -18,11 +18,10 @@ from 32 KiB on-chip SRAM, enables VexiiRiscv `Zicbom` with 64-byte blocks, and
generates VexiiRiscv RTL only below the selected build variant. It is not part
of the supported PR matrix until Linux boot, HP performance, synthesis, and
timing evidence are qualified.
`ci/ihp130-apu.mk` is the APU LP/HP evidence profile. It runs `apu_release`
from PSRAM, stages the embedded APUMC/APUM/WAV/KWS assets through SDRAM,
performs the LP-only image loads, hands APU ownership to the HP hart, and
checks HP-submitted WAV/KWS jobs plus the LP-only register fault probe in the
full-SoC Verilator simulation via `hp-apu-sim`.
`ci/ihp130-rtthread.mk` selects the same RV64 HP hardware and LP loader for
the pinned RT-Thread M-mode selftest. Run `make setup-hp-rtthread`, then
`make CONFIG=configs/ci/ihp130-rtthread.mk SIMU=VERILATOR hp-rtthread-sim`.
All PRODUCT profiles use `rv64imafdc_zicbom_max`; LP compiler/ISA remain RV32.
`ci/ihp130-xpi-flash-loader.mk` builds the SRAM-only XPI NOR service image used
by GDB/OpenOCD; it is a programming utility, not a normal boot application.
Start builds from a committed profile rather than setting an unreviewed mix of
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
AUD_CLK_HZ := 18432000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
AUD_CLK_HZ := 18432000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
+1 -1
View File
@@ -3,7 +3,7 @@ MINI_MODE := PRODUCT
PDK := IHP130
HAVE_PLL := NO
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
+22
View File
@@ -0,0 +1,22 @@
# RV64 HP RT-Thread acceptance; LP remains the RV32 management loader.
SOC := MINI
MINI_MODE := PRODUCT
PDK := IHP130
HAVE_PLL := NO
HAVE_HP := YES
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
PDK_BEHAV := YES
EXT_CLK_HZ := 72000000
AUD_CLK_HZ := 18432000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := YES
APP := hp_boot
LINK_TYPE := ld2_all_sram
SIM_SUCCESS_MARKER := SIM_TEST_PASS
RTL_SIM_TIMEOUT := 20000000
FIRMWARE_NAME := retrosoc_hp_boot
SIM_FIRMWARE_NAME := retrosoc_hp_boot
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
AUD_CLK_HZ := 18432000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
AUD_CLK_HZ := 18432000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
AUD_CLK_HZ := 18432000
+1 -1
View File
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
SRAM_SIZE_KIB := 32
HAVE_HP := YES
HP_CONFIG := rv32imafdc_zicbom_max
HP_CONFIG := rv64imafdc_zicbom_max
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
AUD_CLK_HZ := 18432000
+4 -4
View File
@@ -50,11 +50,11 @@ static void rs_print_hp_core_spec(void) {
printf("\nHigh-Performance-Core Specification:\n");
printf(" Identity\n");
printf(" Core: VexiiRiscv(hart 1), dual-issue in-order\n");
printf(" Role: high-throughput application and Linux\n");
printf(" Role: application, RT-Thread and Linux\n");
printf(" Source: https://github.com/SpinalHDL/VexiiRiscv\n");
printf(" Hardware ISA and privilege\n");
printf(" Base: RV32IMAFDC_Zicbom_Zicntr_Zihpm\n");
printf(" Mode: M/S/U; Sv32 MMU, 9-bit ASID\n");
printf(" Base: RV64IMAFDC_Zicbom_Zicntr_Zihpm\n");
printf(" Mode: M/S/U; Sv39 MMU, 9-bit ASID\n");
printf(" Protection: 16 PMP regions, 4 KiB granularity\n");
printf(" IRQ: machine software/timer/external + supervisor external\n");
printf(" Microarchitecture\n");
@@ -63,7 +63,7 @@ static void rs_print_hp_core_spec(void) {
printf(" Cache and memory\n");
printf(" L1: separate 16 KiB, 4-way instruction and data caches\n");
printf(" Maintenance: 64-byte Zicbom CBO; no hardware coherency\n");
printf(" Bus: native AXI64 I/D + cacheless AXI32 MMIO\n");
printf(" Bus: native AXI64 I/D/MMIO; MMIO downsized to AXI32\n");
printf(" Debug\n");
printf(" Embedded RISC-V JTAG, 4 triggers\n");
printf(" Runtime\n");
+7
View File
@@ -38,6 +38,13 @@ accepted. Java 17 is a host runtime supplied by Docker, Nix, or the documented
Ubuntu prerequisites. No generated CPU RTL or Linux build output belongs in
Git.
`rtthread_hp` pins official RT-Thread v5.3.0 at
`99428a1e7f7447955aa860f7c969273a12095b8f`. `make setup-hp-rtthread` installs
that source, the checksum-locked `riscv_gnu_hp` RV64 compiler, and the hashed
SCons requirement in a local virtual environment. The BSP is copied into the
build variant and uses the upstream kernel/CPU port without modifying it.
The LP SDK retains its existing RV32 toolchain.
The libjpeg-turbo source archive is a host-verification input for the JPEG
accelerator. It supplies an implementation-independent interoperability oracle;
it is not linked into firmware or synthesized RTL. The repository-owned fixed
+13
View File
@@ -27,6 +27,12 @@
"recursive": true,
"license": "MIT"
},
"rtthread_hp": {
"url": "https://github.com/RT-Thread/rt-thread.git",
"revision": "99428a1e7f7447955aa860f7c969273a12095b8f",
"destination": ".cache/retrosoc/sources/rtthread-hp",
"license": "Apache-2.0"
},
"opensbi_hp": {
"url": "https://github.com/riscv-software-src/opensbi.git",
"revision": "cbf9f6734dd85a982c63e3cb5db7ffe09da839ca",
@@ -386,6 +392,13 @@
"download_timeout_seconds": 600,
"resume": true
},
"riscv_gnu_hp": {
"version": "2025.05.01",
"url": "https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.05.01/riscv64-elf-ubuntu-22.04-gcc-nightly-2025.05.01-nightly.tar.xz",
"sha256": "57da2f16e772674ef0202b37217ccdcba3787e1a055ca92a83c9a5b240bca7d1",
"archive": "riscv64-elf-ubuntu-22.04-gcc-nightly-2025.05.01-nightly.tar.xz",
"path": "riscv/bin"
},
"riscv_gnu": {
"version": "2025.05.01",
"url": "https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.05.01/riscv32-elf-ubuntu-22.04-gcc-nightly-2025.05.01-nightly.tar.xz",
+2
View File
@@ -86,6 +86,8 @@ the root README and subsystem guides.
clock/pad/fault/performance/RTC/test contracts, HAL, and verification.
- [ip/hp-platform.md](ip/hp-platform.md) defines the experimental HP PLIC and
LP/HP mailbox register, interrupt, software, and verification contracts.
- [hp-rv64-validation.md](hp-rv64-validation.md) records RV64 core, V2 bundle,
RT-Thread/Linux acceptance evidence and deferred gates.
- [ip/onchip-sram.md](ip/onchip-sram.md) defines the configurable native-AXI4
SRAM architecture, APB capability ABI, technology mapping, verification, and
reliability roadmap.
+158
View File
@@ -0,0 +1,158 @@
# HP RV64 Migration Validation
The active contract is [HP platform](ip/hp-platform.md), phases 2–5. LP remains
RV32 Hazard3. All PRODUCT profiles select RV64IMAFDC with Zicbom, Sv39 and
32-bit physical addresses. No upstream CPU or RT-Thread source is modified.
## Reproduction
```sh
make setup-vexiiriscv setup-hp-rtthread setup-hp-linux
make CONFIG=configs/ci/ihp130-hp.mk SIMU=VERILATOR hp-smoke-sim
make CONFIG=configs/ci/ihp130-rtthread.mk SIMU=VERILATOR hp-rtthread-sim
make CONFIG=configs/ci/ihp130-hp.mk SIMU=VERILATOR hp-linux-sim
python3 scripts/regress.py --root . --suite pr --pdk IHP130 --behavioral-only
```
`HP_CROSS` is independent of LP `CROSS` and resolves to the compiler in the
dependency lock. RT-Thread is official v5.3.0 at
`99428a1e7f7447955aa860f7c969273a12095b8f`, compiled with RV64 `lp64d`.
Its selftest qualifies integer contexts; it does not qualify FCSR preservation
or floating-point tasks. Linux uses its Buildroot RV64 Linux compiler, Sv39,
static musl/BusyBox and a small uncompressed CPIO with a dedicated `/init`.
V2 flash bundles discriminate Linux (1, four entries), smoke (2, one executable)
and RT-Thread (3, one executable). Rebuild V1 bundles. The loader checks strict
flags, workload/count/types, fixed addresses, bounds, non-overlap, unused slots
and CRC. Only smoke enters the GA2D/cache lifecycle protocol. LP alone owns
the final SYSCTRL TEST_STATUS write for all workloads.
## Measured runs
Initial RV64 validation uses `configs/ci/ihp130-hp.mk` and
`BUILD_TIMESTAMP=2026-09-25-11-42`, producing
`build/ihp130-hp-2026-09-25-11-42-bb2e93b39338/`.
| Run | Result | Evidence below variant |
| --- | --- | --- |
| RV64 generated core and Verilator compile | Pass | `generated/vexiiriscv/manifest.json`, `sim/verilator/result-compile.json` |
| GA2D/cache lifecycle smoke | `SIM_TEST_PASS code=0`, 3,446,054 cycles, 191 seconds | `sim/verilator/sim.log`, `result-hp-smoke-sim-check.json` in the same directory |
| RT-Thread kernel/platform | All required markers and `SIM_TEST_PASS code=0`, 6,412,946 cycles, 360 seconds | `sim/verilator/hp-rtthread/sim.log`, `result-sim-check.json` |
The final dedicated `configs/ci/ihp130-rtthread.mk` profile passed all markers
and TEST_STATUS at 6,395,372 cycles in 357 seconds, using
`BUILD_TIMESTAMP=2026-09-25-12-18`. Its evidence is
`build/ihp130-rtthread-2026-09-25-12-18-bb2e93b39338/sim/verilator/hp-rtthread/`.
The final context probe compares registers against an original 64-bit sentinel
stored on each task's stack, catching identical truncation of multiple registers.
The final smoke also passed at 3,460,934 cycles in 195 seconds, with evidence
in `sim/verilator/hp-smoke/` under the initial variant.
Linux Image is 2,152,448 bytes; the static, uncompressed CPIO is 302,080 bytes.
BusyBox is expanded from `allnoconfig` and an explicit allowlist; effective
options and static ELF linkage are checked. Linux acceptance is still running
without an emulator wall-clock timeout; no Linux pass is claimed yet. New workload runs
write logs to `sim/verilator/hp-{smoke,rtthread,linux}/`. Structured results
start as `running`; failures/interruption replace old passes. A UART banner is
diagnostic, never the final verdict.
The affected Python and publication bindings pass 177 tests; one PDF-inspection
test is skipped because `pypdf` is not installed. C format, C policy and host
tests, Ruff, dependency-lock validation, `setup-hp-rtthread` and the dedicated
profile's Verilator doctor pass. The final publication-focused run passes 193
tests with one missing-`pypdf` skip. The full Python run reports 974 passed and
5 skipped; its two missing-FLAC-corpus failures were resolved by installing the
checksum-locked corpus and rerunning both tests (2 passed). Thus 976 cases have
passing evidence. The other skips are optional P7 model/MFCC inputs; no test
expectation was weakened to hide a missing input. After the firmware-reservation
correction, all 62 affected platform and publication checks pass.
The IHP130 behavioral PR regression completed successfully with
`BUILD_TIMESTAMP=2026-09-25-12-14`: strict lint, firmware builds, Verilator
`ci_smoke` (6,783,746 cycles, 384 seconds), `DEBUG_GDB_PASS`, and Icarus
`SIM_TEST_PASS`. Artifacts use `build/ihp130-2026-09-25-12-14-*` and
`build/ihp130-debug-2026-09-25-12-14-*`. Warning-baseline comparisons report
new/increased signatures as non-blocking observations; baselines were not
modified. No synthesis or STA result is implied by this regression.
## RT-Thread first-schedule failure and correction
The first BSP run reached `HP_RTTHREAD_BOOT` and then reported
`RTTHREAD_TRAP cause=1 epc=deadbeee`, failure 92, followed by LP failure 18.
Evidence is retained in `sim/verilator/hp-rtthread-idle-stack-failure/` under
the initial variant. This was a BSP integration error:
1. The BSP used `RT_IDLE_THREAD_STACK_SIZE`; the locked upstream `src/idle.c`
reads `IDLE_THREAD_STACK_SIZE` and otherwise selects 128 bytes without heap.
2. The failing ELF's `idle_thread_stack` was 128 bytes at `0x38004530`.
Upstream `rt_hw_stack_init` reserves 512 bytes for 32 RV64 integer slots
and 32 double-precision slots, filling them with `0xdeadbeef`.
3. That frame starts at `0x380043b0`, 384 bytes before the allocated stack,
overwriting `_object_container`, interrupt-switch state, the scheduler's
ready bitmap and other globals. This explains the invalid first-schedule
state and is independent of the AXI crossbar.
4. The BSP now uses the correct macro with 2048 bytes and a compile-time lower
bound. The same integrated test then passed scheduling, RV64 context, IPC,
timer timeout, and mailbox IRQ checks. Vendor source stayed unchanged.
## Linux firmware reservation correction
The first RV64 run reached Linux 6.12.105 and memory initialization. Its log
reported no `/reserved-memory` node and included the full SDRAM range beginning
at `0x38000000`. OpenSBI's preceding PMP report protected its resident code/data
from S-mode. Static inspection confirmed that the custom platform has no generic
`fdt_fixups()` final-init hook; Linux `arch/riscv/mm/init.c:setup_bootmem` reserves
the kernel, initrd, DTB and DT-declared regions, not an implicit firmware window.
Thus the DT omitted a live firmware allocation. No resulting crash was observed;
the run was deliberately interrupted to correct this integration defect.
The retained log is `sim/verilator/hp-linux-before-firmware-reservation/` under
the initial variant. The DT now reserves the complete, already allocated
512 KiB OpenSBI window with `no-map`, and the effective-config guard requires
`CONFIG_OF_RESERVED_MEM=y`. The DTB test checks both the exact range and
`no-map`. The corrected runtime now prints
`0x0000000038000000..0x000000003807ffff (512 KiB) nomap non-reusable opensbi@38000000`,
confirming that Linux consumed the reservation. Userspace acceptance is still
in progress.
During the subsequent quiet `Initmem setup node 0` interval, two read-only host
debugger samples captured 64,772,063 and 66,503,381 emulator cycles. The sampled
Sv39 PCs resolve to `__init_single_page` and `memmap_init_range` in the actual
`vmlinux`; disassembly passes `s0` as the PFN and increments it at loop end.
`s0` advanced from `0x3b0c4` to `0x3b6ed`, toward the `s1=0x3c000` bound.
Privilege remained S-mode and SATP mode was 8. This establishes loop progress
during that interval, not a complete boot verdict. Samples and disassembly are
retained under `meta/hp-rv64-validation/`; no DUT state was written.
Later samples at 84,162,019 and 92,239,597 cycles resolve to
`should_skip_region` / `__next_mem_range` and `__free_pages_ok` called by
`memblock_free_all`, respectively. A further sample at 97,866,745 cycles is in
`__free_pages_core`, with a later page-descriptor block address. These locate
the later allocator work separately from the earlier page-descriptor loop.
After IRQ initialization, samples landed in timer handling. The interrupted
SEPC then moved from `memset` to `add_device_randomness`; the latter frame was
decoded from valid, matching-tag L1 data-cache lines and checked against the
RISC-V `pt_regs` layout. UART subsequently reported the 9-bit ASID allocator.
These observations avoid treating an IRQ-handler PC or stale raw SDRAM as
evidence of main-thread progress.
## Coverage limits
The repository's mechanical C format/policy checks are partial MISRA evidence;
no complete MISRA certification or new approved Required-rule deviation is
claimed. Board MMIO uses fixed, naturally aligned 32-bit accesses to declared
register windows; RV64 pointer width does not widen device accesses.
Synthesis, netlist simulation, STA and synthesis-dependent metrics are deferred
by explicit user instruction. PPA, CDC/RDC, physical SRAM mapping, hardware
board runs and silicon qualification are not established by these simulations.
The behavioral evidence is IHP130-specific; other PDK matrices and extended
nightly benchmarking were not rerun in this migration.
The GDB regression exercises LP Hazard3 debug; it is not independent RV64 HP
debug/JTAG qualification.
The minimal Linux configuration leaves `CONFIG_RISCV_ISA_ZICBOM` disabled.
The custom OpenSBI platform does not import Zicbom into its hart-extension mask,
so it leaves MENVCFG CBIE/CBCFE disabled. The cache-maintenance evidence here is
the M-mode smoke; enabling native Linux non-coherent DMA requires the matching
firmware extension/permission setup and a separate S-mode CBO acceptance test.
Publication source bindings are updated separately from the previously reviewed
PDF snapshot; a fresh PDF requires an explicitly reviewed committed snapshot.
+103 -1
View File
@@ -1,4 +1,106 @@
# HP Interrupt and Mailbox Platform
# HP RV64 Operating-System Platform
## Approved migration contract
The RV64 migration approved on 2026-09-25 extends the existing HP platform in
the phases below. These are requirements, not claims of completed validation.
LP remains the RV32 Hazard3 management hart (hart 0). HP is VexiiRiscv hart 1,
RV64IMAFDC_Zicbom_Zicntr_Zihpm, with M/S/U modes and Sv39. Physical addresses
remain 32 bits; the reset vector remains `0x38000000`. The existing 16 KiB
four-way I/D caches, 64-byte lines, 9-bit ASIDs, PMP, and clocks remain fixed.
I/D and cacheless MMIO use AXI64 at HP; MMIO is downsized to the existing
AXI32/APB32 control plane. Software accesses peripheral registers as 32-bit
words, including the two halves of CLINT timer registers. No new CDC or
hardware coherency is introduced. LP retains SYSCTRL and terminal-status
ownership, DMA channel 6, SDRAM initialization, and HP release control.
### Boot bundle V2
The little-endian header remains 128 bytes at flash offset `0x00100000`, with
four 24-byte entry slots and CRC32/ISO-HDLC protection. Version is 2. Header
word 7 identifies workload: 1 Linux, 2 GA2D smoke, 3 RT-Thread. Linux has four
entries (types 1 OpenSBI, 2 DTB, 3 Linux Image, 4 uncompressed CPIO), retaining
the established addresses and limits. Smoke and RT-Thread have one executable
entry of type 5, at `0x38000000`, at most 512 KiB; unused entries are zero.
Version 1, unknown workloads, incorrect entry counts/types/addresses, empty
payloads, overlaps, out-of-range sizes, and bad CRCs are rejected before HP
release. Build manifests record RV64, workload, sources and artifact hashes;
builders verify executable ELF class and RISC-V machine identity.
### Software acceptance protocol
Linux publishes event 1, argument `0x4c4e5801`, sequence 1 only after its
userspace acceptance succeeds. On a software failure it publishes event 3
with a nonzero error code. LP prints `HP_LINUX_READY` and terminates on Linux
success without entering the GA2D protocol.
RT-Thread publishes ready event 1, argument `0x52545401`, sequence 1 after
enabling PLIC source 2 in machine context 0. LP sends command `0x52545402`,
argument `0x12345678`, sequence 1. Its ISR clears the HP mailbox source and
completes the PLIC claim; the test thread verifies the received message. Once
all tests pass, HP publishes event 2, argument `0x52545401`, sequence 2.
Event 3 reports a nonzero failure code at sequence 1 or 2. LP alone writes
SYSCTRL TEST_STATUS and prints `HP_RTTHREAD_PASS` on success. Publication is
code, argument, sequence, `fence iorw, iorw`, then doorbell. No shared cached
memory is used by this test protocol. Smoke retains the GA2D and cache-clean
handshake documented by its existing payload.
RT-Thread uses the official v5.3.0 commit
`99428a1e7f7447955aa860f7c969273a12095b8f` without vendor source modifications.
The BSP uses the common RISC-V M-mode port, static threads and IPC objects,
1000 Hz ticks, UART1, hart-1 MSIP/MTIMECMP, and the existing PLIC/mailbox.
The first test image covers integer RV64 computation/context, preemption,
semaphore and message queue behavior, timeouts, and external mailbox IRQ.
RT-Smart, networking, filesystems, and floating-point task qualification are
outside this phase; hardware F/D support remains enabled.
Linux uses RV64 OpenSBI FW_JUMP, Sv39, and a static minimal BusyBox userspace.
The DT reserves `0x38000000..0x3807ffff` with `no-map` for resident OpenSBI;
Linux must never allocate or directly map that firmware window.
Its dedicated `/init` explicitly mounts devtmpfs, procfs, sysfs and tmpfs,
checks device nodes, file round trips and child execution, and reports through
the mailbox. Initial CPIO includes `/dev/console`. Effective kernel config,
not merely its fragment, must enable the required executable, console,
memory-management, filesystem and /dev/mem options. The acceptance CPIO is
uncompressed and does not run the full Buildroot services sequence.
### Development order and verification
#### Phase 2 - RV64 HP core and platform migration
Migrate the fixed generator, all PRODUCT profiles, manifests and core reports;
retain the locked VexiiRiscv revision. Use separate RV32 LP and RV64 HP tools.
Validate generated port widths, narrow MMIO lanes, 64-bit memory accesses,
and the migrated GA2D/cache-lifecycle smoke in IHP130 Verilator.
#### Phase 3 - RT-Thread dependency, BSP and acceptance
Lock sources and build tools, add the self-owned BSP and V2 loader/packager,
and run `hp-rtthread-sim` from its committed IHP130 profile. All individual
test markers, `HP_RTTHREAD_PASS`, and `SIM_TEST_PASS code=0` are required.
Negative bundle and mailbox tests must demonstrate fail-closed behavior.
#### Phase 4 - RV64 Linux minimal-initramfs acceptance
Migrate OpenSBI, Linux, Buildroot and DTB together, verify effective configs,
then run real SoC `hp-linux-sim`. Required markers include Linux userspace
checks, `retroSoC HP Linux ready`, `HP_LINUX_READY`, and `SIM_TEST_PASS code=0`.
Unexpected console corruption remains a failure requiring diagnosis.
#### Phase 5 - Documentation and delivery evidence
Update architecture, guides and publication source bindings. Preserve prior
RV32 evidence as historical. Each workload writes separate run logs and
structured results; an interrupted or ongoing run cannot reuse an old pass.
Run affected host/Python/C/RTL checks and IHP130 behavioral regressions.
Synthesis, netlist simulation, STA, and synthesis-dependent metrics are
explicitly deferred by user instruction, as are SRAM macro replacement,
CDC/RDC/physical signoff and commercial qualification. No PPA claim is made.
Reference boundaries: [RT-Thread v5.3.0](https://github.com/RT-Thread/rt-thread/releases/tag/v5.3.0)
supplies the OS/CPU port; the repository owns board integration. The existing
CLINT/PLIC architecture and locked OpenSBI platform supply the interrupt and
supervisor boot patterns; no third-party board register map is imported.
The experimental LP/HP profile adds a 32-source, two-context PLIC at
`0x0C000000` and a bidirectional mailbox at `0x10019000`. Both are self-owned
+1 -1
View File
@@ -15,7 +15,7 @@ Every committed `MINI_MODE=PRODUCT` profile instantiates two fixed harts:
| --- | --- | --- |
| Core | Hazard3 | generated VexiiRiscv |
| Hart ID | 0 | 1 |
| ISA | profile RV32I/RV32IM | RV32IMAFDC + Zicbom, S/U mode, Sv32 |
| ISA | profile RV32I/RV32IM | RV64IMAFDC + Zicbom, S/U mode, Sv39 |
| Reset clock | REF24 at 24 MHz | external 72 MHz safe clock |
| Role | boot, control, diagnostics, recovery | high-throughput application/Linux |
| JTAG | reset owner | selectable while HP is held in reset |
+5 -1
View File
@@ -33,7 +33,11 @@ The architecture report under `/nfs/share/home/miaoyuchi/plan` is the design
input. This matrix and executable configuration are the repository status
sources of truth.
## Current verification evidence
## Historical RV32 verification evidence
The results below predate the RV64 migration and must not be used as RV64
qualification. Current generation selects `rv64imafdc_zicbom_max`; see
[HP RV64 validation](hp-rv64-validation.md) for migration-specific evidence.
- The complete Python suite passes 308 tests, including directed AXI64
multi-ID/ACL/QoS, target isolation, native AXI64 SRAM, Fabric Monitor,
+7 -5
View File
@@ -24,9 +24,9 @@ advertised for a device or PDK.
| Tier | Product role | Compute topology | Primary software | Defining boundary |
| --- | --- | --- | --- | --- |
| Tiny | Low-power MCU and edge-connectivity endpoint | One Hazard3 MCU core | Bare metal or RTOS | No MMU or external DRAM dependency |
| Mini | Low-cost heterogeneous RV32 Linux control SoC | Hazard3 management core plus one RV32 VexiiRiscv Linux core | Embedded Linux plus management firmware | Lightweight Linux and basic HMI, without a desktop-class accelerator requirement |
| Mini | Low-cost heterogeneous Linux control SoC | RV32 Hazard3 management plus one RV64 VexiiRiscv application core | Embedded Linux or RT-Thread plus management firmware | Lightweight Linux and basic HMI, without a desktop-class accelerator requirement |
| Std | Heterogeneous RV32 graphical Linux edge SoC | Hazard3 management core plus VexiiRiscv performance and efficiency cores | Graphical Linux plus RTOS firmware | Full AXI4 memory fabric, GPU, audio, and AI acceleration |
| Pro | Highest-performance and only RV64 family tier | Hazard3 management core plus four coherent RV64 VexiiRiscv Linux cores | RV64 graphical Linux | Coherent SMP, high-bandwidth memory, GPU, NPU, and video codecs |
| Pro | Highest-performance coherent RV64 family tier | Hazard3 management core plus four coherent RV64 VexiiRiscv Linux cores | RV64 graphical Linux | Coherent SMP, high-bandwidth memory, GPU, NPU, and video codecs |
The VexiiRiscv targets rely on the upstream core's documented RV32/RV64,
single/dual-issue, cache, Sv32/Sv39, AXI4, and Linux capabilities. The exact
@@ -177,10 +177,12 @@ responsible for clock and memory initialization, image selection, VexiiRiscv
boot release, fault recovery, and final power-state control. Linux must not be
able to reconfigure the management-core lifecycle controls.
The initial VexiiRiscv configuration should provide:
The frozen Mini RV64 configuration provides the following architectural target;
validation status is recorded separately in [HP RV64 validation](hp-rv64-validation.md).
The Std/Pro roadmap below remains independent of this implemented Mini profile.
- RV32IMAFDC with machine, supervisor, and user modes.
- Sv32 virtual memory, hardware page-table walking, and the privileged CSRs
- RV64IMAFDC with machine, supervisor, and user modes.
- Sv39 virtual memory, hardware page-table walking, and the privileged CSRs
required by the supported Linux kernel.
- LR/SC atomics, separate 16 KiB instruction and data caches, and uncached MMIO
regions.
+7
View File
@@ -5,6 +5,13 @@ an English product document with a separate MPW compatibility appendix. It does
not define or change RTL, register ABIs, build profiles or hardware quality policy.
The canonical RTL/configuration inputs remain authoritative.
The current working source includes the Mini RV64/Sv39 migration, V2 workload
bundle checks, and minimal Linux `/init` handoff. RT-Thread's M-mode BSP and
acceptance evidence are documented in [HP RV64 validation](../docs/hp-rv64-validation.md).
These edits do not advance `mini.json.source_revision` or relabel an existing
PDF. Review and commit the implementation snapshot before producing a matching
new PDF; the source-drift check remains mandatory.
## Mini datasheet
The prototype chip brand is **Rill(清溪)**. Its bilingual label replaces the
@@ -1,23 +1,22 @@
#import "../style.typ": *
#change-start("v05-emphasis-architecture","Selected body emphasis: architecture")
#import "../figures.typ": *
#import "../waveforms.typ": timing
#import "../diagram-packages.typ": memory-window-diagram
#import "../soc-architecture.typ": soc-functional-diagram
= System Architecture
#change-start("dev-architecture","Ten-master fabric, address map, LP IRQ and lifecycle reference")
#change-start("dev-architecture","Nine-master fabric, address map, LP IRQ and lifecycle reference")
== Introduction
=== SoC Architecture
Mini PRODUCT contains *two fixed harts*, an LP-owned control plane, a native HP data fabric and
two APB4 register islands. There is *no hardware cache coherency*. Software transfers shared
Mini PRODUCT contains two fixed harts, an LP-owned control plane, a native HP data fabric and
two APB4 register islands. There is no hardware cache coherency. Software transfers shared
buffer ownership explicitly and performs the required fences and cache maintenance.
#figure(soc-functional-diagram(), caption:[Mini PRODUCT functional architecture and clock domains.])<soc-functional-overview>
=== Management Processor
==== Hazard3
Hazard3 is hart 0 and the *root-management processor*. The reference profile selects RV32IM
Hazard3 is hart 0 and the root-management processor. The reference profile selects RV32IM
firmware. Its AHB-Lite interface is adapted to AXI32 for control access; memory transactions
are directed through the LP gateway to the shared data plane. The management JTAG path provides
halt, resume, register and system-bus access. LP retains control while HP is held in reset.
@@ -25,8 +24,8 @@ halt, resume, register and system-bus access. LP retains control while HP is hel
=== Application Processor
==== VexiiRiscv
The generated HP hart is a dual-issue RV32IMAFDC + Zicbom configuration, with supervisor/user
modes, Sv32 virtual memory and *64-byte cache-maintenance blocks*. Hart 1 uses native AXI64
The generated HP hart is a dual-issue RV64IMAFDC + Zicbom configuration, with supervisor/user
modes, Sv39 virtual memory and 64-byte cache-maintenance blocks. Hart 1 uses native AXI64
instruction and data paths. Its uncached MMIO path is downsized and crosses into the LP
control plane. OpenSBI/Linux inputs and generated-core configuration are dependency-locked.
#source-note("docs/lp-hp-architecture.md", title:"LP/HP architecture and boot contract")
@@ -171,5 +170,3 @@ Claim/complete and priority rules are defined in the HP platform contract.
#include "register-programming.typ"
#include "interface-subsets.typ"
#change-end("dev-architecture")
#change-end("v05-emphasis-architecture")
@@ -1,13 +1,15 @@
#import "../style.typ": *
#change-start("v05-emphasis-boot-bundle-format","Selected body emphasis: boot bundle format")
#import "../diagram-packages.typ": binary-figures, storage-figures
#let bundle = data.system_reference.software.bundle_reference
#let hex(value) = code("0x"+upper(str(value,base:16)))
=== HP Boot Bundle Binary Format <boot-bundle-format>
The supplied format is a fixed four-artifact bundle, serialized as *little-endian 32-bit words*.
The format version is #bundle.version; it is independent of the datasheet's v0.5 revision.
The supplied V2 format is a typed workload bundle, serialized as little-endian 32-bit words.
Linux uses four artifacts; smoke and RT-Thread use one executable descriptor at
0x38000000 with the remaining three descriptor slots zero. Workload values are 1, 2 and 3
respectively. V1 bundles must be rebuilt.
The format version is #bundle.version; it is independent of the datasheet's v0.4 revision.
The bundle starts at Flash offset #hex(bundle.bundle_offset), after the LP firmware area.
Its fixed header is #bundle.fixed_header_bytes bytes, each descriptor is #bundle.entry_bytes
bytes and the complete header including #bundle.entry_count descriptors is #bundle.header_bytes bytes.
@@ -15,8 +17,8 @@ bytes and the complete header including #bundle.entry_count descriptors is #bund
The following offsets are relative to the beginning of the named structure. The descriptor
array starts immediately after the fixed header, so descriptor n begins at
#code(str(bundle.fixed_header_bytes)+" + n * "+str(bundle.entry_bytes)), for n = 0…#(bundle.entry_count - 1).
All listed fields occupy four bytes. Use the *explicit serialization, not an arbitrary host
structure layout*. The existing load addresses and maximum allocations remain in the preceding
All listed fields occupy four bytes. Use the explicit serialization, not an arbitrary host
structure layout. The existing load addresses and maximum allocations remain in the preceding
image-layout table.
#binary-figures("software-boot","software")
@@ -58,14 +60,13 @@ or invite reliance on unvalidated encodings. Use the canonical packager output f
]
}
The generated payload boundary is #bundle.payload_alignment bytes; the loader's address checks
require four-byte alignment. The generator writes flags=1 and reserved=0, while the loader
tests the REQUIRED bit and has no separate rejection for other flag bits or the reserved word.
It bounds individual payload ranges but does not separately enforce sequential disjoint
placement or a padding pattern. Record these as current checks, not as stronger validation.
The generated and accepted payload boundary is #bundle.payload_alignment bytes. The loader
requires flags=1, a known workload, its exact entry count/types/load addresses, and zero unused
descriptors. It rejects overlapping or out-of-bounds payloads. Padding bytes are not validated.
#source-note("app/apps/hp_boot/hp_boot_bundle.h",title:"Handwritten bundle fields, types and allocation bounds")
#source-note("scripts/package_hp_boot.py",title:"Actual byte serialization, alignment, padding and CRC generation")
#source-note("app/apps/hp_boot/main.c",title:"Actual header/entry acceptance and copy checks")
#source-note("app/apps/hp_boot/hp_boot_bundle.c",title:"Actual header/entry acceptance")
#source-note("app/apps/hp_boot/main.c",title:"Copy checks and workload-specific terminal handshakes")
==== Synthetic serialization example
This example is generated by the existing packager from non-executable synthetic payloads.
@@ -90,5 +91,3 @@ The example values are recalculated from the actual packager rather than maintai
#source-note("tests/test_hp_boot_bundle.py",title:"Existing package layout/CRC test boundary")
#storage-figures("software-boot",section:"software")
#change-end("v05-emphasis-boot-bundle-format")
@@ -1,24 +1,23 @@
#import "../style.typ": *
#change-start("v05-emphasis-linux-runtime","Selected body emphasis: linux runtime")
#import "../system-figures.typ": sequence-diagram
#let platform = data.system_reference.software.platform
=== OpenSBI platform and console path <linux-runtime>
The supplied OpenSBI platform exposes *one application hart*, with hart ID #platform.hart_id.
The supplied OpenSBI platform exposes one application hart, with hart ID #platform.hart_id.
LP remains the separate management firmware processor. The platform's ACLINT descriptor covers
two hart-indexed register positions beginning at zero so it can address hart 1; that storage
range is not a declaration that Linux runs on both harts. The *kernel configuration disables SMP*.
range is not a declaration that Linux runs on both harts. The kernel configuration disables SMP.
The early platform setup programs UART1, registers its polled console and initializes machine
software-interrupt support. Timer initialization uses the ACLINT machine timer. Console writes
wait while TX is full; this loop has *no local timeout*. These implemented callbacks do not
wait while TX is full; this loop has no local timeout. These implemented callbacks do not
establish that all optional SBI services or all peripherals have native Linux drivers.
#figure(sequence-diagram((
[*LP handoff* \ Existing bundle validation \ Release HP at OpenSBI],
[*OpenSBI on hart 1* \ UART1 SBI console \ ACLINT platform setup],
[*FW_JUMP* \ Enter Linux Image \ Pass the prepared DTB],
[*Kernel / initramfs* \ SBI early console and hvc0 \ Run /sbin/init],
[*Kernel / initramfs* \ SBI early console and hvc0 \ Run /init],
[*Rootfs ready service* \ Print ready text \ Publish mailbox fields],
[*LP observation* \ Match sequence / event \ Separate from driver coverage],
)),caption:[Supplied OpenSBI/Linux handoff and readiness path. The diagram describes source-level checkpoints.])<linux-runtime-flow>
@@ -28,7 +27,7 @@ path in this configuration. The UART1 device-tree node's presence does not subst
native driver. The configured machine timer and software-interrupt path are distinct from
external interrupt-controller and custom peripheral driver integration.
#source-note("app/ports/linux/opensbi/retrosoc_hp/platform.c",title:"Hart mapping, console callbacks and ACLINT setup")
#source-note("app/ports/linux/linux/retrosoc_hp.config",title:"RV32, SBI console and single-hart kernel configuration")
#source-note("app/ports/linux/linux/retrosoc_hp.config",title:"RV64, SBI console and single-hart kernel configuration")
=== Device-tree and image consistency
The device-tree template, OpenSBI build arguments, boot-bundle bounds and actual generated HP
@@ -41,49 +40,43 @@ the following values explain the platform relationship rather than defining a se
([Main memory],[#code(platform.memory_base), #(platform.memory_bytes / 1024 / 1024) MiB],[Device-tree envelope; actual external memory and boot-loader bounds must agree.]),
([Timer base rate],[#platform.timebase_hz Hz],[Match ACLINT timebase-frequency and the OpenSBI mtimer declaration.]),
([CPU / UART clock declarations],[#platform.clock_hz Hz],[Nominal template values, not measured or dynamically synchronized frequencies.]),
([MMU / cache maintenance],[Sv32; #(platform.cbom_bytes)-byte CBO blocks],[Software metadata must be checked against the generated HP artifact.]),
([Initial ramdisk],[Start #code("0x"+str(platform.initrd_start,base:16))],[The source template's equal start/end is patched using the built compressed rootfs size.]),
([MMU / cache maintenance],[Sv39; #(platform.cbom_bytes)-byte CBO blocks],[Software metadata must be checked against the generated HP artifact.]),
([Initial ramdisk],[Start #code("0x"+str(platform.initrd_start,base:16))],[The source template's equal start/end is patched using the built uncompressed CPIO size.]),
([Interrupt controllers],[ACLINT CPU causes; PLIC machine/supervisor contexts],[A DT node and binding alone do not demonstrate a complete driver or interrupt acceptance test.])),
widths:(1fr,1.3fr,2.15fr))
The image builder replaces linux,initrd-end with the start plus the actual rootfs.cpio.gz size.
The image builder replaces linux,initrd-end with the start plus the actual rootfs.cpio size.
That value is an end-exclusive boundary; the generated DTB, not the unpatched source template,
must accompany the images. OpenSBI FW_TEXT_START, FW_JUMP_ADDR and FW_JUMP_FDT_ADDR are selected
from the supplied fixed layout. Retain the output DTB, source configuration and bundle manifest
together. A changed device-tree property does not reconfigure clocks or synthesize different RTL.
The resident OpenSBI window at 0x38000000 occupies a 512 KiB no-map reserved-memory
node. Linux must not allocate this firmware memory; the custom platform does not
apply the generic OpenSBI FDT fixups.
#source-note("app/ports/linux/linux/retrosoc_hp.dts",title:"Device-tree template and logical platform bindings")
#source-note("scripts/build_hp_linux.py",title:"Actual initrd-end patch and FW_JUMP build arguments")
=== Kernel and rootfs ready handoff
#change-start("v05-refresh-linux-mailbox","HAL-derived mailbox purposes and ready-only rootfs boundary")
The rootfs service S99retrosoc-hp prints its ready message and then performs four 32-bit mailbox
writes. The published event is an init-service checkpoint, not proof of all drivers, networking,
The dedicated /init mounts procfs, sysfs, devtmpfs and tmpfs, checks file I/O and child execution,
then runs the static hp-ready helper. It prints its ready message and publishes through 32-bit
mailbox writes with an I/O fence before the doorbell. This is a userspace checkpoint, not proof of all drivers, networking,
storage or long-term Linux stability. The text is emitted before the mailbox writes, so the text
alone is not the LP's readiness condition.
#ds-table("linux-ready-writes",[Rootfs service mailbox publication order],
#ds-table("linux-ready-writes",[Userspace helper mailbox publication order],
([Order],[Address],[Written value],[Purpose]),
platform.ready_writes.enumerate().map(((i,row))=>(str(i+1),code(row.address),code(row.value),
[#code(row.register) \ #row.purpose])),
([Linux-ready event],[Argument / ready state],[Sequence],[Interrupt request]).at(i))),
widths:(0.4fr,1.1fr,1.1fr,1.85fr))
The script uses devmem from the supplied userland with CONFIG_DEVMEM enabled in the kernel.
It contains no explicit readback or per-write failure handling. The LP loader checks the
exact sequence, event and argument with a bounded iteration budget. A rootfs message, process
exit, mailbox publication and final SYSCTRL TEST_STATUS are different observations.
The current loader subsequently requests GA2D acceptance and cache-clean responses before
returning ownership to LP and writing a successful verdict. This rootfs script implements *only
the first ready event*; it supplies none of those later responses. Reaching Linux init is
therefore insufficient for a complete loader acceptance pass. Use the matching freestanding
acceptance payload for that protocol, or provide and validate the missing Linux service as
separate integration work. See @boot-configuration for the exact message identities and budget.
The helper checks open/mmap errors for /dev/mem and reports init failures through event 3
when the mailbox can be mapped. LP validates the expected event, argument and sequence,
then writes TEST_STATUS directly for the Linux workload. GA2D/cache lifecycle is a separate
smoke workload. A rootfs message alone is not the final SYSCTRL verdict.
Resource ownership and non-coherent buffer rules still apply after Linux starts. Follow
@software-support before choosing a driver path, and @multicore-operation for later LP/HP
transactions. This description adds no new successful boot or board-validation claim.
#source-note("app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp",title:"Ready message and actual mailbox write order")
#source-note("crt/src/hal/hp_mailbox.c",title:"Event, argument and sequence register purposes")
#source-note("app/ports/linux/hp_ready.c",title:"Ready message and actual mailbox write order")
#source-note("app/ports/linux/init",title:"Minimal userspace acceptance checks")
#source-note("app/apps/hp_boot/main.c",title:"LP sequence/event checks and final terminal result")
#change-end("v05-refresh-linux-mailbox")
#change-end("v05-emphasis-linux-runtime")
+12 -27
View File
@@ -3,16 +3,13 @@
// Publication status is explicit; successful build/tests do not change these marks.
#let artifact-status = (
(name:"Available",fill:"full"),
(name:"Functional",fill:"left-half"),
(name:"Reproduced",fill:"empty"),
(name:"Tapedout",fill:"empty"),
(name:"Available",selected:true),
(name:"Functional",selected:false),
(name:"Reproduced",selected:false),
(name:"Tapedout",selected:false),
)
#cover(evaluation:artifact-status)[
#change-start("v05-rill-cover","Rill bilingual prototype brand in the existing cover metadata row")
#change-start("v05-emphasis-cover","Cover contact, partial Functional mark and selected feature emphasis")
#change-start("v05-product-brief","v0.5 document identity and implemented accelerator features")
#text(9pt, weight: "semibold", fill: gold)[PRODUCT DATASHEET / #doc.status]
#v(rhythm.cover-gap)
#text(30pt, weight: "semibold")[retroSoC Mini]
@@ -21,10 +18,9 @@
#v(rhythm.cover-gap)
#text(13pt)[An Open-Source, Linux-Capable Asymmetric Dual-Core SoC]
#v(rhythm.cover-meta-gap)
// Inter's 1490/2048 em cap edge keeps CJK fallback from increasing this row.
#grid(columns: (1fr, 1fr),
[#text(font:("Inter","Noto Sans CJK SC"),weight:"bold",top-edge:0.7275390625em)[#doc.brand_name(#doc.brand_name_zh)] · v#doc.version \ #doc.date],
align(right)[#doc.author#link("mailto:"+doc.author_email)[(#doc.author_email)] \ #doc.maintainer],
[*#doc.document_id* · v#doc.version \ #doc.date],
align(right)[#doc.author \ #doc.maintainer],
)
#v(rhythm.cover-rule-gap)
#line(length:100%, stroke:1.1pt + gold)
@@ -36,16 +32,15 @@
#set list(tight:false,spacing:rhythm.cover-list-spacing,body-indent:rhythm.cover-list-indent)
*Compute and control*
- Hazard3 LP: boot, clocks, resource ownership and fault recovery.
- Dual-issue VexiiRiscv HP: RV32IMAFDC + Zicbom, Sv32.
- NPU: *64 dense MACs*, eight INT8 operator classes and 64 KiB private SRAM.
- Dual-issue VexiiRiscv HP: RV64IMAFDC + Zicbom, Sv39.
- JTAG debug; fixed EXT-L control and EXT-H AXI64 slots.
*Memory and interconnect*
- *32 KiB banked SRAM* in this profile; 4/16/32/64/128 KiB build options.
- 32 KiB banked SRAM in this profile; 4/16/32/64/128 KiB build options.
- AXI32 control, native AXI64 data paths and APB4 registers.
- SDRAM, QPI PSRAM and OPI/HyperBus-style external-memory controllers.
- XPI: four chip selects, 16 LUT sequences, 1/2/4-bit SDR transfers.
- *Eight DMA channels*; linked-list TCDs, 16-beat bursts and stream endpoints.
- Eight DMA channels; linked-list TCDs, 16-beat bursts and stream endpoints.
*Platform services*
- Two 32-bit timers with 16-bit prescalers; four-channel PWM.
@@ -56,8 +51,8 @@
#colbreak()
*Connectivity*
- *32 GPIOs*: atomic outputs, pin interrupts and two alternate-function selections.
- Two UARTs with *64-byte TX/RX FIFOs*; UART0 DMA and RTS/CTS.
- 32 GPIOs: atomic outputs, pin interrupts and two alternate-function selections.
- Two UARTs with 64-byte TX/RX FIFOs; UART0 DMA and RTS/CTS.
- Two I2C controllers: 7/10-bit addressing and 16-entry command/RX FIFOs.
- SPI-SD, two 1/4-bit SDR SDIO hosts and bidirectional PS/2.
- USB2: 8 endpoints, 16 host channels, 16 KiB packet RAM; external ULPI PHY.
@@ -67,7 +62,7 @@
- Stereo 16/24-bit I2S master; 8-bit RGB565/YUV422 DVP with crop/snapshot capture.
- Baseline JPEG encode/decode up to 2048 × 2048, with private DMA.
- GA2D fill/copy/convert/opaque blend and A8 masks.
- APU WAV/FLAC decode; fixed KWS in the P7 configuration; MP3 unsupported.
- APU WAV/FLAC decode; MP3/KWS not advertised.
- AES-128/192/256, SHA-224/256 and raw RSA-2048; programmable CRC.
- RNG source remains unqualified for production entropy.
@@ -79,15 +74,10 @@
#note(below: 0pt)[This draft describes a reviewed RTL/configuration snapshot. It does not establish silicon
speed grades, electrical limits, production availability or certification. Gen2/Gen2+ is the
retained document title; no separate derivative specifications are inferred.]
#change-end("v05-product-brief")
#change-end("v05-emphasis-cover")
#change-end("v05-rill-cover")
]
#pagebreak()
== Overview
#change-start("v05-emphasis-overview","Cover-adjacent overview and evidence context")
#change-start("v05-overview","NPU-inclusive functional inventory and configuration reference")
retroSoC Mini combines a small management processor with an application processor and shared
memory and I/O. Hazard3 retains authority over startup, clock transitions, resource ownership
and fault recovery. VexiiRiscv supplies the application-side compute and Linux integration.
@@ -96,7 +86,6 @@ experimentation, education and ASIC prototyping.
#figure(product-diagram(), caption:[Integrated Mini PRODUCT IP inventory, organized by function.])<product-diagram>
#change-start("v05-refresh-identity","Reviewed source identity for this same-version revision")
#ds-table("profile", [Document reference configuration],
([Property], [Reference]),
(
@@ -109,7 +98,3 @@ experimentation, education and ASIC prototyping.
([MPW compatibility], code(doc.mpw_profile)),
), widths:(0.8fr,1.9fr),
)
#change-end("v05-overview")
#change-end("v05-refresh-identity")
#change-end("v05-emphasis-overview")
@@ -13,7 +13,7 @@ ISA/CSR manuals. A software compiler option does not remove a hardware extension
([Execution width],[RV32 integration.],[XLEN #cpu.hp.xlen / physical address width #cpu.hp.physicalWidth.]),
([Configured extensions],cpu.lp_extensions.join(", "),cpu.hp_isa.filter(x=>not(x in ("s","u"))).join(", ")),
([Privilege],[Machine-mode configuration, U_MODE = #cpu.lp.U_MODE.],[S and U selected by the generator, in addition to machine-mode operation.]),
([MMU / software platform],[No LP MMU is advertised by this integration.],[Supplied software platform declares Sv32; verify agreement with the generated core before deployment.]),
([MMU / software platform],[No LP MMU is advertised by this integration.],[Supplied software platform declares Sv39; verify agreement with the generated core before deployment.]),
([Protection],[PMP_REGIONS = #cpu.lp.PMP_REGIONS.],[PMP entries = #cpu.hp.at("pmpParam.pmpSize") / granularity = #cpu.hp.at("pmpParam.granularity") bytes.]),
([Reset entry],code(data.reset_address),code(cpu.hp.resetVector.trim("L",at:end))),
([Trap / counter configuration],[MTVEC_INIT: #code(cpu.lp.MTVEC_INIT) \ Machine CSR: #cpu.lp.CSR_M_MANDATORY / counters: #cpu.lp.CSR_COUNTER.],[ASID width #cpu.hp.asidWidth and #cpu.hp.additionalPerformanceCounters additional performance counters. \ Time-read option: #cpu.hp.at("privParam.withRdTime").]),
@@ -88,7 +88,7 @@ profile; other profiles can depend on external memory even when Linux is not use
[*External boot image* \ XPI-visible bundle \ Header and payload CRCs],
[*LP loader* \ Validate and copy \ Retain root authority],
[*External SDRAM* \ OpenSBI, DTB \ Linux and initramfs],
[*HP application* \ Hart 1, Sv32 \ Linux enters via OpenSBI],
[*HP application* \ Hart 1, Sv39 \ Linux enters via OpenSBI],
[*SBI console / timer* \ Supplied platform path],
[*LP supervision* \ Mailbox observation \ Resource and reset policy])),
caption:[Supplied Linux boot composition and management responsibilities.])
+120 -374
View File
@@ -1,30 +1,22 @@
{
"schema_version": 1,
"source_revision": "c3de7c602a7ca0f0f9ade9d3ffb59339bc34fb8b",
"source_revision": "2a497ecef0b084c02f77ddfb1e94fb0197e14b02",
"sources": [
"Makefile",
"app/README.md",
"app/apps/apu_release/main.c",
"app/apps/hp_boot/hp_boot_bundle.h",
"app/apps/hp_boot/main.c",
"app/ports/hp-apu/main.c",
"app/ports/linux/README.md",
"app/ports/linux/linux/retrosoc_hp.dts",
"app/ports/linux/opensbi/retrosoc_hp/platform.c",
"configs/benchmark/ihp130-hazard3-coremark.mk",
"configs/ci/ihp130-apu.mk",
"configs/ci/ihp130-hp.mk",
"configs/ci/ihp130.mk",
"configs/cluster/mini-mpw.mk",
"crt/README.md",
"crt/include/retrosoc/hal/apu_regs.h",
"crt/include/retrosoc/hal/ga2d.h",
"crt/include/retrosoc/hal/npu.h",
"crt/include/retrosoc/hal/npu_regs.h",
"crt/include/retrosoc/hal/resource.h",
"crt/include/retrosoc/hal/sysctrl.h",
"crt/src/hal/ga2d.c",
"crt/src/hal/npu.c",
"crt/src/hal/resource.c",
"crt/src/hal/sysctrl.c",
"docs/axi4-interconnect.md",
@@ -34,7 +26,6 @@
"docs/hazard3-debug.md",
"docs/ip/fabric-monitor.md",
"docs/ip/ga2d.md",
"docs/ip/npu-verification.md",
"docs/ip/resource-controller.md",
"docs/lp-hp-architecture.md",
"docs/mini-high-performance-traceability.md",
@@ -43,28 +34,17 @@
"physical/README.md",
"publications/datasheets/mini.json",
"publications/datasheets/register-profiles.json",
"publications/examples/npu.c",
"rtl/ip/multimedia/apb4_apu.sv",
"rtl/ip/multimedia/apb4_ga2d.sv",
"rtl/ip/multimedia/apb4_npu.sv",
"rtl/ip/multimedia/apu_define.svh",
"rtl/ip/multimedia/apu_kws_engine.sv",
"rtl/ip/multimedia/apu_kws_model_loader.sv",
"rtl/ip/multimedia/apu_kws_sram_client.sv",
"rtl/ip/multimedia/apu_local_sram.sv",
"rtl/ip/multimedia/apu_p5_codecs.apus",
"rtl/ip/multimedia/apu_reg.sv",
"rtl/ip/multimedia/ga2d_core.sv",
"rtl/ip/multimedia/ga2d_dma.sv",
"rtl/ip/multimedia/npu_accumulator.sv",
"rtl/ip/multimedia/npu_define.svh",
"rtl/ip/multimedia/npu_job_decoder.sv",
"rtl/ip/multimedia/npu_local_sram.sv",
"rtl/ip/multimedia/npu_pkg.sv",
"rtl/ip/multimedia/npu_reg.sv",
"rtl/ip/multimedia/npu_scheduler.sv",
"rtl/mini/integration/soc_topology.json",
"scripts/apu_abi_digest.py",
"scripts/apu_isa.py",
"scripts/apu_kws.py",
"scripts/apu_mcasm.py",
@@ -72,23 +52,8 @@
"scripts/build_apu_p5_bundle.py",
"scripts/build_hp_linux.py",
"scripts/check_lp_hp_performance.py",
"scripts/npu_compiler.py",
"scripts/npu_compiler_p0.py",
"scripts/npu_descriptors.py",
"scripts/package_hp_boot.py",
"scripts/parse_performance_log.py",
"tests/test_lp_irq.py",
"rtl/mini/top/retrosoc.sv",
"rtl/mini/top/apb4_periph.sv",
"docs/development-environment.md",
"scripts/development_environment.py",
"dependencies/dependencies.lock.json",
"docker/Dockerfile",
"flake.nix",
".github/workflows/development-environment.yml",
".github/workflows/quality.yml",
"CONTRIBUTING.md",
"docs/git-workflow.md"
"tests/test_lp_irq.py"
],
"support": [
{
@@ -644,7 +609,7 @@
"id": "resource",
"title": "Resource Controller",
"implementation": "Partial",
"scope": "Ten independently managed shared resources; resource 8 owns GA2D and resource 9 owns NPU execution, including lifecycle and LP/HP IRQ routing.",
"scope": "Nine independently managed shared resources; resource 8 owns the active P5 GA2D direct 2D engine and IRQ route.",
"dependencies": "No additional off-chip component implied; use the selected clock/reset and access policy.",
"hal": "Published API and syntax example; see the IP chapter.",
"linux": "Native driver support not established in this publication.",
@@ -664,7 +629,7 @@
"id": "monitor",
"title": "Fabric Monitor",
"implementation": "Integrated",
"scope": "Ten master and six target observation banks; master bank 8 observes GA2D traffic and master bank 9 observes NPU descriptor and data DMA traffic.",
"scope": "Nine master and six target observation banks; bank 8 observes active P5 GA2D direct 2D traffic.",
"dependencies": "No additional off-chip component implied; use the selected clock/reset and access policy.",
"hal": "Published API and syntax example; see the IP chapter.",
"linux": "Native driver support not established in this publication.",
@@ -774,80 +739,23 @@
"id": "apu",
"title": "Audio Processing Unit",
"implementation": "Partial",
"scope": "WAV/FLAC image and job/stream execution; APUC-backed KWS is enabled only in the P9 acceptance configuration. MP3 remains unsupported.",
"dependencies": "Load compatible APUMC V2, APUC and APUM images in order. MP3 is unsupported and KWS is gated off by default; corpus, real-time and physical qualification remain separate.",
"scope": "Microcode-controlled WAV/FLAC decoding with private DMA, direct/ring submission, I2S TX and local storage.",
"dependencies": "Load the compatible checked-in P5 APUMC V2 image. MP3 is unsupported and KWS is gated off by default; corpus, real-time and physical qualification remain separate.",
"hal": "Published API and syntax example; see the IP chapter.",
"linux": "No delivered Linux ASoC integration. The LP/HP APU release image is bare-metal acceptance firmware, not a kernel driver.",
"linux": "Native driver support not established in this publication.",
"verification": "Tests available",
"sources": [
"Makefile",
"app/apps/apu_release/main.c",
"app/ports/hp-apu/main.c",
"configs/ci/ihp130-apu.mk",
"crt/include/retrosoc/hal/apu.h",
"crt/include/retrosoc/hal/apu_regs.h",
"crt/src/hal/apu.c",
"docs/ip/apu.md",
"publications/examples/apu.c",
"rtl/ip/multimedia/apb4_apu.sv",
"rtl/ip/multimedia/apu_define.svh",
"rtl/ip/multimedia/apu_kws_coeff_loader.sv",
"rtl/ip/multimedia/apu_kws_coeff_store.sv",
"rtl/ip/multimedia/apu_kws_sram_client.sv",
"rtl/ip/multimedia/apu_local_sram.sv",
"rtl/ip/multimedia/apu_p5_codecs.apus",
"rtl/ip/multimedia/apu_reg.sv",
"rtl/ip/multimedia/apu_proof_memo.sv",
"scripts/apu_abi_digest.py",
"scripts/apu_isa.py",
"scripts/apu_kws.py",
"scripts/apu_kws_coeff.py",
"scripts/apu_mcasm.py",
"scripts/apu_p5_coefficients.py",
"scripts/build_apu_p5_bundle.py"
],
"tests": [
"tests/test_apu.py",
"tests/test_apu_p7_concurrent.py",
"tests/test_apu_p7_qualification.py",
"tests/test_apu_p8_contention.py",
"tests/test_apu_p8_quiesce_load.py"
],
"reports": []
},
{
"id": "npu",
"title": "Neural Processing Unit",
"implementation": "Integrated",
"scope": "Eight INT8 operators with native HP descriptor/DMA execution and private local SRAM.",
"dependencies": "Static compiler-supported graphs, exclusive resource/buffer ownership and explicit cache maintenance; locked KWS/VWW references for qualification.",
"hal": "Eleven public NPU HAL operations and a bounded submission example.",
"linux": "No native Linux NPU driver ABI is established. The HP smoke payload is freestanding acceptance firmware.",
"verification": "Tests available",
"sources": [
"crt/include/retrosoc/hal/npu.h",
"crt/include/retrosoc/hal/npu_regs.h",
"crt/src/hal/npu.c",
"docs/ip/npu-verification.md",
"docs/ip/npu.md",
"publications/examples/npu.c",
"rtl/ip/multimedia/apb4_npu.sv",
"rtl/ip/multimedia/npu_accumulator.sv",
"rtl/ip/multimedia/npu_define.svh",
"rtl/ip/multimedia/npu_job_decoder.sv",
"rtl/ip/multimedia/npu_local_sram.sv",
"rtl/ip/multimedia/npu_pkg.sv",
"rtl/ip/multimedia/npu_reg.sv",
"rtl/ip/multimedia/npu_scheduler.sv",
"scripts/npu_compiler.py",
"scripts/npu_compiler_p0.py",
"scripts/npu_descriptors.py"
],
"tests": [
"tests/test_npu_register_parity.py",
"tests/test_npu_rtl_p4.py",
"tests/test_npu_compiler.py",
"tests/test_npu_p6.py"
"tests/test_apu.py"
],
"reports": []
},
@@ -988,7 +896,7 @@
"impact": "Stale reads or loss of dirty data across CPU/DMA ownership changes.",
"trigger": "Concurrent cached CPU access and non-snooping DMA/LP access.",
"workaround": "Use exclusive ownership, whole cache-block ranges, directional cache maintenance and fences.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"docs/lp-hp-architecture.md",
"docs/ip/resource-controller.md"
@@ -996,16 +904,14 @@
},
{
"id": "hp-ready-wait",
"title": "Linux ready service does not complete loader acceptance",
"impact": "The supplied rootfs publishes the initial ready checkpoint but does not provide the later GA2D result and cache-clean service required by the current hp_boot acceptance sequence.",
"trigger": "Using the ready-only Linux service where the loader expects the full acceptance mailbox protocol.",
"workaround": "Pair the loader with a matching acceptance payload or service. Current polling is bounded by iteration budgets and missing handshakes fail their stage; an initial ready message is not a terminal pass.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"title": "HP loader has no firmware-local ready timeout",
"impact": "LP can wait indefinitely for the expected Linux mailbox event.",
"trigger": "No mailbox message after HP release.",
"workaround": "Use the simulator deadline during acceptance. A board supervisor/watchdog policy is integration work; no automatic retry is implemented here.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"app/apps/hp_boot/main.c",
"configs/ci/ihp130-hp.mk",
"app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp",
"crt/src/hal/hp_mailbox.c"
"configs/ci/ihp130-hp.mk"
]
},
{
@@ -1014,7 +920,7 @@
"impact": "A CRC-valid image is not proven to come from a trusted signer.",
"trigger": "Untrusted image or writable external boot storage.",
"workaround": "Treat signing, key storage, rollback prevention and secure recovery as separate unimplemented system requirements.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"app/apps/hp_boot/main.c",
"app/apps/hp_boot/hp_boot_bundle.h"
@@ -1026,7 +932,7 @@
"impact": "A HAL or DT node does not provide a native Linux driver.",
"trigger": "Applications attempt direct Linux use of a custom peripheral.",
"workaround": "Use the published support matrix, retain LP ownership where needed, and validate a platform driver before handoff.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"app/ports/linux/README.md",
"app/ports/linux/linux/retrosoc_hp.dts"
@@ -1038,7 +944,7 @@
"impact": "Some downstream peripheral engines are not reset by the central lifecycle request.",
"trigger": "Using Resource CONTROL.RESET as independent engine reset containment.",
"workaround": "Drain and use each IP reset/recovery contract. APU P1 has a local reset connection; do not generalize it to all engines.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"docs/ip/resource-controller.md"
]
@@ -1049,7 +955,7 @@
"impact": "Missing cache-clean acknowledgement prevents preservation of modified shared data.",
"trigger": "HP shutdown times out before acknowledgement.",
"workaround": "Keep a recoverable authoritative copy outside dirty HP cache; treat timed-out work as failed and reinitialize dependent queues.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"docs/lp-hp-architecture.md",
"docs/ip/resource-controller.md"
@@ -1061,7 +967,7 @@
"impact": "The inactive memory window returns an error and its pads are disconnected.",
"trigger": "Accessing the inactive memory mode or attempting a live protocol change.",
"workaround": "Select the mode at boot before use; respect the sticky lock. A live handover is not supported.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"docs/lp-hp-architecture.md"
]
@@ -1072,7 +978,7 @@
"impact": "Dedicated USB2 ULPI and SDIO1 pads need board assignment and electrical/timing review.",
"trigger": "Assuming logical pads are FPGA ball or package-pin assignments.",
"workaround": "Supply board constraints, bank voltages, external devices and validated timing before enabling a physical route.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"fpga/README.md",
"publications/datasheets/sections/pins.typ"
@@ -1081,10 +987,10 @@
{
"id": "apu-production",
"title": "APU MP3/KWS availability and qualification limits",
"impact": "WAV/FLAC code and image are implemented. MP3 remains a reserved trap; default PRODUCT disables KWS, while the dedicated P7 configuration enables its fixed APUM model. These facts do not establish full-corpus, sustained real-time or physical qualification.",
"impact": "WAV/FLAC code and image are implemented; this does not establish complete corpus, sustained real-time or physical qualification. MP3 remains a reserved trap entry; KWS RTL exists but PRODUCT defaults to EnableP7=0 and does not advertise KWS.",
"trigger": "Submitting MP3, assuming default KWS availability, or inferring full qualification from capability bits.",
"workaround": "Read the configuration-specific capability/digest. Use the supported image/model and explicit loader, cache and ownership protocol. Obtain complete revision-matched accuracy/concurrency/physical reports before wider qualification.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"workaround": "Use advertised WAV/FLAC paths with a validated APUMC image and supported formats/rates. Treat KWS as gated development functionality until its complete qualification evidence is supplied.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"publications/datasheets/ips/apu.typ",
"rtl/ip/multimedia/apu_reg.sv"
@@ -1096,7 +1002,7 @@
"impact": "Deterministic test data cannot supply production cryptographic entropy.",
"trigger": "Using the current entropy stream to generate secret keys or nonces.",
"workaround": "Keep diagnostic use separate; production entropy requires a reviewed physical source and qualification.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"publications/datasheets/ips/rng.typ",
"rtl/mini/top/apb4_system.sv"
@@ -1108,7 +1014,7 @@
"impact": "Configuration clocks and behavioral models are not electrical or silicon ratings.",
"trigger": "Selecting board voltage, frequency, thermal or timing limits from RTL defaults.",
"workaround": "Use approved technology, macro, package and board reports; leave absent specifications TBD.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"physical/README.md",
"docs/pll-clock-control.md"
@@ -1120,7 +1026,7 @@
"impact": "Legacy selection writes are rejected in PRODUCT.",
"trigger": "Calling selectable user-core/IP mutators on a fixed PRODUCT configuration.",
"workaround": "Detect mode/capabilities first and use fixed EXT-L/EXT-H APIs in PRODUCT.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; MPW differences are stated separately.",
"applies_to": "Reviewed v0.4 PRODUCT snapshot; MPW differences are stated separately.",
"sources": [
"docs/lp-hp-architecture.md",
"docs/ip/user-ip.md"
@@ -1144,7 +1050,7 @@
"impact": "READ_BASE and WRITE_BASE next-state assignments are not gated by the KindExtH write-legal result; an EXT-L write can change those readbacks while returning PSLVERR.",
"trigger": "Writing READ_BASE or WRITE_BASE through the EXT-L register window.",
"workaround": "Treat these writes as invalid and avoid them. Preserve the slot fault/address when diagnosing an error; do not assume a rejected write rolls back state. EXT-L has no connected data master, so these local outputs do not grant an EXT-L DMA path.",
"applies_to": "Reviewed v0.5 PRODUCT source snapshot; static RTL observation, no new simulation or hardware test.",
"applies_to": "Reviewed v0.4 PRODUCT source snapshot; static RTL observation, no new simulation or hardware test.",
"sources": [
"rtl/mini/top/extension_slot.sv",
"rtl/mini/top/extension_subsystem.sv"
@@ -1161,20 +1067,6 @@
"crt/arch/riscv/startup.S",
"rtl/mini/mk/software.mk"
]
},
{
"id": "npu-deployment-scope",
"title": "NPU execution does not imply arbitrary model or qualified performance support",
"impact": "Unsupported graphs, unsafe buffer reuse or an assumed Linux driver can prevent correct deployment.",
"trigger": "Dynamic/arbitrary TFLite graphs, unadvertised operators, timeout without drain, or missing cache/ownership handoff.",
"workaround": "Use the static compiler subset and explicit CPU preprocessing/Softmax. Check capability and numeric profile, retain buffers until terminal/drained state, and require exact-revision reports for accuracy/performance claims.",
"applies_to": "Reviewed v0.5 PRODUCT snapshot; no MLPerf, timing-closure or silicon qualification claim.",
"sources": [
"rtl/ip/multimedia/npu_reg.sv",
"rtl/ip/multimedia/apb4_npu.sv",
"scripts/npu_compiler.py",
"crt/src/hal/npu.c"
]
}
],
"programming": {
@@ -2656,7 +2548,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"**64-byte TX and RX FIFOs**; fractional baud-rate generator.\""
"text": "\"64-byte TX and RX FIFOs; fractional baud-rate generator.\""
}
]
},
@@ -2680,7 +2572,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"Two controller instances with **7-bit and 10-bit addressing**.\""
"text": "\"Two controller instances with 7-bit and 10-bit addressing.\""
}
]
},
@@ -2705,7 +2597,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"**Stereo master TX/RX** with independent audio clock.\""
"text": "\"Stereo master TX/RX with independent audio clock.\""
}
]
},
@@ -2729,7 +2621,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"Bidirectional **open-drain** host interface.\""
"text": "\"Bidirectional open-drain host interface.\""
}
]
},
@@ -2753,7 +2645,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"**24-bit GRB** transmission on one GPIO alternate function.\""
"text": "\"24-bit GRB transmission on one GPIO alternate function.\""
}
]
},
@@ -2778,7 +2670,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"SD card **SPI-mode** command/data host.\""
"text": "\"SD card SPI-mode command/data host.\""
}
]
},
@@ -2804,7 +2696,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"Native **one-bit/four-bit SDR** operation.\""
"text": "\"Native one-bit/four-bit SDR operation.\""
}
]
},
@@ -2829,7 +2721,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"Dual-role digital controller with **external 8-bit ULPI PHY**.\""
"text": "\"Dual-role digital controller with external 8-bit ULPI PHY.\""
}
]
},
@@ -2854,7 +2746,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"Four chip-select slots and **16 programmable LUT sequences**.\""
"text": "\"Four chip-select slots and 16 programmable LUT sequences.\""
}
]
},
@@ -2879,7 +2771,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"Four ESP-PSRAM64H devices addressable through a **32 MiB window**.\""
"text": "\"Four ESP-PSRAM64H devices addressable through a 32 MiB window.\""
}
]
},
@@ -2904,7 +2796,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"One octal DDR memory interface and **one selected protocol profile**.\""
"text": "\"One octal DDR memory interface and one selected protocol profile.\""
}
]
},
@@ -2929,7 +2821,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"Fixed **64 MiB, x16 SDR** geometry with bank/row tracking.\""
"text": "\"Fixed 64 MiB, x16 SDR geometry with bank/row tracking.\""
}
]
},
@@ -2953,7 +2845,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"**8-bit parallel RGB565/YUV422** capture.\""
"text": "\"8-bit parallel RGB565/YUV422 capture.\""
}
]
},
@@ -2965,7 +2857,7 @@
"title": "JPEG",
"role": "Baseline sequential codec",
"modes": "8-bit SOF0 encode/decode and the indexed raster formats; modes are mutually exclusive.",
"excluded": "No progressive/lossless/arithmetic/10-12-bit modes. DMA permits one normal read and one normal write at a time.",
"excluded": "No progressive/lossless/arithmetic/10-12-bit modes. Native SoC DMA admission is currently blocked at slot 6.",
"software": "Standalone codec/register behavior is distinct from end-to-end SoC payload availability.",
"evidence": "Source-level subset; no compliance report attached",
"sources": [
@@ -2978,7 +2870,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"8-bit **Baseline Sequential JPEG** encode or decode.\""
"text": "\"8-bit Baseline Sequential JPEG encode or decode.\""
}
]
},
@@ -2990,7 +2882,7 @@
"title": "APU",
"role": "Coreless control/transport subsystem",
"modes": "Register/transport and bounded development codec paths described in the IP chapter.",
"excluded": "MP3 unsupported; KWS requires the P7-enabled configuration. No generic codec, arbitrary TFLite, Linux ASoC or complete corpus qualification is implied.",
"excluded": "MP3 is not supported. KWS is implemented as a gated development path and remains disabled/unadvertised by default. No generic codec or full corpus qualification is implied.",
"software": "A HAL, microcode format or test source does not establish an enabled production audio service.",
"evidence": "Source-level subset; no compliance report attached",
"sources": [
@@ -3002,7 +2894,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"**Coreless microcode sequencer** with private DMA and local storage.\""
"text": "\"Coreless microcode sequencer with private DMA and local storage.\""
}
]
},
@@ -3029,30 +2921,6 @@
"text": "`define APB4_GA2D__CAPABILITY_P5 32'h0000_07ff"
}
]
},
{
"id": "npu",
"ips": [
"npu"
],
"title": "NPU",
"role": "Static INT8 tensor processing",
"modes": "Eight operator classes, checked INT32 accumulation, double-rounding requantization and native HP descriptor DMA.",
"software": "Static compiler-generated C, NPU HAL and freestanding LP/HP acceptance; preprocessing and terminal Softmax run on CPU.",
"excluded": "No arbitrary/dynamic TFLite graphs, implicit fallback, APUM binary compatibility, dedicated camera/audio stream or native Linux driver ABI.",
"evidence": "Source-level subset; no compliance report attached",
"sources": [
"rtl/ip/multimedia/npu_define.svh",
"rtl/ip/multimedia/apb4_npu.sv",
"scripts/npu_compiler.py"
],
"bindings": [
{
"file": "rtl/ip/multimedia/npu_define.svh",
"kind": "snippet",
"text": "`define APB4_NPU__CAPABILITY_P4 32'h0000_007f"
}
]
}
],
"formats": [
@@ -3326,7 +3194,7 @@
{
"file": "publications/datasheets/features.json",
"kind": "snippet",
"text": "\"**Coreless microcode sequencer** with private DMA and local storage.\""
"text": "\"Coreless microcode sequencer with private DMA and local storage.\""
}
]
}
@@ -3860,22 +3728,6 @@
"rtl/ip/multimedia/ga2d_core.sv"
]
},
{
"id": "apb4_npu",
"chapter": "npu",
"family": "npu",
"mode": "PRODUCT",
"region": "APB4_NPU",
"catalog": "npu",
"qualification": "Integrated native-HP NPU execution with eight operator classes, descriptor DMA and private SRAM; CAPABILITY=0x7F and OP_CAPABILITY=0x1FE. Resource 9 routes LP vector 33 / HP PLIC source 12. Use configured lifecycle, cache and descriptor admission rules; no native Linux driver, arbitrary model or current corpus/physical qualification is implied.",
"sources": [
"docs/ip/npu.md",
"rtl/ip/multimedia/npu_reg.sv",
"rtl/ip/multimedia/apb4_npu.sv",
"rtl/ip/multimedia/npu_control_cdc.sv",
"rtl/ip/multimedia/npu_core.sv"
]
},
{
"id": "apb4_crypto",
"chapter": "crypto",
@@ -5139,10 +4991,11 @@
3,
4,
9,
18,
9,
18,
9,
10,
18,
19,
11,
12,
13,
@@ -5150,12 +5003,11 @@
15,
16,
17,
17,
19
17
],
"expected_entries": 4,
"meanings": {
"0": "Ready checkpoint, GA2D acceptance result, cache-clean and ownership return completed; successful terminal status. NPU ownership checks apply only with RS_NPU_P5_ACCEPTANCE or RS_NPU_P6_ACCEPTANCE.",
"0": "Selected workload completed: Linux-ready, RT-Thread kernel/mailbox IRQ tests, or smoke GA2D/cache lifecycle.",
"1": "UART initialization failed; terminal failure is written directly without requiring a printable console.",
"2": "HP hold/reset/debug-selection/presence prerequisite failed.",
"3": "SDRAM did not reach the required ready/error-free state within the firmware wait.",
@@ -5173,8 +5025,8 @@
"15": "The request to hold HP after P5 GA2D completion returned an unexpected error.",
"16": "Cache-clean request, P5 GA2D cache mailbox event, clean acknowledgement, or HP-held confirmation failed.",
"17": "GA2D handoff back to LP or LP-owned safe-idle confirmation failed.",
"18": "NPU LP-owned idle prerequisite, handoff to HP, or HP-owned idle confirmation failed.",
"19": "NPU handoff back to LP or LP-owned safe-idle confirmation failed."
"18": "RT-Thread ready message failed validation or HP reported a test failure.",
"19": "LP-to-HP IRQ command failed or RT-Thread final verdict failed validation."
}
}
},
@@ -5194,7 +5046,7 @@
"app/ports/linux/linux/retrosoc_hp.config",
"app/ports/linux/linux/retrosoc_hp.dts",
"app/ports/linux/opensbi/retrosoc_hp/platform.c",
"app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp",
"app/ports/linux/hp_ready.c",
"crt/arch/riscv/startup.S",
"crt/arch/riscv/system_irq.S",
"crt/include/retrosoc/arch/riscv/system_csr.h",
@@ -5216,11 +5068,7 @@
"rtl/mini/mk/software.mk",
"scripts/build_hp_linux.py",
"scripts/regress.py",
"crt/src/hal/hp_mailbox.c",
"crt/include/retrosoc/core/status.h",
"rtl/ip/peripheral/hp_mailbox_define.svh",
"rtl/mini/address_map/memory_map.json",
"rtl/ip/peripheral/apb4_hp_mailbox.sv"
"app/ports/linux/init"
],
"bindings": [
{
@@ -5380,7 +5228,7 @@
{
"id": "kernel-sbi",
"file": "app/ports/linux/linux/retrosoc_hp.config",
"text": "CONFIG_SMP=n\nCONFIG_HVC_RISCV_SBI=y\nCONFIG_SERIAL_EARLYCON_RISCV_SBI=y"
"text": "CONFIG_SMP=n\nCONFIG_PRINTK=y\nCONFIG_TTY=y\nCONFIG_BINFMT_ELF=y\nCONFIG_BINFMT_SCRIPT=y\nCONFIG_HVC_RISCV_SBI=y\nCONFIG_SERIAL_EARLYCON_RISCV_SBI=y"
},
{
"id": "kernel-ready-support",
@@ -5390,7 +5238,7 @@
{
"id": "initrd-patch",
"file": "scripts/build_hp_linux.py",
"text": "initrd_end = LAYOUT[\"rootfs.cpio.gz\"][0] + rootfs_source.stat().st_size"
"text": "initrd_end = LAYOUT[\"rootfs.cpio\"][0] + rootfs_source.stat().st_size"
},
{
"id": "sbi-entry",
@@ -5399,8 +5247,8 @@
},
{
"id": "ready-log",
"file": "app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp",
"text": "echo \"retroSoC HP Linux ready\""
"file": "app/ports/linux/hp_ready.c",
"text": "puts(\"retroSoC HP Linux ready\")"
},
{
"id": "smoke-selection",
@@ -5607,33 +5455,6 @@
"coverage": "Discover P5 capability, submit direct single-job FILL/COPY/CONVERT/BLEND work through master 8, including A8 fixed-color foreground masks and exact equal background/destination in-place composition, verify the resource-owned LP external completion route, and inspect destinations.",
"boundary": "Exercises the direct private-AXI64 P5 functional subset only; it does not cover transparent-background/premultiplied-alpha modes, scaling, rendering, descriptor/ring/queue submission, cache coherency, a Linux graphics driver, HP P5 composition acceptance, or physical performance."
},
{
"id": "ga2d-bounded-wait",
"title": "GA2D bounded wait and timeout ownership",
"kind": "test-fail",
"code": 15,
"trigger": "rs_ci_smoke_ga2d_bounded_wait(",
"coverage": "Force a deliberately small rs_ga2d_wait budget to expire with RS_ETIMEOUT while a real SDRAM job keeps running, prove timeout expiry does not imply safe idle or buffer reclaim, then complete the job under a normal bounded wait with exact destination and counter checks, and confirm rs_ga2d_abort_wait on the idle engine.",
"boundary": "Covers LP polling-budget semantics only; it does not exercise HP-side timeout handling, watchdog TIMEOUT error recovery, or abort of an in-flight job."
},
{
"id": "ga2d-dma-contention",
"title": "GA2D and central DMA concurrent progress",
"kind": "test-fail",
"code": 16,
"trigger": "rs_ci_smoke_ga2d_dma_contention(",
"coverage": "Run a central-DMA memory-to-memory transfer and a GA2D copy concurrently in disjoint SDRAM regions, verify both payloads byte-exactly, and confirm fabric-monitor request counters advance for both master 2 and master 8 during the shared window.",
"boundary": "Covers LP CPU, central DMA, and GA2D competition with SDRAM refresh in the behavioral product; wider peripheral-master contention is evidenced in the GA2D platform testbench, and no starvation bound is proven here."
},
{
"id": "npu-p2-shell-irq",
"title": "NPU P2 shell ownership and IRQ route",
"kind": "test-fail",
"code": 17,
"trigger": "rs_ci_smoke_npu_irq(",
"coverage": "Hand resource 9 to LP through the Resource Controller quiesce/acknowledge round trip, read back the shell identity/capability, and verify the IRQ_TEST-injected event reaches external ordinal 31 and clears by W1C.",
"boundary": "Covers the P2 register shell and interrupt route only; EXECUTION_READY stays clear, the private master is tied idle, and no job, DMA, or operator behavior is exercised."
},
{
"id": "apu",
"title": "APU discovery",
@@ -5860,52 +5681,43 @@
"sources": [
"scripts/package_hp_boot.py",
"app/apps/hp_boot/hp_boot_bundle.h",
"app/apps/hp_boot/main.c"
"app/apps/hp_boot/main.c",
"app/apps/hp_boot/hp_boot_bundle.c"
],
"loader_bindings": [
{
"source": "app/apps/hp_boot/main.c",
"source": "app/apps/hp_boot/hp_boot_bundle.c",
"function": "rs_hp_boot_crc32_byte",
"body_sha256": "b048241b3b6c9507a3d2b630af3ce8e4f2dbc0cdfbe662f76a8fce8ebe6037bc"
},
{
"source": "app/apps/hp_boot/main.c",
"source": "app/apps/hp_boot/hp_boot_bundle.c",
"function": "rs_hp_boot_crc32",
"body_sha256": "ee0d898baadc9da12772f6246b2f8b4635216fe68cf67e08793865d2ca40dc90"
},
{
"source": "app/apps/hp_boot/main.c",
"function": "rs_hp_boot_range_valid",
"body_sha256": "d9bdafe55cf55481f4a4b33e5ed41e73be9cf9f18a212c8acfcf20c46e0db4ed"
},
{
"source": "app/apps/hp_boot/main.c",
"function": "rs_hp_boot_entry_expected",
"body_sha256": "742ab68f51e33c801d28e5df8f18302f8a0651621868fb5e6ed64762b0734938"
},
{
"source": "app/apps/hp_boot/main.c",
"source": "app/apps/hp_boot/hp_boot_bundle.c",
"function": "rs_hp_boot_header_valid",
"body_sha256": "2409563cb2fb7bace28215f54f83189ecbd11c2257d1959be5aed5013d7c2905"
"body_sha256": "cd86a399c2307681a36887647da8f3a585a0d6bbe5cb531b33bfdd84ad2e96a2"
}
],
"header_fields": {
"magic": "Format marker written as a little-endian 32-bit word.",
"version": "Bundle format version; distinct from the datasheet revision.",
"header_size": "Bytes in the fixed header plus all entry descriptors.",
"entry_count": "Number of fixed-order artifact entries.",
"entry_count": "Linux uses four entries; smoke and RT-Thread use one executable entry. The remaining three slots are zero.",
"total_size": "Bundle-relative byte extent from BUNDLE_OFFSET through the aligned image end; includes gaps and padding.",
"header_crc32": "CRC of the complete header/entry area with this field zeroed.",
"flags": "Generator writes REQUIRED; loader requires its bit to be set.",
"reserved": "Generator writes zero; loader has no independent zero-value check for this field."
"flags": "Must equal REQUIRED (1); extra flag bits are rejected.",
"workload": "V2 workload discriminator: 1 Linux, 2 smoke, 3 RT-Thread. Unknown values and V1 are rejected."
},
"entry_fields": {
"type": "Fixed artifact type in the expected OpenSBI, DTB, Linux, initramfs order.",
"type": "Linux uses types 1..4 in fixed order; smoke/RT-Thread use executable type 5 at 0x38000000.",
"flash_offset": "Absolute offset from the start of the flash image, not from the bundle header.",
"load_address": "Fixed destination address in the selected SDRAM map.",
"size": "Nonzero payload byte count; excludes alignment padding.",
"crc32": "CRC of exactly size payload bytes.",
"flags": "Generator writes REQUIRED; loader requires its bit to be set."
"flags": "Must equal REQUIRED (1); extra flag bits are rejected."
},
"rules": [
{
@@ -5916,8 +5728,8 @@
},
{
"topic": "Entry identity",
"producer": "Four artifacts in fixed order, with the prescribed load address and maximum size for each.",
"loader": "Checks exact type/order/load address and the per-artifact maximum, plus nonzero size and mapped ranges.",
"producer": "Workload 1: four Linux artifacts. Workloads 2/3: one executable type 5. Unused descriptor slots are zero.",
"loader": "Checks workload, exact count/type/order/address, per-artifact size limits and zero unused slots.",
"consequence": "This is not a generic relocatable image table."
},
{
@@ -5929,20 +5741,20 @@
{
"topic": "Address alignment",
"producer": "Aligns each payload start and the final cursor to PAYLOAD_ALIGNMENT.",
"loader": "Checks flash_offset and load_address modulo four, not the generator's larger boundary.",
"consequence": "Generated layout and accepted alignment are different conditions."
"loader": "Requires each absolute flash offset to be 4096-byte aligned and the exact fixed load address.",
"consequence": "Loader and packager enforce the same payload-start alignment."
},
{
"topic": "Flags and reserved word",
"producer": "Writes flags=REQUIRED and fixed-header reserved=0.",
"loader": "Requires the REQUIRED bit in header and entries. Does not independently reject extra flag bits or nonzero reserved.",
"consequence": "Preserve canonical generator values; do not claim strict reserved-bit rejection."
"topic": "Flags and workload",
"producer": "Writes flags=1 and the explicit V2 workload discriminator.",
"loader": "Rejects additional flag bits, unknown workloads, V1 and nonzero unused descriptors.",
"consequence": "Rebuild old bundles; do not infer workload from placeholder payload bytes."
},
{
"topic": "Payload placement and fill",
"producer": "Places payloads sequentially without overlap, filling unused image bytes with 0xFF.",
"loader": "Bounds each entry within the bundle/SDRAM ranges; does not independently enforce sequential disjoint extents or padding values.",
"consequence": "Do not confuse deterministic output layout with stronger validation that is absent from the loader."
"loader": "Enforces monotonic non-overlapping flash payload extents within the bundle. Exact fixed load windows are disjoint. Padding bytes are not checked.",
"consequence": "Overlap is rejected; padding is neither payload data nor authenticated metadata."
},
{
"topic": "Capacity and length",
@@ -6018,7 +5830,6 @@
"rtl/ip/multimedia/apb4_apu.sv",
"rtl/ip/multimedia/apb4_ga2d.sv",
"rtl/ip/multimedia/apb4_jpeg.sv",
"rtl/ip/multimedia/apb4_npu.sv",
"rtl/ip/multimedia/apu_control_store.sv",
"rtl/ip/multimedia/apu_define.svh",
"rtl/ip/multimedia/apu_local_sram.sv",
@@ -6039,15 +5850,6 @@
"rtl/ip/multimedia/jpeg_encode_core.sv",
"rtl/ip/multimedia/jpeg_reg.sv",
"rtl/ip/multimedia/jpeg_table_store.sv",
"rtl/ip/multimedia/npu_accumulator.sv",
"rtl/ip/multimedia/npu_control_cdc.sv",
"rtl/ip/multimedia/npu_core.sv",
"rtl/ip/multimedia/npu_define.svh",
"rtl/ip/multimedia/npu_dma.sv",
"rtl/ip/multimedia/npu_local_sram.sv",
"rtl/ip/multimedia/npu_pkg.sv",
"rtl/ip/multimedia/npu_reg.sv",
"rtl/ip/multimedia/npu_scheduler.sv",
"rtl/ip/peripheral/apb4_clint.sv",
"rtl/ip/peripheral/apb4_dma.sv",
"rtl/ip/peripheral/apb4_gpio.sv",
@@ -6163,9 +5965,6 @@
"rtl/mini/top/user_ip_top.sv",
"rtl/mini/top/user_ip_wrapper.sv",
"scripts/apu_isa.py",
"scripts/npu_compiler_p0.py",
"scripts/npu_descriptors.py",
"scripts/npu_executor.py",
"scripts/package_hp_boot.py"
],
"bindings": [
@@ -7352,110 +7151,57 @@
"soc_architecture_catalog": "publications/datasheets/soc-architecture.json"
},
"ci_snapshot": {
"revision": "c3de7c602a7ca0f0f9ade9d3ffb59339bc34fb8b",
"checked_date": "2026-09-23",
"checked_at": "2026-09-23T08:26:42Z",
"boundary": "Observed public GitHub workflow status for this exact commit. Unfinished runs have no conclusion. Installation, environment checking and runtime regression are separate evidence; workflow outcomes do not qualify unexecuted physical or silicon stages.",
"revision": "2a497ecef0b084c02f77ddfb1e94fb0197e14b02",
"checked_date": "2026-09-17",
"boundary": "Public GitHub workflow/job outcomes for this exact commit. Behavioral regression success is not synthesis, netlist, STA, formal, FPGA or silicon qualification. A failed prerequisite can leave later tests unexecuted.",
"runs": [
{
"name": "quality",
"run_id": 35833990836,
"status": "in_progress",
"conclusion": null,
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833990836",
"scope": "Repository quality checks and script/RTL fixture tests",
"note": "No terminal conclusion has been observed. No per-IP corpus or physical qualification is inferred."
},
{
"name": "regression-smoke",
"run_id": 35833991124,
"status": "completed",
"conclusion": "success",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833991124",
"scope": "Bounded IHP130 smoke regression",
"note": "Selected workflow stages completed successfully. No per-IP corpus or physical qualification is inferred."
},
{
"name": "regression-ihp130",
"run_id": 35833991071,
"status": "in_progress",
"conclusion": null,
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833991071",
"scope": "IHP130 hosted behavioral regression",
"note": "No terminal conclusion has been observed. No per-IP corpus or physical qualification is inferred."
},
{
"name": "regression-sky130",
"run_id": 35833991199,
"status": "in_progress",
"conclusion": null,
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833991199",
"scope": "SKY130 hosted behavioral regression",
"note": "No terminal conclusion has been observed. No per-IP corpus or physical qualification is inferred."
"run_id": 35035899124,
"result": "success",
"scope": "IHP130 PR behavioral-only regression",
"note": "Run pr regression passed; formal environment step skipped. Synthesis/timing environment checks are setup checks, not physical results.",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35035899124"
},
{
"name": "regression-gf180",
"run_id": 35833991194,
"status": "in_progress",
"conclusion": null,
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833991194",
"scope": "GF180 hosted behavioral regression",
"note": "No terminal conclusion has been observed. No per-IP corpus or physical qualification is inferred."
"run_id": 35035899130,
"result": "success",
"scope": "GF180 workflow",
"note": "Workflow outcome only; detailed stages require their own artifacts.",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35035899130"
},
{
"name": "regression-ics55",
"run_id": 35833991306,
"status": "in_progress",
"conclusion": null,
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833991306",
"scope": "ICS55 hosted behavioral regression",
"note": "No terminal conclusion has been observed. No per-IP corpus or physical qualification is inferred."
"run_id": 35035899146,
"result": "success",
"scope": "ICS55 workflow",
"note": "Workflow outcome only; detailed stages require their own artifacts.",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35035899146"
},
{
"name": "development-environment",
"run_id": 35833990893,
"status": "in_progress",
"conclusion": null,
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833990893",
"scope": "Docker/Nix installation, environment checks and hosted IHP130 behavioral regression",
"note": "No terminal conclusion has been observed. No per-IP corpus or physical qualification is inferred.",
"observations": [
{
"name": "docker: Build Docker development environment",
"scope": "installation",
"status": "completed",
"conclusion": "success",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833990893/job/107092965761"
},
{
"name": "docker: Run IHP130 regression in development environment",
"scope": "runtime-regression",
"status": "in_progress",
"conclusion": null,
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833990893/job/107092965761"
},
{
"name": "nix: Install Nix",
"scope": "installation",
"status": "completed",
"conclusion": "success",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833990893/job/107092965933"
},
{
"name": "nix: Check Nix flake",
"scope": "environment-check",
"status": "completed",
"conclusion": "success",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833990893/job/107092965933"
},
{
"name": "nix: Run IHP130 regression in development environment",
"scope": "runtime-regression",
"status": "completed",
"conclusion": "success",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35833990893/job/107092965933"
}
]
"name": "regression-smoke",
"run_id": 35035899140,
"result": "success",
"scope": "Smoke workflow",
"note": "Does not qualify all peripheral use cases.",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35035899140"
},
{
"name": "quality",
"run_id": 35035898949,
"result": "failure",
"scope": "Quality workflow",
"note": "Check source formatting failed. Later host tests, script tests and APU P5 acceptance were skipped.",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35035898949"
},
{
"name": "regression-sky130",
"run_id": 35035899137,
"result": "failure",
"scope": "SKY130 PR workflow",
"note": "Run pr regression failed. Do not present this platform as passing.",
"url": "https://github.com/retroSoC/retroSoC/actions/runs/35035899137"
}
]
}
+10 -5
View File
@@ -8,13 +8,10 @@ from pathlib import Path
from publications.implementation_reference import without_comments
from publications.api_bundle_reference import bundle_layout, validate_api, dependencies as api_bundle_dependencies
from publications.boot_acceptance_reference import SOURCES as BOOT_SOURCES, collect_boot_acceptance, ready_mailbox
def dependencies(spec: dict) -> set[str]:
paths = set(spec.get("sources", []))
if spec:
paths.update(BOOT_SOURCES)
paths.update(api_bundle_dependencies(spec))
paths.update(spec.get("runtime_profiles", []))
for row in spec.get("bindings", []):
@@ -177,11 +174,20 @@ def linux_platform(root: Path) -> dict:
raise ValueError("CPU and UART device-tree clock declarations disagree")
if dt_value("linux,initrd-start") != dt_value("linux,initrd-end"):
raise ValueError("reviewed initrd template placeholder changed")
ready = (root / "app/ports/linux/hp_ready.c").read_text(encoding="utf-8")
ordered = ['puts("retroSoC HP Linux ready")', 'mailbox[8] = (error == 0U) ? 1U : 3U;',
'mailbox[9] = (error == 0U) ? UINT32_C(0x4C4E5801) : error;',
'mailbox[10] = 1U;', '"fence iorw, iorw"', 'mailbox[11] = 1U;']
if any(text not in ready for text in ordered) or [ready.index(text) for text in ordered] != sorted(ready.index(text) for text in ordered):
raise ValueError("Linux ready message/publication order changed")
writes = [(0x10019020, 1), (0x10019024, 0x4C4E5801), (0x10019028, 1), (0x1001902C, 1)]
if "descriptor, 0x10019000)" not in ready:
raise ValueError("Linux mailbox mapping changed")
return {"hart_id": 1, "timebase_hz": timebase, "clock_hz": int(clocks[0]),
"cbom_bytes": dt_value("riscv,cbom-block-size"), "memory_base": memory[0][0],
"memory_bytes": int(memory[0][1], 0), "initrd_start": dt_value("linux,initrd-start"),
"initrd_template_end": dt_value("linux,initrd-end"), "bootargs": bootargs[0],
"ready_writes": ready_mailbox(root)}
"ready_writes": [{"address": f"0x{a:08X}", "value": f"0x{v:08X}"} for a, v in writes]}
def collect_software(root: Path, spec: dict) -> dict:
@@ -191,7 +197,6 @@ def collect_software(root: Path, spec: dict) -> dict:
raise ValueError("software diagnostic application coverage changed")
return {**copy.deepcopy(spec), "sources": sorted(dependencies(spec)), "profiles": runtime_profiles(root, spec),
"irq": irq_support(root), "platform": linux_platform(root),
"boot_acceptance": collect_boot_acceptance(root, function_body),
"api_reference": validate_api(root, spec["api_semantics"], function_body),
"bundle_reference": bundle_layout(root, spec["boot_bundle"], function_body),
"applications": [application_diagnostics(root, app) for app in spec["applications"]]}
+1
View File
@@ -6,6 +6,7 @@ automation.
- `build.txt` provides dependencies for setup, build, and regression helpers.
- `ci.txt` provides the fast quality tools, including Python lint and test
dependencies.
- `rtthread.txt` pins SCons for the isolated HP RT-Thread build environment.
Update requirements deliberately and keep their hashes/pins compatible with
the repository lock policy. Validate the affected commands locally and in CI;
+4
View File
@@ -0,0 +1,4 @@
# Official RT-Thread build frontend, isolated from the SDK Python environment.
--only-binary=:all:
--require-hashes
scons==4.8.1 --hash=sha256:a4c3b434330e2d7d975002fd6783284ba348bf394db94c8f83fdc5bf69cdb8d7
+110 -80
View File
@@ -108,11 +108,11 @@ module axi4_data_crossbar #(
logic user;
} read_resp_t;
addr_channel_t m_aw [NumMasters];
addr_channel_t m_ar [NumMasters];
write_channel_t m_w [NumMasters];
write_resp_t m_b [NumMasters];
read_resp_t m_r [NumMasters];
addr_channel_t m_aw [NumMasters];
addr_channel_t m_ar [NumMasters];
write_channel_t m_w [NumMasters];
write_resp_t m_b [NumMasters];
read_resp_t m_r [NumMasters];
logic [NumMasters-1:0] m_awvalid;
logic [NumMasters-1:0] m_awready;
logic [NumMasters-1:0] m_wvalid;
@@ -124,11 +124,11 @@ module axi4_data_crossbar #(
logic [NumMasters-1:0] m_rvalid;
logic [NumMasters-1:0] m_rready;
addr_channel_t t_aw [NumTargets];
addr_channel_t t_ar [NumTargets];
write_channel_t t_w [NumTargets];
write_resp_t t_b [NumTargets];
read_resp_t t_r [NumTargets];
addr_channel_t t_aw [NumTargets];
addr_channel_t t_ar [NumTargets];
write_channel_t t_w [NumTargets];
write_resp_t t_b [NumTargets];
read_resp_t t_r [NumTargets];
logic [NumTargets-1:0] t_awvalid;
logic [NumTargets-1:0] t_awready;
logic [NumTargets-1:0] t_wvalid;
@@ -154,6 +154,7 @@ module axi4_data_crossbar #(
logic [NumTargets-1:0] s_write_capture;
logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_req;
logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_arb_req;
logic [NumMasters-1:0][ NumTargets-1:0] s_write_resp_req;
logic [NumMasters-1:0][ NumTargets-1:0] unused_read_resp_grant;
logic [NumMasters-1:0][ NumTargets-1:0] unused_write_resp_grant;
@@ -163,27 +164,30 @@ module axi4_data_crossbar #(
logic [NumMasters-1:0] s_write_resp_valid;
logic [NumMasters-1:0] s_read_terminal;
logic [NumMasters-1:0] s_write_terminal;
logic [NumTargets-1:0] s_invalid_read_response;
logic [NumTargets-1:0] s_invalid_write_response;
logic [NumTargets-1:0] s_invalid_read_fault_accept;
logic [NumTargets-1:0] s_invalid_write_fault_accept;
logic s_protocol_fault_pending;
logic s_protocol_fault_event;
logic s_protocol_recovery_q;
logic [NumMasters-1:0] s_read_resp_lock_d, s_read_resp_lock_q;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_d;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_q;
logic [NumTargets-1:0] s_invalid_read_response;
logic [NumTargets-1:0] s_invalid_write_response;
logic [NumTargets-1:0] s_invalid_read_fault_accept;
logic [NumTargets-1:0] s_invalid_write_fault_accept;
logic s_protocol_fault_pending;
logic s_protocol_fault_event;
logic s_protocol_recovery_q;
logic [NumTargets-1:0] s_target_write_owner_full;
logic [NumTargets-1:0] s_target_write_owner_empty;
logic [NumTargets-1:0] s_target_write_owner_push;
logic [NumTargets-1:0] s_target_write_owner_pop;
logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data;
logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count;
logic [NumTargets-1:0] s_target_write_owner_full;
logic [NumTargets-1:0] s_target_write_owner_empty;
logic [NumTargets-1:0] s_target_write_owner_push;
logic [NumTargets-1:0] s_target_write_owner_pop;
logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data;
logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target;
logic [NumMasters-1:0][ 3:0] s_read_fault_reason;
logic [NumMasters-1:0][ 3:0] s_write_fault_reason;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target;
logic [NumMasters-1:0][ 3:0] s_read_fault_reason;
logic [NumMasters-1:0][ 3:0] s_write_fault_reason;
logic [NumMasters-1:0][CountWidth-1:0] s_master_read_count_d, s_master_read_count_q;
logic [NumMasters-1:0][CountWidth-1:0] s_master_write_count_d, s_master_write_count_q;
@@ -388,7 +392,7 @@ module axi4_data_crossbar #(
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.advance_i (s_read_terminal[master]),
.request_i (s_read_resp_req[master]),
.request_i (s_read_resp_arb_req[master]),
.grant_o (unused_read_resp_grant[master]),
.selected_o(s_read_resp_selected[master]),
.valid_o (s_read_resp_valid[master])
@@ -406,6 +410,20 @@ module axi4_data_crossbar #(
);
end
always_comb begin
// Keep all beats of one read burst on its selected target. AXI read
// responses may complete out of order by ID, but beats of a burst must
// not be interleaved with another target's burst on the same master.
s_read_resp_arb_req = s_read_resp_req;
for (int master = 0; master < NumMasters; master++) begin
if (s_read_resp_lock_q[master]) begin
s_read_resp_arb_req[master] = '0;
s_read_resp_arb_req[master][s_read_resp_lock_target_q[master]] =
s_read_resp_req[master][s_read_resp_lock_target_q[master]];
end
end
end
for (genvar target = 0; target < NumTargets; target++) begin : gen_target_ports
assign targets[target].awid = t_aw[target].id;
assign targets[target].awaddr = t_aw[target].addr;
@@ -846,18 +864,24 @@ module axi4_data_crossbar #(
end
always_comb begin
s_master_read_count_d = s_master_read_count_q;
s_master_write_count_d = s_master_write_count_q;
s_target_read_count_d = s_target_read_count_q;
s_target_write_count_d = s_target_write_count_q;
s_read_id_busy_d = s_read_id_busy_q;
s_write_id_busy_d = s_write_id_busy_q;
s_master_read_count_d = s_master_read_count_q;
s_master_write_count_d = s_master_write_count_q;
s_target_read_count_d = s_target_read_count_q;
s_target_write_count_d = s_target_write_count_q;
s_read_id_busy_d = s_read_id_busy_q;
s_write_id_busy_d = s_write_id_busy_q;
s_read_resp_lock_d = s_read_resp_lock_q;
s_read_resp_lock_target_d = s_read_resp_lock_target_q;
for (int master = 0; master < NumMasters; master++) begin
if (s_read_terminal[master]) begin
s_master_read_count_d[master] = s_master_read_count_d[master] - 1'b1;
s_target_read_count_d[s_read_resp_selected[master]] =
s_target_read_count_d[s_read_resp_selected[master]] - 1'b1;
s_read_id_busy_d[master][s_read_complete_id[master]] = 1'b0;
s_read_resp_lock_d[master] = 1'b0;
end else if (!s_read_resp_lock_q[master] && s_read_resp_valid[master]) begin
s_read_resp_lock_d[master] = 1'b1;
s_read_resp_lock_target_d[master] = s_read_resp_selected[master];
end
if (s_write_terminal[master]) begin
s_master_write_count_d[master] = s_master_write_count_d[master] - 1'b1;
@@ -972,53 +996,59 @@ module axi4_data_crossbar #(
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
fault_valid_o <= 1'b0;
fault_master_o <= '0;
fault_target_o <= '0;
fault_addr_o <= '0;
fault_write_o <= 1'b0;
fault_reason_o <= '0;
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_read_resp_lock_q <= '0;
s_read_resp_lock_target_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
fault_valid_o <= 1'b0;
fault_master_o <= '0;
fault_target_o <= '0;
fault_addr_o <= '0;
fault_write_o <= 1'b0;
fault_reason_o <= '0;
end else begin
if (flush_i) begin
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_read_resp_lock_q <= '0;
s_read_resp_lock_target_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
end else begin
s_master_read_count_q <= s_master_read_count_d;
s_master_write_count_q <= s_master_write_count_d;
s_target_read_count_q <= s_target_read_count_d;
s_target_write_count_q <= s_target_write_count_d;
s_read_id_busy_q <= s_read_id_busy_d;
s_write_id_busy_q <= s_write_id_busy_d;
s_write_route_q <= s_write_route_d;
s_route_read_ptr_q <= s_route_read_ptr_d;
s_route_write_ptr_q <= s_route_write_ptr_d;
s_route_count_q <= s_route_count_d;
s_read_age_q <= s_read_age_d;
s_write_age_q <= s_write_age_d;
s_master_read_count_q <= s_master_read_count_d;
s_master_write_count_q <= s_master_write_count_d;
s_target_read_count_q <= s_target_read_count_d;
s_target_write_count_q <= s_target_write_count_d;
s_read_id_busy_q <= s_read_id_busy_d;
s_write_id_busy_q <= s_write_id_busy_d;
s_read_resp_lock_q <= s_read_resp_lock_d;
s_read_resp_lock_target_q <= s_read_resp_lock_target_d;
s_write_route_q <= s_write_route_d;
s_route_read_ptr_q <= s_route_read_ptr_d;
s_route_write_ptr_q <= s_route_write_ptr_d;
s_route_count_q <= s_route_count_d;
s_read_age_q <= s_read_age_d;
s_write_age_q <= s_write_age_d;
if (s_protocol_fault_event) s_protocol_recovery_q <= 1'b1;
end
if (!fault_valid_o || fault_ready_i) begin
+9 -2
View File
@@ -127,11 +127,18 @@ than replace, the common `SIM_TEST_PASS` simulation verdict.
the fixed HP core below `build/`; generated RTL is never tracked.
`setup_hp_linux.py` installs the locked OpenSBI, Linux, and Buildroot revisions
and can resume a checkout left without `HEAD` by an interrupted fetch.
`build_hp_linux.py` builds the RV32 `ilp32d` image set with the repo-owned
external OpenSBI platform. `package_hp_boot.py` creates the v1 LP/HP flash
`build_hp_linux.py` builds the RV64 `lp64d` userspace/OpenSBI image set with the repo-owned
external OpenSBI platform. `package_hp_boot.py` creates the V2 typed LP/HP flash
bundle and its SHA-256/CRC manifest. `check_lp_hp_performance.py` applies the
measured 2.5x CoreMark/MHz gate.
`setup_hp_rtthread.py` installs the locked kernel, RV64 bare-metal compiler and
isolated SCons environment. `build_hp_rtthread.py` stages only the repository BSP
under the variant and records the source/compiler/configuration inputs.
`hp_tools.py` checks source revisions and RV64 ELF class. `run_hp_sim.py` keeps
Linux, smoke and RT-Thread logs/verdicts separate and checks every required
workload marker together with a successful process exit.
`run_debug_session.py` is the local Hazard3 debug acceptance driver. It starts
the Verilator remote-bitbang endpoint, the lock-pinned OpenOCD binary, and
RISC-V GDB, then records their logs and a structured result. Invoke it through
+125 -14
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Build the pinned RV32 HP Buildroot, Linux, DTB, and OpenSBI images."""
"""Build pinned RV64 Linux images with a small, static acceptance initramfs."""
from __future__ import annotations
@@ -11,21 +11,45 @@ import shutil
import subprocess
from pathlib import Path
try:
from scripts.hp_tools import require_revision, require_rv64_elf
except ModuleNotFoundError:
from hp_tools import require_revision, require_rv64_elf
LAYOUT = {
"fw_jump.bin": (0x38000000, 512 * 1024),
"retrosoc_hp.dtb": (0x38080000, 64 * 1024),
"Image": (0x38400000, 12 * 1024 * 1024),
"rootfs.cpio.gz": (0x39000000, 8 * 1024 * 1024),
"rootfs.cpio": (0x39000000, 8 * 1024 * 1024),
}
REQUIRED_LINUX_CONFIG = (
"CONFIG_ARCH_RV64I",
"CONFIG_64BIT",
"CONFIG_MMU",
"CONFIG_OF_RESERVED_MEM",
"CONFIG_BINFMT_ELF",
"CONFIG_BINFMT_SCRIPT",
"CONFIG_PRINTK",
"CONFIG_TTY",
"CONFIG_HVC_RISCV_SBI",
"CONFIG_SERIAL_EARLYCON_RISCV_SBI",
"CONFIG_PROC_FS",
"CONFIG_SYSFS",
"CONFIG_SHMEM",
"CONFIG_TMPFS",
"CONFIG_DEVTMPFS",
"CONFIG_DEVMEM",
)
def command(arguments: list[str], cwd: Path) -> None:
def command(arguments: list[str], cwd: Path, extra_env: dict[str, str] | None = None) -> None:
environment = dict(os.environ)
environment.pop("CONFIG", None)
environment.pop("MAKEFLAGS", None)
environment.pop("MAKEOVERRIDES", None)
environment.pop("MFLAGS", None)
environment.update(extra_env or {})
subprocess.run(arguments, cwd=cwd, check=True, env=environment)
@@ -51,12 +75,65 @@ def source_revision(path: Path) -> str:
def find_toolchain(buildroot_output: Path) -> str:
matches = sorted((buildroot_output / "host/bin").glob("riscv32*-linux-*-gcc"))
matches = sorted((buildroot_output / "host/bin").glob("riscv64*-linux-*-gcc"))
if len(matches) != 1:
raise RuntimeError(f"expected one RV32 Linux GCC in {buildroot_output / 'host/bin'}")
raise RuntimeError(f"expected one RV64 Linux GCC in {buildroot_output / 'host/bin'}")
return str(matches[0])[: -len("gcc")]
def minimal_busybox(buildroot: Path, output: Path, external: Path, jobs: int) -> str:
"""Expand an allowlist using BusyBox's own allnoconfig, not default-y oldconfig."""
make = ["make", f"O={output}", f"BR2_EXTERNAL={external}", f"-j{jobs}"]
command([*make, "busybox-configure"], buildroot)
sources = [path for path in (output / "build").glob("busybox-*")
if (path / "scripts/kconfig/conf").is_file()]
if len(sources) != 1:
raise RuntimeError("expected one configured locked BusyBox source")
source = sources[0]
config_dir = output.parent / "busybox-config"
(config_dir / "include").mkdir(parents=True, exist_ok=True)
command([str(source / "scripts/kconfig/conf"), "-n", str(source / "Config.in")], config_dir,
{"srctree": str(source), "KCONFIG_NOTIMESTAMP": "1",
"KCONFIG_ALLCONFIG": str(external / "busybox/retrosoc_hp.config")})
# This BusyBox conf implementation resets booleans even when ALLCONFIG
# specified y. Overlay our explicit choices after its all-no expansion;
# Buildroot's ordinary oldconfig then resolves the real dependencies.
selected = dict(line.split("=", 1) for line in
(external / "busybox/retrosoc_hp.config").read_text().splitlines()
if line.startswith("CONFIG_") and "=" in line)
config = config_dir / ".config"
lines = []
for line in config.read_text().splitlines():
key = line[2:].split(" ", 1)[0] if line.startswith("# CONFIG_") else line.split("=", 1)[0]
lines.append(f"{key}={selected.pop(key)}" if key in selected else line)
lines.extend(f"{key}={value}" for key, value in selected.items())
config.write_text("\n".join(lines) + "\n", encoding="utf-8")
config_arg = f"BUSYBOX_CONFIG_FILE={config_dir / '.config'}"
command([*make, config_arg, "busybox-reconfigure"], buildroot)
return config_arg
def validate_linux_config(config: Path) -> None:
values: dict[str, str] = {}
for line in config.read_text(encoding="utf-8").splitlines():
if line.startswith("CONFIG_") and "=" in line:
symbol, value = line.split("=", 1)
values[symbol] = value
elif line.startswith("# CONFIG_") and line.endswith(" is not set"):
symbol = line[len("# ") : -len(" is not set")]
values[symbol] = "n"
invalid = [
f"{symbol}={values.get(symbol, 'missing')}"
for symbol in REQUIRED_LINUX_CONFIG
if values.get(symbol) != "y"
]
if invalid:
raise RuntimeError(
"invalid HP Linux effective configuration: " + ", ".join(invalid)
)
def build(args: argparse.Namespace) -> None:
root = args.root.resolve()
output = args.output.resolve()
@@ -64,6 +141,9 @@ def build(args: argparse.Namespace) -> None:
buildroot = require_source(args.buildroot, "Buildroot")
linux = require_source(args.linux, "Linux")
opensbi = require_source(args.opensbi, "OpenSBI")
for name, path in (("buildroot_hp", buildroot), ("linux_hp", linux), ("opensbi_hp", opensbi)):
if path != require_revision(root, name).resolve():
raise ValueError(f"{name} must use its locked source directory")
external = root / "app/ports/linux"
buildroot_output = output / "buildroot"
@@ -71,7 +151,16 @@ def build(args: argparse.Namespace) -> None:
["make", f"O={buildroot_output}", f"BR2_EXTERNAL={external}", "retrosoc_hp_defconfig"],
buildroot,
)
command(["make", f"O={buildroot_output}", f"BR2_EXTERNAL={external}", f"-j{args.jobs}"], buildroot)
busybox_config = minimal_busybox(buildroot, buildroot_output, external, args.jobs)
command(["make", f"O={buildroot_output}", f"BR2_EXTERNAL={external}",
busybox_config, f"-j{args.jobs}"], buildroot)
busybox_sources = sorted((buildroot_output / "build").glob("busybox-*/.config"))
if len(busybox_sources) != 1:
raise RuntimeError("missing effective BusyBox configuration")
busybox_effective = busybox_sources[0].read_text().splitlines()
for symbol in ("STATIC", "BUSYBOX", "ASH", "MOUNT", "TEST", "ECHO", "CAT", "TRUE"):
if f"CONFIG_{symbol}=y" not in busybox_effective:
raise RuntimeError(f"HP BusyBox requires CONFIG_{symbol}=y")
cross_compile = find_toolchain(buildroot_output)
linux_output = output / "linux"
@@ -94,6 +183,7 @@ def build(args: argparse.Namespace) -> None:
["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}", "olddefconfig"],
linux,
)
validate_linux_config(linux_output / ".config")
command(
["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}",
f"-j{args.jobs}", "Image"],
@@ -102,10 +192,28 @@ def build(args: argparse.Namespace) -> None:
image_dir = output / "images"
image_dir.mkdir(parents=True, exist_ok=True)
rootfs_source = buildroot_output / "images/rootfs.cpio.gz"
if not rootfs_source.is_file():
raise FileNotFoundError(f"HP Linux build output is missing: {rootfs_source}")
initrd_end = LAYOUT["rootfs.cpio.gz"][0] + rootfs_source.stat().st_size
require_rv64_elf(linux_output / "vmlinux")
busybox = buildroot_output / "target/bin/busybox"
require_rv64_elf(busybox)
if "INTERP" in subprocess.check_output([cross_compile + "readelf", "-l", str(busybox)], text=True):
raise ValueError("HP acceptance BusyBox must be statically linked")
helper = output / "hp-ready"
command([cross_compile + "gcc", "-Os", "-static", "-Wall", "-Wextra", "-Werror",
"-o", str(helper), str(external / "hp_ready.c")], root)
require_rv64_elf(helper)
archive_spec = output / "initramfs.list"
entries = [f"dir /{name} 755 0 0" for name in ("bin", "dev", "proc", "sys", "tmp")]
entries += [f"file /bin/busybox {busybox} 755 0 0",
f"file /bin/hp-ready {helper} 755 0 0", f"file /init {external / 'init'} 755 0 0",
"nod /dev/console 600 0 0 c 5 1", "nod /dev/mem 600 0 0 c 1 1"]
entries += [f"slink /bin/{name} busybox 777 0 0" for name in
("sh", "mount", "mkdir", "echo", "test", "cat", "sleep")]
archive_spec.write_text("\n".join(entries) + "\n", encoding="utf-8")
rootfs_source = image_dir / "rootfs.cpio"
with rootfs_source.open("wb") as archive:
subprocess.run([str(linux_output / "usr/gen_init_cpio"), "-t", "0", str(archive_spec)],
stdout=archive, check=True)
initrd_end = LAYOUT["rootfs.cpio"][0] + rootfs_source.stat().st_size
command(
[
"dtc",
@@ -140,9 +248,9 @@ def build(args: argparse.Namespace) -> None:
f"CROSS_COMPILE={cross_compile}",
"PLATFORM=retrosoc_hp",
f"PLATFORM_DIR={external / 'opensbi'}",
"PLATFORM_RISCV_XLEN=32",
"PLATFORM_RISCV_ABI=ilp32d",
"PLATFORM_RISCV_ISA=rv32imafdc_zicbom_zicsr_zifencei",
"PLATFORM_RISCV_XLEN=64",
"PLATFORM_RISCV_ABI=lp64d",
"PLATFORM_RISCV_ISA=rv64imafdc_zicbom_zicsr_zifencei",
"FW_TEXT_START=0x38000000",
"FW_JUMP=y",
"FW_JUMP_ADDR=0x38400000",
@@ -155,15 +263,18 @@ def build(args: argparse.Namespace) -> None:
copies = {
opensbi_output / "platform/retrosoc_hp/firmware/fw_jump.bin": image_dir / "fw_jump.bin",
linux_output / "arch/riscv/boot/Image": image_dir / "Image",
rootfs_source: image_dir / "rootfs.cpio.gz",
}
for source, destination in copies.items():
if not source.is_file():
raise FileNotFoundError(f"HP Linux build output is missing: {source}")
shutil.copy2(source, destination)
require_rv64_elf(opensbi_output / "platform/retrosoc_hp/firmware/fw_jump.elf")
manifest: dict[str, object] = {
"schema_version": 1,
"xlen": 64,
"abi": "lp64d",
"initramfs": "minimal-static-uncompressed",
"boot_flow": "opensbi-fw_jump",
"hart_id": 1,
"sources": {
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Build the repository BSP against the unmodified, locked RT-Thread kernel."""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import re
import shutil
import subprocess
from pathlib import Path
try:
from scripts.hp_tools import cross_prefix, require_revision, require_rv64_elf
except ModuleNotFoundError:
from hp_tools import cross_prefix, require_revision, require_rv64_elf
def build(root: Path, output: Path, jobs: int) -> None:
source = require_revision(root, "rtthread_hp")
bsp = output / "bsp"
bsp.mkdir(parents=True, exist_ok=True)
for path in (root / "app/ports/rtthread").iterdir():
if path.is_file():
shutil.copy2(path, bsp / path.name)
environment = dict(os.environ)
for key in ("CONFIG", "MAKEFLAGS", "MAKEOVERRIDES", "MFLAGS"):
environment.pop(key, None)
environment.update(RTT_ROOT=str(source), RTT_EXEC_PATH=str(Path(cross_prefix(root)).parent),
RETROSOC_ROOT=str(root))
expected = re.search(r"^scons==([\d.]+)", (root / "requirements/rtthread.txt").read_text(), re.M)
actual = subprocess.check_output([str(root / ".cache/retrosoc/rtthread-venv/bin/python"),
"-c", "import SCons; print(SCons.__version__)"], text=True).strip()
if expected is None or actual != expected[1]:
raise ValueError(f"RT-Thread SCons version does not match requirements: {actual}")
subprocess.run([str(root / ".cache/retrosoc/rtthread-venv/bin/scons"), f"-j{jobs}"],
cwd=bsp, env=environment, check=True)
require_rv64_elf(bsp / "rtthread.elf")
images = output / "images"
images.mkdir(parents=True, exist_ok=True)
for name in ("rtthread.elf", "rtthread.bin", "rtthread.map"):
shutil.copy2(bsp / name, images / name)
revision = subprocess.check_output(["git", "-C", str(source), "rev-parse", "HEAD"],
text=True).strip()
manifest = {"schema_version": 1, "xlen": 64, "abi": "lp64d", "hart_id": 1,
"rtthread_revision": revision,
"scons_version": actual,
"compiler": subprocess.check_output([cross_prefix(root) + "gcc", "--version"],
text=True).splitlines()[0],
"sha256": hashlib.sha256((images / "rtthread.bin").read_bytes()).hexdigest()}
manifest["inputs"] = {str(path.relative_to(root)): hashlib.sha256(path.read_bytes()).hexdigest()
for path in sorted((root / "app/ports/rtthread").iterdir()) if path.is_file()}
manifest["inputs"]["requirements/rtthread.txt"] = hashlib.sha256(
(root / "requirements/rtthread.txt").read_bytes()).hexdigest()
(images / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--jobs", type=int, default=1)
args = parser.parse_args()
build(args.root.resolve(), args.output.resolve(), args.jobs)
if __name__ == "__main__":
main()
+4 -1
View File
@@ -86,7 +86,10 @@ def generate(args: argparse.Namespace) -> None:
manifest = {
"schema_version": 1,
"module": GENERATED_MODULE,
"configuration": "rv32imafdc_zicbom_max",
"configuration": "rv64imafdc_zicbom_max",
"xlen": 64,
"physical_address_width": 32,
"mmu": "sv39",
"vexiiriscv_revision": actual,
"source_status": git_status(source),
"submodules": submodules,
+46
View File
@@ -0,0 +1,46 @@
"""Shared locked RV64 build helpers for HP payloads."""
from __future__ import annotations
import argparse
import struct
import subprocess
from pathlib import Path
try:
from scripts.dependency_lock import load_lock
except ModuleNotFoundError:
from dependency_lock import load_lock
def cross_prefix(root: Path) -> str:
spec = load_lock(root / "dependencies/dependencies.lock.json")["toolchains"]["ubuntu-22.04"][
"riscv_gnu_hp"
]
return str(root / ".cache/retrosoc/development/toolchains" /
f"riscv_gnu_hp-{spec['version']}" / spec["path"] / "riscv64-unknown-elf-")
def require_rv64_elf(path: Path) -> None:
header = path.read_bytes()[:64]
if (len(header) < 64 or header[:6] != b"\x7fELF\x02\x01" or
struct.unpack_from("<H", header, 18)[0] != 243):
raise ValueError(f"expected a little-endian RV64 ELF: {path}")
def require_revision(root: Path, name: str) -> Path:
spec = load_lock(root / "dependencies/dependencies.lock.json")["sources"][name]
source = root / spec["destination"]
actual = subprocess.check_output(["git", "-C", str(source), "rev-parse", "HEAD"], text=True).strip()
if actual != spec["revision"]:
raise ValueError(f"{name} revision mismatch: {actual} != {spec['revision']}")
if subprocess.run(["git", "-C", str(source), "diff", "--quiet", "HEAD", "--"],
check=False).returncode:
raise ValueError(f"{name} has modified tracked source files: {source}")
return source
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, required=True)
print(cross_prefix(parser.parse_args().root.resolve()))
+24 -9
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Package LP firmware and the fixed HP Linux image set into one flash image."""
"""Package LP firmware and a typed RV64 HP workload into a V2 flash image."""
from __future__ import annotations
@@ -15,7 +15,7 @@ FLASH_SIZE = 16 * 1024 * 1024
BUNDLE_OFFSET = 1 * 1024 * 1024
PAYLOAD_ALIGNMENT = 4096
MAGIC = 0x50485352
VERSION = 1
VERSION = 2
REQUIRED = 1
HEADER = struct.Struct("<8I")
ENTRY = struct.Struct("<6I")
@@ -23,9 +23,19 @@ ARTIFACTS = (
(1, "fw_jump.bin", 0x38000000, 512 * 1024),
(2, "retrosoc_hp.dtb", 0x38080000, 64 * 1024),
(3, "Image", 0x38400000, 12 * 1024 * 1024),
(4, "rootfs.cpio.gz", 0x39000000, 8 * 1024 * 1024),
(4, "rootfs.cpio", 0x39000000, 8 * 1024 * 1024),
)
HEADER_SIZE = HEADER.size + (ENTRY.size * len(ARTIFACTS))
WORKLOADS = {"linux": 1, "smoke": 2, "rtthread": 3}
def artifacts_for(workload: str) -> tuple[tuple[int, str, int, int], ...]:
if workload == "linux":
return ARTIFACTS
if workload not in WORKLOADS:
raise ValueError(f"unsupported HP workload: {workload}")
name = "hp_smoke.bin" if workload == "smoke" else "rtthread.bin"
return ((5, name, 0x38000000, 512 * 1024),)
def align_up(value: int, alignment: int) -> int:
@@ -37,6 +47,8 @@ def sha256(data: bytes) -> str:
def package(args: argparse.Namespace) -> None:
workload = getattr(args, "workload", "linux")
artifacts = artifacts_for(workload)
firmware = args.firmware.read_bytes()
if len(firmware) > BUNDLE_OFFSET:
raise ValueError(
@@ -48,7 +60,7 @@ def package(args: argparse.Namespace) -> None:
payloads: list[tuple[int, bytes]] = []
artifact_manifest: dict[str, object] = {}
cursor = payload_offset
for kind, name, load_address, maximum in ARTIFACTS:
for kind, name, load_address, maximum in artifacts:
data = (args.images / name).read_bytes()
if not data or len(data) > maximum:
raise ValueError(f"{name} size {len(data)} is outside 1..{maximum} bytes")
@@ -75,8 +87,8 @@ def package(args: argparse.Namespace) -> None:
total_size,
0,
REQUIRED,
0,
) + b"".join(entries)
WORKLOADS[workload],
) + b"".join(entries).ljust(HEADER_SIZE - HEADER.size, b"\0")
header_crc32 = zlib.crc32(header) & 0xFFFFFFFF
header = HEADER.pack(
MAGIC,
@@ -86,8 +98,8 @@ def package(args: argparse.Namespace) -> None:
total_size,
header_crc32,
REQUIRED,
0,
) + b"".join(entries)
WORKLOADS[workload],
) + b"".join(entries).ljust(HEADER_SIZE - HEADER.size, b"\0")
image = bytearray(b"\xFF" * cursor)
image[: len(firmware)] = firmware
@@ -99,7 +111,9 @@ def package(args: argparse.Namespace) -> None:
args.output.write_bytes(image)
manifest = {
"schema_version": 1,
"format": "retrosoc-hp-boot-bundle-v1",
"format": "retrosoc-hp-boot-bundle-v2",
"workload": workload,
"xlen": 64,
"bundle_offset": f"0x{BUNDLE_OFFSET:08X}",
"flash_capacity_bytes": FLASH_SIZE,
"header_crc32": f"0x{header_crc32:08X}",
@@ -120,6 +134,7 @@ def main() -> None:
parser.add_argument("--images", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--manifest", type=Path, required=True)
parser.add_argument("--workload", choices=WORKLOADS, default="linux")
package(parser.parse_args())
+1 -1
View File
@@ -210,7 +210,7 @@ def main() -> int:
"duration_seconds": round(time.monotonic() - start_clock, 3),
"peak_rss_kib": resource.getrusage(resource.RUSAGE_CHILDREN).ru_maxrss,
"exit_code": returncode,
"status": "passed" if returncode == 0 else "failed",
"status": "interrupted" if returncode == 130 else ("passed" if returncode == 0 else "failed"),
"log": str(args.log.resolve()),
}
if error_message:
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""Run and validate one HP workload without reusing another workload's verdict."""
from __future__ import annotations
import argparse
import json
import subprocess
import sys
from pathlib import Path
MARKERS = {
"smoke": ("HP_LINUX_READY", "HP_GA2D_PASS", "HP_GA2D_CACHE_CLEAN"),
"linux": ("HP_LINUX_INIT_PASS", "retroSoC HP Linux ready", "HP_LINUX_READY"),
"rtthread": ("RTTHREAD_RV64_PASS", "RTTHREAD_TIMEOUT_PASS", "RTTHREAD_PREEMPT_PASS",
"RTTHREAD_CONTEXT_PASS", "RTTHREAD_IPC_PASS", "RTTHREAD_MAILBOX_IRQ_PASS",
"RTTHREAD_TEST_PASS", "HP_RTTHREAD_PASS"),
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--emulator", type=Path, required=True)
parser.add_argument("--image", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--workload", choices=MARKERS, required=True)
parser.add_argument("--timeout", type=int, required=True)
args = parser.parse_args()
output = args.output.resolve()
output.mkdir(parents=True, exist_ok=True)
result = output / "result-sim-check.json"
result.write_text(json.dumps({"status": "running", "workload": args.workload}) + "\n",
encoding="utf-8")
scripts = Path(__file__).resolve().parent
try:
process = subprocess.run([
sys.executable, str(scripts / "run_flow.py"), "--tool", "verilator-sim",
"--stream-bytes", "--log", str(output / "sim.log"), "--result",
str(output / "result-sim.json"), "--cwd", str(output), "--",
str(args.emulator.resolve()), "-i", str(args.image.resolve()),
"--fast-flash", "-t", str(args.timeout),
], check=False)
if process.returncode:
result.write_text(json.dumps({"status": "failed", "exit_code": process.returncode})
+ "\n", encoding="utf-8")
return process.returncode
command = [sys.executable, str(scripts / "check_simulation.py"), "--log",
str(output / "sim.log"), "--result", str(result)]
for marker in ("VERILATOR_FAST_FLASH=enabled", "SIM_TEST_PASS code=0",
*MARKERS[args.workload]):
command.extend(("--require", marker))
return subprocess.run(command, check=False).returncode
except KeyboardInterrupt:
result.write_text('{"status": "interrupted"}\n', encoding="utf-8")
return 130
if __name__ == "__main__":
raise SystemExit(main())
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Install the locked RT-Thread source, RV64 compiler and SCons environment."""
from __future__ import annotations
import argparse
import venv
from pathlib import Path
from dependency_lock import load_lock
from install_toolchain import install
from setup_helpers import ensure_git_repo, run
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--update", action="store_true")
args = parser.parse_args()
root = Path(__file__).resolve().parents[1]
lock = load_lock()
spec = lock["sources"]["rtthread_hp"]
ensure_git_repo(spec["url"], root / spec["destination"], spec["revision"], update=args.update)
install("riscv_gnu_hp", lock["toolchains"]["ubuntu-22.04"]["riscv_gnu_hp"],
root / ".cache/retrosoc/development", args.update)
environment = root / ".cache/retrosoc/rtthread-venv"
if not (environment / "bin/python").is_file():
venv.EnvBuilder(with_pip=True).create(environment)
run((str(environment / "bin/python"), "-m", "pip", "install", "--require-hashes",
"--cache-dir", str(root / ".cache/retrosoc/pip"),
"-r", str(root / "requirements/rtthread.txt")))
if __name__ == "__main__":
main()
+2 -2
View File
@@ -8,7 +8,7 @@ import vexiiriscv.misc.EmbeddedRiscvJtag
import java.nio.file.{Files, Paths}
/** Generates the fixed retroSoC RV32 Linux application core. */
/** Generates the fixed retroSoC RV64 application core. */
object GenerateRetroSocHp extends App {
require(args.length == 1, "usage: GenerateRetroSocHp <output-directory>")
@@ -16,7 +16,7 @@ object GenerateRetroSocHp extends App {
Files.createDirectories(output)
val param = new ParamSimple()
param.xlen = 32
param.xlen = 64
param.physicalWidth = 32
param.resetVector = 0x38000000L
param.asidWidth = 9
+111
View File
@@ -120,6 +120,54 @@ module axi4_data_crossbar_tb;
end
endtask
task automatic issue_master1_read_burst(input logic [6:0] id, input logic [31:0] addr);
begin
@(negedge clk_i);
masters[1].arid = id;
masters[1].araddr = addr;
masters[1].arlen = 8'd7;
masters[1].arsize = 3'd3;
masters[1].arburst = 2'b01;
masters[1].arvalid = 1'b1;
do @(posedge clk_i); while (!masters[1].arready);
@(negedge clk_i);
masters[1].arvalid = 1'b0;
masters[1].arlen = '0;
end
endtask
task automatic return_target0_burst(input logic [6:0] id, input logic [63:0] data_base);
begin
for (int unsigned beat = 0; beat < 8; beat++) begin
@(negedge clk_i);
targets[0].rid = id;
targets[0].rdata = data_base + beat;
targets[0].rresp = 2'b00;
targets[0].rlast = (beat == 7);
targets[0].rvalid = 1'b1;
do @(posedge clk_i); while (!targets[0].rready);
@(negedge clk_i);
targets[0].rvalid = 1'b0;
end
end
endtask
task automatic return_target1_burst(input logic [6:0] id, input logic [63:0] data_base);
begin
for (int unsigned beat = 0; beat < 8; beat++) begin
@(negedge clk_i);
targets[1].rid = id;
targets[1].rdata = data_base + beat;
targets[1].rresp = 2'b00;
targets[1].rlast = (beat == 7);
targets[1].rvalid = 1'b1;
do @(posedge clk_i); while (!targets[1].rready);
@(negedge clk_i);
targets[1].rvalid = 1'b0;
end
end
endtask
task automatic return_target0_read(input logic [6:0] id, input logic [63:0] data);
begin
@(negedge clk_i);
@@ -428,6 +476,69 @@ module axi4_data_crossbar_tb;
$fatal(1, "same-target reads did not drain the crossbar");
end
read_burst_target_lock : begin
logic [ 6:0] first_id;
logic [ 6:0] second_id;
logic [63:0] first_base;
logic [63:0] second_base;
logic [ 6:0] expected_id;
logic [63:0] expected_data;
issue_master1_read_burst(6'b001_100, 32'h3000_0200);
issue_master1_read_burst(6'b001_101, 32'h3800_0200);
if (outstanding_read_o != 8'd2) begin
$fatal(1, "read bursts were not tracked concurrently");
end
fork
return_target0_burst(6'b001_100, 64'hAAAA_0000_0000_0000);
return_target1_burst(6'b001_101, 64'hBBBB_0000_0000_0000);
begin
for (int unsigned beat = 0; beat < 16; beat++) begin
do begin
@(negedge clk_i);
#1;
end while (!masters[1].rvalid);
if (beat == 0) begin
first_id = masters[1].rid;
if (first_id == 6'b001_100) begin
first_base = 64'hAAAA_0000_0000_0000;
second_id = 6'b001_101;
second_base = 64'hBBBB_0000_0000_0000;
end else if (first_id == 6'b001_101) begin
first_base = 64'hBBBB_0000_0000_0000;
second_id = 6'b001_100;
second_base = 64'hAAAA_0000_0000_0000;
end else begin
$fatal(1, "read burst returned an unexpected ID");
end
end
if (beat < 8) begin
expected_id = first_id;
expected_data = first_base + beat;
end else begin
expected_id = second_id;
expected_data = second_base + (beat - 8);
end
if ((masters[1].rid != expected_id) || (masters[1].rdata != expected_data) ||
(masters[1].rlast != (beat == 7 || beat == 15))) begin
$fatal(
1,
"read response burst was interleaved or malformed at beat %0d rid=%h expected_id=%h data=%h expected_data=%h last=%b expected_last=%b",
beat, masters[1].rid, expected_id, masters[1].rdata, expected_data,
masters[1].rlast, (beat == 7 || beat == 15));
end
end
end
join
@(negedge clk_i);
if (!idle_o || (outstanding_read_o != 8'd0)) begin
$fatal(1, "read burst target lock did not drain the crossbar");
end
end
jpeg_master_admission_credit_priority_and_acl : begin
// JPEG's normal class is above the LP gateway's class before aging.
@(negedge clk_i);
+61 -2
View File
@@ -3,12 +3,15 @@
from __future__ import annotations
import argparse
import ctypes
import importlib.util
import re
import struct
import subprocess
import zlib
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
PACKAGER = ROOT / "scripts/package_hp_boot.py"
@@ -48,7 +51,7 @@ def test_hp_boot_bundle_layout_crc_and_payloads(tmp_path: Path) -> None:
image = output.read_bytes()
header_values = module.HEADER.unpack_from(image, module.BUNDLE_OFFSET)
magic, version, header_size, entry_count, total_size, header_crc, flags, reserved = (
magic, version, header_size, entry_count, total_size, header_crc, flags, workload = (
header_values
)
assert magic == module.MAGIC
@@ -57,7 +60,7 @@ def test_hp_boot_bundle_layout_crc_and_payloads(tmp_path: Path) -> None:
assert entry_count == len(module.ARTIFACTS) == 4
assert total_size == len(image) - module.BUNDLE_OFFSET
assert flags == module.REQUIRED
assert reserved == 0
assert workload == 1
header = bytearray(image[module.BUNDLE_OFFSET : module.BUNDLE_OFFSET + header_size])
struct.pack_into("<I", header, 20, 0)
@@ -74,6 +77,62 @@ def test_hp_boot_bundle_layout_crc_and_payloads(tmp_path: Path) -> None:
assert entry_flags == module.REQUIRED
@pytest.fixture(scope="module")
def loader(tmp_path_factory):
library = tmp_path_factory.mktemp("hp-loader") / "loader.so"
subprocess.run(["cc", "-Wall", "-Wextra", "-Werror", "-shared", "-fPIC",
str(ROOT / "app/apps/hp_boot/hp_boot_bundle.c"), "-o", str(library)], check=True)
result = ctypes.CDLL(str(library))
result.rs_hp_boot_header_valid.argtypes = [ctypes.c_void_p]
result.rs_hp_boot_header_valid.restype = ctypes.c_bool
result.rs_hp_boot_message_status.argtypes = [ctypes.c_uint32] * 6
result.rs_hp_boot_message_status.restype = ctypes.c_uint32
return result
@pytest.mark.parametrize("workload", ["linux", "smoke", "rtthread"])
def test_v2_loader_accepts_canonical_bundle_and_rejects_bad_headers(tmp_path, loader, workload):
module = load_packager()
firmware = tmp_path / "lp.bin"
firmware.write_bytes(b"LP")
images = tmp_path / "images"
images.mkdir()
for _, name, _, _ in module.artifacts_for(workload):
(images / name).write_bytes(b"payload")
output = tmp_path / "bundle.bin"
module.package(argparse.Namespace(firmware=firmware, images=images, output=output,
manifest=tmp_path / "bundle.json", workload=workload))
header = output.read_bytes()[module.BUNDLE_OFFSET:module.BUNDLE_OFFSET + 128]
assert loader.rs_hp_boot_header_valid(ctypes.create_string_buffer(header))
# Every mutation has a corrected CRC, so structural checks are exercised.
mutations = [(4, 1), (8, 64), (12, 0), (16, 0xFFFFFFFF), (24, 3), (28, 99),
(32, 99), (36, 0x100000), (36, 0xFFFFFFFF), (40, 0x38000004),
(44, 0), (44, 0x80001), (52, 3)]
mutations += [(60, 0x101000)] if workload == "linux" else [(56, 1)]
for offset, value in mutations:
changed = bytearray(header)
struct.pack_into("<I", changed, offset, value)
struct.pack_into("<I", changed, 20, 0)
struct.pack_into("<I", changed, 20, zlib.crc32(changed))
assert not loader.rs_hp_boot_header_valid(ctypes.create_string_buffer(bytes(changed))), (offset, value)
changed = bytearray(header)
changed[20] ^= 1
assert not loader.rs_hp_boot_header_valid(ctypes.create_string_buffer(bytes(changed)))
def test_mailbox_verdict_rejects_bad_codes_arguments_and_sequences(loader):
status = loader.rs_hp_boot_message_status
assert status(1, 0x52545401, 1, 1, 0x52545401, 1) == 1
assert status(2, 0x52545401, 2, 2, 0x52545401, 2) == 1
assert status(0, 0, 0, 1, 0x52545401, 1) == 0
assert status(1, 0x52545401, 1, 2, 0x52545401, 2) == 0
assert status(3, 7, 1, 2, 0x52545401, 2) == 2
assert status(3, 0, 2, 1, 0x52545401, 1) == 2
assert status(1, 0x52545401, 2, 1, 0x52545401, 1) == 2
assert status(2, 0x52545401, 1, 1, 0x52545401, 1) == 2
assert status(1, 0x4C4E5801, 1, 1, 0x52545401, 1) == 2
def test_mailbox_c_offsets_match_handwritten_rtl() -> None:
rtl_pattern = re.compile(r"^`define\s+APB4_HP_MAILBOX__(\w+)\s+12'h([0-9A-Fa-f]+)$")
c_pattern = re.compile(
+43 -7
View File
@@ -7,6 +7,11 @@ import shutil
import subprocess
from pathlib import Path
import pytest
from scripts import build_hp_linux
from scripts.run_hp_sim import MARKERS
ROOT = Path(__file__).resolve().parents[1]
@@ -20,7 +25,7 @@ def test_hp_profile_and_locked_generator_contract() -> None:
profile = (ROOT / "configs/ci/ihp130-hp.mk").read_text(encoding="utf-8")
assert "HAVE_HP" in profile and "YES" in profile
assert "rv32imafdc_zicbom_max" in profile
assert "rv64imafdc_zicbom_max" in profile
assert "APP" in profile and "hp_boot" in profile
assert "LINK_TYPE" in profile and "ld2_all_sram" in profile
@@ -28,6 +33,8 @@ def test_hp_profile_and_locked_generator_contract() -> None:
encoding="utf-8"
)
for requirement in (
"param.xlen = 64",
"param.physicalWidth = 32",
'param.addISA("m", "a", "f", "d", "c", "s", "u", "zicbom", "zicntr", "zihpm")',
"param.decoders = 2",
"param.lanes = 2",
@@ -50,16 +57,16 @@ def test_hp_linux_simulation_uses_explicit_fast_flash_acceptance() -> None:
verilator_makefile = (ROOT / "rtl/mini/mk/verilator.mk").read_text(encoding="utf-8")
emulator = (ROOT / "rtl/mini/dv/verilator/csrc/main.cpp").read_text(encoding="utf-8")
assert "HP_LINUX_SIM_TIME ?= 7200" in makefile
assert "HP_LINUX_SIM_TIME ?= 0" in makefile
assert "hp-linux-sim: hp-bundle comp" in makefile
assert "VERILATOR_SIM_ARGS=--fast-flash sim" in makefile
assert "--workload linux --timeout $(HP_LINUX_SIM_TIME)" in makefile
for marker in (
"VERILATOR_FAST_FLASH=enabled",
"retroSoC HP Linux ready",
"HP_LINUX_READY",
"SIM_TEST_PASS code=0",
):
assert f"--require '{marker}'" in makefile
assert marker in (*MARKERS["linux"], "SIM_TEST_PASS code=0", "VERILATOR_FAST_FLASH=enabled")
assert "VERILATOR_SIM_ARGS ?=" in verilator_makefile
assert "$(VERILATOR_SIM_ARGS) -t $(SOC_SIM_TIME)" in verilator_makefile
assert '("fast-flash"' in emulator
@@ -128,8 +135,7 @@ def test_hp_smoke_simulation_requires_ga2d_result_and_cache_lifecycle_markers()
target = makefile.split("hp-smoke-sim: hp-smoke-bundle comp", 1)[1].split("\nifeq", 1)[0]
assert "HP_SMOKE_SIM_TIME ?= 300" in makefile
assert "SOC_SIM_TIME=$(HP_SMOKE_SIM_TIME)" in target
assert "VERILATOR_SIM_ARGS=--fast-flash" in target
assert "--workload smoke --timeout $(HP_SMOKE_SIM_TIME)" in target
for marker in (
"SIM_TEST_PASS code=0",
@@ -137,7 +143,7 @@ def test_hp_smoke_simulation_requires_ga2d_result_and_cache_lifecycle_markers()
"HP_GA2D_PASS",
"HP_GA2D_CACHE_CLEAN",
):
assert f"--require '{marker}'" in target
assert marker in (*MARKERS["smoke"], "SIM_TEST_PASS code=0")
def test_hp_cache_handshake_budget_covers_cbo_and_mailbox_round_trip() -> None:
@@ -172,6 +178,28 @@ def test_linux_build_uses_external_opensbi_platform_and_actual_initrd_end() -> N
assert "aclint_mtimer_cold_init" in platform
def test_hp_linux_effective_config_is_fail_closed(tmp_path: Path) -> None:
fragment = (ROOT / "app/ports/linux/linux/retrosoc_hp.config").read_text(
encoding="utf-8"
)
for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG:
assert f"{symbol}=y" in fragment
config = tmp_path / ".config"
valid = "".join(f"{symbol}=y\n" for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG)
config.write_text(valid, encoding="utf-8")
build_hp_linux.validate_linux_config(config)
config.write_text(valid.replace("CONFIG_BINFMT_ELF=y", "# CONFIG_BINFMT_ELF is not set"),
encoding="utf-8")
with pytest.raises(RuntimeError, match="CONFIG_BINFMT_ELF=n"):
build_hp_linux.validate_linux_config(config)
config.write_text(valid.replace("CONFIG_TTY=y\n", ""), encoding="utf-8")
with pytest.raises(RuntimeError, match="CONFIG_TTY=missing"):
build_hp_linux.validate_linux_config(config)
def test_hp_linux_device_tree_compiles_and_can_patch_initrd_end(tmp_path: Path) -> None:
dtc = shutil.which("dtc")
fdtput = shutil.which("fdtput")
@@ -206,6 +234,14 @@ def test_hp_linux_device_tree_compiles_and_can_patch_initrd_end(tmp_path: Path)
).strip()
assert initrd_end == "39123456"
assert hart_id == "1"
reservation = subprocess.check_output(
[fdtget, "-t", "x", str(dtb), "/reserved-memory/opensbi@38000000", "reg"], text=True
).strip()
assert reservation == "38000000 80000"
properties = subprocess.check_output(
[fdtget, "-p", str(dtb), "/reserved-memory/opensbi@38000000"], text=True
).splitlines()
assert "no-map" in properties
dts = (ROOT / "app/ports/linux/linux/retrosoc_hp.dts").read_text(encoding="utf-8")
assert '"zicbom"' in dts
assert "riscv,cbom-block-size = <64>;" in dts
+78
View File
@@ -0,0 +1,78 @@
"""RV64 artifact admission and workload-specific simulation verdicts."""
from __future__ import annotations
import json
import signal
import struct
import subprocess
import sys
import time
from pathlib import Path
import pytest
from scripts.hp_tools import require_rv64_elf
from scripts.run_hp_sim import MARKERS
ROOT = Path(__file__).resolve().parents[1]
@pytest.mark.parametrize("elf_class,machine,accepted", [(2, 243, True), (1, 243, False), (2, 62, False)])
def test_hp_executable_class(elf_class, machine, accepted, tmp_path):
header = bytearray(64)
header[:6] = b"\x7fELF" + bytes((elf_class, 1))
struct.pack_into("<H", header, 18, machine)
path = tmp_path / "payload.elf"
path.write_bytes(header)
if accepted:
require_rv64_elf(path)
else:
with pytest.raises(ValueError, match="RV64 ELF"):
require_rv64_elf(path)
@pytest.mark.parametrize("fault", ["none", "missing", "failure", "exit"])
def test_hp_runner_requires_all_markers_and_zero_exit(tmp_path, fault):
emulator = tmp_path / "emu"
markers = ["VERILATOR_FAST_FLASH=enabled", "SIM_TEST_PASS code=0", *MARKERS["rtthread"]]
if fault == "missing":
markers.remove("RTTHREAD_MAILBOX_IRQ_PASS")
if fault == "failure":
markers.append("SIM_TEST_FAIL code=1")
emulator.write_text(f"#!{sys.executable}\nprint({chr(10).join(markers)!r})\n"
f"raise SystemExit({int(fault == 'exit')})\n")
emulator.chmod(0o755)
output = tmp_path / "result"
output.mkdir()
verdict = output / "result-sim-check.json"
verdict.write_text('{"status":"passed"}')
result = subprocess.run([sys.executable, str(ROOT / "scripts/run_hp_sim.py"),
"--emulator", str(emulator), "--image", str(tmp_path / "boot.bin"),
"--output", str(output), "--workload", "rtthread", "--timeout", "1"],
capture_output=True, text=True, check=False)
assert (result.returncode == 0) == (fault == "none")
assert json.loads(verdict.read_text())["status"] == ("passed" if fault == "none" else "failed")
def test_running_and_interrupted_flow_replace_previous_pass(tmp_path):
verdict = tmp_path / "result.json"
verdict.write_text('{"status":"passed"}')
ready = tmp_path / "ready"
child = f"from pathlib import Path; import time; Path({str(ready)!r}).touch(); time.sleep(30)"
process = subprocess.Popen([sys.executable, str(ROOT / "scripts/run_flow.py"), "--tool", "test",
"--log", str(tmp_path / "sim.log"), "--result", str(verdict),
"--", sys.executable, "-c", child], stdout=subprocess.DEVNULL)
try:
deadline = time.monotonic() + 10
while not ready.exists() and time.monotonic() < deadline:
time.sleep(0.02)
assert ready.exists()
assert json.loads(verdict.read_text())["status"] == "running"
process.send_signal(signal.SIGINT)
assert process.wait(timeout=10) == 130
assert json.loads(verdict.read_text())["status"] == "interrupted"
finally:
if process.poll() is None:
process.send_signal(signal.SIGINT)
process.wait(timeout=10)
+3 -3
View File
@@ -78,12 +78,12 @@ def test_booter_prints_present_hp_core_specification() -> None:
for text in (
"High-Performance-Core Specification:",
"Core: VexiiRiscv(hart 1), dual-issue in-order",
"Base: RV32IMAFDC_Zicbom_Zicntr_Zihpm",
"Mode: M/S/U; Sv32 MMU, 9-bit ASID",
"Base: RV64IMAFDC_Zicbom_Zicntr_Zihpm",
"Mode: M/S/U; Sv39 MMU, 9-bit ASID",
"Protection: 16 PMP regions, 4 KiB granularity",
"L1: separate 16 KiB, 4-way instruction and data caches",
"Maintenance: 64-byte Zicbom CBO; no hardware coherency",
"Bus: native AXI64 I/D + cacheless AXI32 MMIO",
"Bus: native AXI64 I/D/MMIO; MMIO downsized to AXI32",
"Embedded RISC-V JTAG, 4 triggers",
):
assert text in booter
+5 -5
View File
@@ -228,12 +228,12 @@ int main(int argc, char **argv) {
bool expected=true;
switch(scenario) {
case 30: break;
case 31: header.reserved=0x1234; header.flags|=0x80; header.entries[0].flags|=0x80; break;
case 32: header.entries[0].flash_offset+=4; break;
case 31: header.workload=0x1234; header.flags|=0x80; header.entries[0].flags|=0x80; expected=false; break;
case 32: header.entries[0].flash_offset+=4; expected=false; break;
case 33: header.entries[0].flash_offset+=1; expected=false; break;
case 34: header.entries[0].flags=0; expected=false; break;
case 35: header.header_crc32^=1; assert(!rs_hp_boot_header_valid(&header)); return 0;
case 36: header.entries[1].flash_offset=header.entries[0].flash_offset; break;
case 36: header.entries[1].flash_offset=header.entries[0].flash_offset; expected=false; break;
case 37: header.entries[0].size=0; expected=false; break;
case 38: header.header_size+=4; expected=false; break;
case 39: header.entry_count=3; expected=false; break;
@@ -281,8 +281,8 @@ def c_behavior(tmp_path_factory):
}
for family, names in selections.items():
extracted += "\n".join(real_definition(sources[family], name) for name in names)
boot = (ROOT / "app/apps/hp_boot/main.c").read_text(encoding="utf-8")
extracted += "\n".join(real_definition(boot, row["function"]) for row in SPEC["boot_bundle"]["loader_bindings"])
extracted += "\n".join(real_definition((ROOT / row["source"]).read_text(encoding="utf-8"), row["function"])
for row in SPEC["boot_bundle"]["loader_bindings"])
source = folder / "behavior.c"
source.write_text(constants + "\n" + HARNESS.replace("/* REAL_FUNCTIONS */", extracted), encoding="utf-8")
exe = folder / "behavior"
+9 -8
View File
@@ -146,7 +146,7 @@ def test_linux_platform_uses_source_values_and_order():
("app/ports/linux/linux/retrosoc_hp.dts", "cpu@1", "cpu@0"),
("app/ports/linux/linux/retrosoc_hp.dts", "linux,initrd-end = <0x39000000>", "linux,initrd-end = <0x39100000>"),
("app/ports/linux/opensbi/retrosoc_hp/platform.c", ".mtime_freq = 1000000UL", ".mtime_freq = 2000000UL"),
("app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp", "0x10019024 32 0x4C4E5801", "0x10019024 32 0x4C4E5802"),
("app/ports/linux/hp_ready.c", "0x4C4E5801", "0x4C4E5802"),
])
def test_linux_consistency_and_ready_event_drift_fail(source_tree, relative, old, new):
replace(source_tree, relative, old, new)
@@ -155,20 +155,21 @@ def test_linux_consistency_and_ready_event_drift_fail(source_tree, relative, old
def test_ready_request_cannot_move_before_payload(source_tree):
path = source_tree / "app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp"
path = source_tree / "app/ports/linux/hp_ready.c"
lines = path.read_text().splitlines()
first = next(i for i, line in enumerate(lines) if "devmem" in line)
lines[first], lines[first + 3] = lines[first + 3], lines[first]
first = next(i for i, line in enumerate(lines) if "mailbox[8]" in line)
last = next(i for i, line in enumerate(lines) if "mailbox[11]" in line)
lines[first], lines[last] = lines[last], lines[first]
path.write_text("\n".join(lines))
with pytest.raises(ValueError, match="sequence"):
with pytest.raises(ValueError, match="publication"):
sr.linux_platform(source_tree)
def test_ready_text_order_cannot_be_silently_reversed(source_tree):
path = source_tree / "app/ports/linux/rootfs-overlay/etc/init.d/S99retrosoc-hp"
path = source_tree / "app/ports/linux/hp_ready.c"
text = path.read_text()
message = ' echo "retroSoC HP Linux ready"'
lines = [line for line in text.splitlines() if 'echo "retroSoC HP Linux ready"' not in line]
message = ' (void)puts("retroSoC HP Linux ready");'
lines = [line for line in text.splitlines() if 'puts("retroSoC HP Linux ready")' not in line]
lines.append(message)
path.write_text("\n".join(lines))
with pytest.raises(ValueError, match="message/publication"):
+1 -1
View File
@@ -2079,7 +2079,7 @@ def test_run_flow_records_interruption(tmp_path: Path) -> None:
process.communicate(timeout=10)
assert process.returncode == 130
data = json.loads(result.read_text(encoding="utf-8"))
assert data["status"] == "failed"
assert data["status"] == "interrupted"
assert data["exit_code"] == 130
assert data["error"] == "interrupted"