mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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:
81 files changed
+2423
-974
No files matched your search
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -1,228 +1,321 @@
|
||||
# retroSoC
|
||||
|
||||
An open-source RISC-V SoC platform, from SystemVerilog RTL and firmware to reproducible verification and release artifacts.
|
||||
|
||||
[](LICENSE)
|
||||
[](rtl)
|
||||
[](configs/ci/ihp130.mk)
|
||||
[](configs/ci/ihp130.mk)
|
||||
[](dependencies/dependencies.lock.json)<br>
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-ihp130.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-gf180.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-ics55.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml)<br>
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/regression-sky130.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/quality.yml)
|
||||
[](https://github.com/retroSoC/retroSoC/actions/workflows/nightly.yml)
|
||||
[](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:
|
||||
|
||||
[](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
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
@@ -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 *)©, 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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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')
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
Vendored
+7
@@ -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
|
||||
|
||||
Vendored
+13
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
@@ -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.])
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"]]}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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": {
|
||||
|
||||
@@ -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()
|
||||
@@ -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,
|
||||
|
||||
@@ -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()))
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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())
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"):
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in new issue
Block a user