mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add HP mailbox and PLIC tests; enhance existing test coverage
- Updated axi4_interconnect_tb to include an additional master and issue high-priority access tests. - Introduced hp_mailbox_tb for testing the HP mailbox functionality, including register and doorbell operations. - Added plic_tb to validate PLIC priority, claim, and completion mechanisms. - Enhanced pll_ctrl_tb to initialize additional system control signals. - Updated soc_irq_topology_tb to account for new IRQ sources and validate IRQ signal behavior. - Improved sysctrl_tb to include tests for HP lifecycle control and status registers. - Added tests for HP boot bundle layout, CRC, and payload validation. - Introduced test_hp_mailbox.py for RTL regression testing of the HP mailbox. - Added test_hp_platform.py to validate HP platform configuration and generated-source boundaries. - Enhanced test_librelane_flow.py to ensure correct signal placement in chip configuration. - Added performance log tests to validate LP and HP coremark ratios. - Updated test_soc_topology.py to reflect changes in IRQ and peripheral mappings.
This commit is contained in:
101 files changed
+4880
-111
No files matched your search
@@ -42,6 +42,8 @@ HAVE_SRAM_MACRO ?= $(if $(filter ICS55,$(PDK)),NO,YES)
|
|||||||
SRAM_SIZE_KIB ?= $(if $(filter ICS55,$(PDK)),128,32)
|
SRAM_SIZE_KIB ?= $(if $(filter ICS55,$(PDK)),128,32)
|
||||||
PDK_BEHAV ?= NO
|
PDK_BEHAV ?= NO
|
||||||
HAVE_SVA ?= NO
|
HAVE_SVA ?= NO
|
||||||
|
HAVE_HP ?= NO
|
||||||
|
HP_CONFIG ?= rv32imafdc_max
|
||||||
BUILD_RELEASE ?= NO
|
BUILD_RELEASE ?= NO
|
||||||
JTAG_IDCODE ?= DEADBEEF
|
JTAG_IDCODE ?= DEADBEEF
|
||||||
EXT_CLK_HZ ?= 72000000
|
EXT_CLK_HZ ?= 72000000
|
||||||
@@ -61,16 +63,22 @@ RTL_PATH := $(ROOT_PATH)/rtl/mini
|
|||||||
RTL_TOP ?= retrosoc_tb
|
RTL_TOP ?= retrosoc_tb
|
||||||
|
|
||||||
# SW
|
# SW
|
||||||
ISA ?= RV32IM
|
ISA ?= RV32IM
|
||||||
HAVE_CSR ?= NO
|
HAVE_CSR ?= NO
|
||||||
FIRMWARE_NAME ?= retrosoc_fw
|
FIRMWARE_NAME ?= retrosoc_fw
|
||||||
APP ?= shell
|
APP ?= shell
|
||||||
LINK_TYPE ?= ld2_sram
|
LINK_TYPE ?= ld2_sram
|
||||||
COREMARK_MODE ?= quick
|
COREMARK_MODE ?= quick
|
||||||
|
HP_PERF_MIN_RATIO ?= 2.5
|
||||||
|
LP_COREMARK_REPORT ?=
|
||||||
|
HP_COREMARK_REPORT ?=
|
||||||
|
|
||||||
BUILD_ROOT ?= $(ROOT_PATH)/build
|
BUILD_ROOT ?= $(ROOT_PATH)/build
|
||||||
CACHE_ROOT ?= $(ROOT_PATH)/.cache/retrosoc
|
CACHE_ROOT ?= $(ROOT_PATH)/.cache/retrosoc
|
||||||
|
VEXIIRISCV_ROOT ?= $(abspath $(ROOT_PATH)/../VexiiRiscv)
|
||||||
|
SBT ?= sbt
|
||||||
BUILD_TIMESTAMP ?= $(shell date '+%Y-%m-%d-%H-%M')
|
BUILD_TIMESTAMP ?= $(shell date '+%Y-%m-%d-%H-%M')
|
||||||
|
BUILD_TIMESTAMP := $(BUILD_TIMESTAMP)
|
||||||
MAX_JOBS ?= 16
|
MAX_JOBS ?= 16
|
||||||
HOST_CC ?= cc
|
HOST_CC ?= cc
|
||||||
PYTHON ?= python3
|
PYTHON ?= python3
|
||||||
@@ -87,7 +95,7 @@ JOBS ?= $(shell count=$$(nproc 2>/dev/null || printf '1'); \
|
|||||||
if [ "$$count" -gt "$(MAX_JOBS)" ]; then printf '%s' '$(MAX_JOBS)'; \
|
if [ "$$count" -gt "$(MAX_JOBS)" ]; then printf '%s' '$(MAX_JOBS)'; \
|
||||||
else printf '%s' "$$count"; fi)
|
else printf '%s' "$$count"; fi)
|
||||||
CONFIG_KEY_VARS := SOC PDK HAVE_PLL HAVE_SRAM_IF HAVE_SRAM_MACRO SRAM_SIZE_KIB PDK_BEHAV HAVE_SVA \
|
CONFIG_KEY_VARS := SOC PDK HAVE_PLL HAVE_SRAM_IF HAVE_SRAM_MACRO SRAM_SIZE_KIB PDK_BEHAV HAVE_SVA \
|
||||||
BUILD_RELEASE JTAG_IDCODE EXT_CLK_HZ AUD_CLK_HZ CLINT_TIMEBASE_HZ ISA HAVE_CSR APP LINK_TYPE \
|
HAVE_HP HP_CONFIG BUILD_RELEASE JTAG_IDCODE EXT_CLK_HZ AUD_CLK_HZ CLINT_TIMEBASE_HZ ISA HAVE_CSR APP LINK_TYPE \
|
||||||
COREMARK_MODE RTL_TOP FIRMWARE_NAME
|
COREMARK_MODE RTL_TOP FIRMWARE_NAME
|
||||||
VARIANT_ID := $(strip $(shell $(VCS_SHELL_PYTHON) $(ROOT_PATH)/scripts/config_key.py \
|
VARIANT_ID := $(strip $(shell $(VCS_SHELL_PYTHON) $(ROOT_PATH)/scripts/config_key.py \
|
||||||
--lock $(LOCK_FILE) --profile $(PROFILE_NAME) --timestamp $(BUILD_TIMESTAMP) \
|
--lock $(LOCK_FILE) --profile $(PROFILE_NAME) --timestamp $(BUILD_TIMESTAMP) \
|
||||||
@@ -99,11 +107,30 @@ LOCK_DIGEST := $(strip $(shell $(VCS_SHELL_PYTHON) $(ROOT_PATH)/scripts/depend
|
|||||||
--lock $(LOCK_FILE) --digest | tail -n 1))
|
--lock $(LOCK_FILE) --digest | tail -n 1))
|
||||||
CONFIG_DIGEST := $(lastword $(subst -, ,$(VARIANT_ID)))
|
CONFIG_DIGEST := $(lastword $(subst -, ,$(VARIANT_ID)))
|
||||||
export BUILD_TIMESTAMP
|
export BUILD_TIMESTAMP
|
||||||
VARIANT_ROOT := $(abspath $(BUILD_ROOT))/$(VARIANT_ID)
|
VARIANT_ROOT := $(abspath $(BUILD_ROOT))/$(VARIANT_ID)
|
||||||
SW_BUILD_DIR := $(VARIANT_ROOT)/sw
|
SW_BUILD_DIR := $(VARIANT_ROOT)/sw
|
||||||
SIM_TOOL_NAME := $(shell printf '%s' '$(SIMU)' | tr '[:upper:]' '[:lower:]')
|
SIM_TOOL_NAME := $(shell printf '%s' '$(SIMU)' | tr '[:upper:]' '[:lower:]')
|
||||||
SIM_BUILD_ROOT := $(VARIANT_ROOT)/sim/$(SIM_TOOL_NAME)
|
SIM_BUILD_ROOT := $(VARIANT_ROOT)/sim/$(SIM_TOOL_NAME)
|
||||||
META_DIR := $(VARIANT_ROOT)/meta
|
META_DIR := $(VARIANT_ROOT)/meta
|
||||||
|
HP_GENERATED_DIR := $(VARIANT_ROOT)/generated/vexiiriscv
|
||||||
|
HP_GENERATED_RTL := $(HP_GENERATED_DIR)/vexii_riscv_hp_generated.v
|
||||||
|
HP_GENERATED_MANIFEST := $(HP_GENERATED_DIR)/manifest.json
|
||||||
|
HP_GENERATED_STAMP := $(HP_GENERATED_DIR)/.stamp
|
||||||
|
HP_LINUX_BUILD_DIR := $(VARIANT_ROOT)/hp-linux
|
||||||
|
HP_LINUX_STAMP := $(HP_LINUX_BUILD_DIR)/images/.stamp
|
||||||
|
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_SMOKE_BUILD_DIR := $(VARIANT_ROOT)/hp-smoke
|
||||||
|
HP_SMOKE_STAMP := $(HP_SMOKE_BUILD_DIR)/images/.stamp
|
||||||
|
HP_SMOKE_BUNDLE_NAME ?= retrosoc_hp_smoke
|
||||||
|
HP_SMOKE_BUNDLE_BIN := $(SW_BUILD_DIR)/$(HP_SMOKE_BUNDLE_NAME).bin
|
||||||
|
HP_SMOKE_BUNDLE_HEX := $(SW_BUILD_DIR)/$(HP_SMOKE_BUNDLE_NAME).hex
|
||||||
|
HP_SMOKE_MANIFEST := $(SW_BUILD_DIR)/$(HP_SMOKE_BUNDLE_NAME).json
|
||||||
|
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
|
||||||
ifeq ($(SYNTH_RECIPE),balanced)
|
ifeq ($(SYNTH_RECIPE),balanced)
|
||||||
SYN_BUILD_ROOT := $(VARIANT_ROOT)/syn/yosys
|
SYN_BUILD_ROOT := $(VARIANT_ROOT)/syn/yosys
|
||||||
STA_BUILD_ROOT := $(VARIANT_ROOT)/sta/opensta
|
STA_BUILD_ROOT := $(VARIANT_ROOT)/sta/opensta
|
||||||
@@ -128,8 +155,9 @@ VALID_SYNTH_RECIPE := balanced area speed
|
|||||||
VALID_STA := NONE OPENSTA
|
VALID_STA := NONE OPENSTA
|
||||||
VALID_PDK := ICS55 IHP130 SKY130 GF180
|
VALID_PDK := ICS55 IHP130 SKY130 GF180
|
||||||
VALID_BOOL := YES NO
|
VALID_BOOL := YES NO
|
||||||
|
VALID_HP_CONFIG := rv32imafdc_max
|
||||||
VALID_ISA := RV32E RV32I RV32IM
|
VALID_ISA := RV32E RV32I RV32IM
|
||||||
VALID_APP := benchmark bringup ci_smoke coremark debug shell xpi_flash_loader
|
VALID_APP := benchmark bringup ci_smoke coremark debug hp_boot shell xpi_flash_loader
|
||||||
VALID_LINK_TYPE := xip jtag_sram ld2_all_sram ld2_sram ld2_psram ld2_sdram
|
VALID_LINK_TYPE := xip jtag_sram ld2_all_sram ld2_sram ld2_psram ld2_sdram
|
||||||
VALID_COREMARK_MODE := quick standard
|
VALID_COREMARK_MODE := quick standard
|
||||||
VALID_SRAM_SIZE_KIB := 4 16 32 64 128
|
VALID_SRAM_SIZE_KIB := 4 16 32 64 128
|
||||||
@@ -150,6 +178,8 @@ $(call validate_value,HAVE_SRAM_MACRO,$(VALID_BOOL))
|
|||||||
$(call validate_value,SRAM_SIZE_KIB,$(VALID_SRAM_SIZE_KIB))
|
$(call validate_value,SRAM_SIZE_KIB,$(VALID_SRAM_SIZE_KIB))
|
||||||
$(call validate_value,PDK_BEHAV,$(VALID_BOOL))
|
$(call validate_value,PDK_BEHAV,$(VALID_BOOL))
|
||||||
$(call validate_value,HAVE_SVA,$(VALID_BOOL))
|
$(call validate_value,HAVE_SVA,$(VALID_BOOL))
|
||||||
|
$(call validate_value,HAVE_HP,$(VALID_BOOL))
|
||||||
|
$(call validate_value,HP_CONFIG,$(VALID_HP_CONFIG))
|
||||||
$(call validate_value,BUILD_RELEASE,$(VALID_BOOL))
|
$(call validate_value,BUILD_RELEASE,$(VALID_BOOL))
|
||||||
$(call validate_value,WAVE,$(VALID_BOOL))
|
$(call validate_value,WAVE,$(VALID_BOOL))
|
||||||
$(call validate_value,FORMAL,$(VALID_BOOL))
|
$(call validate_value,FORMAL,$(VALID_BOOL))
|
||||||
@@ -255,6 +285,10 @@ ifeq ($(HAVE_SVA), NO)
|
|||||||
DEF_LIST += +define+SV_ASSRT_DISABLE
|
DEF_LIST += +define+SV_ASSRT_DISABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_HP), YES)
|
||||||
|
DEF_LIST += +define+HAVE_HP
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(SYNTH), YOSYS)
|
ifeq ($(SYNTH), YOSYS)
|
||||||
DEF_LIST += +define+SYNTHESIS
|
DEF_LIST += +define+SYNTHESIS
|
||||||
endif
|
endif
|
||||||
@@ -279,15 +313,16 @@ endif
|
|||||||
include physical/librelane/Makefile
|
include physical/librelane/Makefile
|
||||||
include physical/ecc/Makefile
|
include physical/ecc/Makefile
|
||||||
|
|
||||||
.PHONY: help config doctor setup setup-regression setup-mpw setup-clusterip setup-ip setup-pdk setup-app \
|
.PHONY: help config doctor setup setup-regression setup-mpw setup-clusterip setup-ip setup-pdk setup-app setup-hp-linux hp-linux hp-bundle hp-smoke-bundle hp-smoke-sim \
|
||||||
clean-all purge-cache manifest check-warnings metrics check-metrics package commercial-package \
|
clean-all purge-cache manifest check-warnings metrics check-metrics package commercial-package \
|
||||||
regress-smoke regress-pr regress-nightly sim-asm format format-check sw-format sw-format-check mk-format \
|
regress-smoke regress-pr regress-nightly sim-asm format format-check sw-format sw-format-check mk-format \
|
||||||
mk-format-check rtl-format rtl-format-check rtl-style-check rtl-migrate-connections rtl-migrate-names sw-policy-check sw-host-test \
|
mk-format-check rtl-format rtl-format-check rtl-style-check rtl-migrate-connections rtl-migrate-names sw-policy-check sw-host-test \
|
||||||
benchmark-report coremark-report \
|
benchmark-report coremark-report \
|
||||||
|
hp-performance-check \
|
||||||
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \
|
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \
|
||||||
check-clock-reset-domains tech-cell-test rtl-lint check-rtl-lint \
|
check-clock-reset-domains tech-cell-test rtl-lint check-rtl-lint \
|
||||||
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-dvp formal-i2s formal-onchip-ram formal-opipsram formal-dma formal-sdio formal-clean formal-doctor \
|
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-dvp formal-i2s formal-onchip-ram formal-opipsram formal-dma formal-sdio formal-clean formal-doctor \
|
||||||
rtl-style-check-all rtl-readiness-check rtl-readiness-check-all
|
rtl-style-check-all rtl-readiness-check rtl-readiness-check-all vexii-generate
|
||||||
.NOTPARALLEL: setup
|
.NOTPARALLEL: setup
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@@ -311,6 +346,10 @@ help:
|
|||||||
' ecc-package package ECC core views and evidence' \
|
' ecc-package package ECC core views and evidence' \
|
||||||
' setup install pinned external dependencies' \
|
' setup install pinned external dependencies' \
|
||||||
' setup-regression install pinned dependencies for all PR PDK profiles' \
|
' 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-bundle package LP firmware and HP Linux images for flash' \
|
||||||
|
' hp-smoke-sim run LP release, HP MMIO, and mailbox RTL smoke test' \
|
||||||
' doctor check tools, paths, and selected configuration' \
|
' doctor check tools, paths, and selected configuration' \
|
||||||
' config | manifest print/write the effective configuration' \
|
' config | manifest print/write the effective configuration' \
|
||||||
' memory-map generate the selected address-map artifacts' \
|
' memory-map generate the selected address-map artifacts' \
|
||||||
@@ -320,6 +359,7 @@ help:
|
|||||||
' soc-topology generate the selected internal SoC integration artifacts' \
|
' soc-topology generate the selected internal SoC integration artifacts' \
|
||||||
' check-soc-topology validate the canonical internal SoC integration map' \
|
' check-soc-topology validate the canonical internal SoC integration map' \
|
||||||
' user-extensions generate the selected scalar user-extension bindings' \
|
' user-extensions generate the selected scalar user-extension bindings' \
|
||||||
|
' vexii-generate generate the locked HP VexiiRiscv RTL below build/' \
|
||||||
' check-user-extensions validate the canonical user-extension map' \
|
' check-user-extensions validate the canonical user-extension map' \
|
||||||
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
|
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
|
||||||
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
|
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
|
||||||
@@ -328,6 +368,7 @@ help:
|
|||||||
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
|
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
|
||||||
' benchmark-report run the memory/DMA profile and write meta/performance.json' \
|
' benchmark-report run the memory/DMA profile and write meta/performance.json' \
|
||||||
' coremark-report run the quick CoreMark profile and write meta/coremark.json' \
|
' coremark-report run the quick CoreMark profile and write meta/coremark.json' \
|
||||||
|
' hp-performance-check require measured HP CoreMark/MHz >= 2.5x LP' \
|
||||||
' tech-cell-test test open-PDK technology IO and clock wrappers' \
|
' tech-cell-test test open-PDK technology IO and clock wrappers' \
|
||||||
' check-warnings | metrics analyze flow logs and reports' \
|
' check-warnings | metrics analyze flow logs and reports' \
|
||||||
' check-metrics apply the committed metrics policy' \
|
' check-metrics apply the committed metrics policy' \
|
||||||
@@ -366,7 +407,7 @@ config:
|
|||||||
HAVE_PLL '$(HAVE_PLL)' HAVE_SRAM_IF '$(HAVE_SRAM_IF)' \
|
HAVE_PLL '$(HAVE_PLL)' HAVE_SRAM_IF '$(HAVE_SRAM_IF)' \
|
||||||
HAVE_SRAM_MACRO '$(HAVE_SRAM_MACRO)' SRAM_SIZE_KIB '$(SRAM_SIZE_KIB)' \
|
HAVE_SRAM_MACRO '$(HAVE_SRAM_MACRO)' SRAM_SIZE_KIB '$(SRAM_SIZE_KIB)' \
|
||||||
PDK_BEHAV '$(PDK_BEHAV)' HAVE_SVA '$(HAVE_SVA)' \
|
PDK_BEHAV '$(PDK_BEHAV)' HAVE_SVA '$(HAVE_SVA)' \
|
||||||
BUILD_RELEASE '$(BUILD_RELEASE)' \
|
HAVE_HP '$(HAVE_HP)' HP_CONFIG '$(HP_CONFIG)' BUILD_RELEASE '$(BUILD_RELEASE)' \
|
||||||
JTAG_IDCODE '$(JTAG_IDCODE)' EXT_CLK_HZ '$(EXT_CLK_HZ)' AUD_CLK_HZ '$(AUD_CLK_HZ)' \
|
JTAG_IDCODE '$(JTAG_IDCODE)' EXT_CLK_HZ '$(EXT_CLK_HZ)' AUD_CLK_HZ '$(AUD_CLK_HZ)' \
|
||||||
CLINT_TIMEBASE_HZ '$(CLINT_TIMEBASE_HZ)' \
|
CLINT_TIMEBASE_HZ '$(CLINT_TIMEBASE_HZ)' \
|
||||||
ISA '$(ISA)' HAVE_CSR '$(HAVE_CSR)' APP '$(APP)' \
|
ISA '$(ISA)' HAVE_CSR '$(HAVE_CSR)' APP '$(APP)' \
|
||||||
@@ -390,6 +431,13 @@ coremark-report: firmware
|
|||||||
$(FLOW_PYTHON) $(ROOT_PATH)/scripts/parse_coremark_log.py --log $(PERF_LOG) \
|
$(FLOW_PYTHON) $(ROOT_PATH)/scripts/parse_coremark_log.py --log $(PERF_LOG) \
|
||||||
--output $(META_DIR)/coremark.json
|
--output $(META_DIR)/coremark.json
|
||||||
|
|
||||||
|
hp-performance-check:
|
||||||
|
@test -n '$(LP_COREMARK_REPORT)' -a -n '$(HP_COREMARK_REPORT)' || { \
|
||||||
|
echo 'LP_COREMARK_REPORT and HP_COREMARK_REPORT are required' >&2; exit 1; }
|
||||||
|
$(FLOW_PYTHON) $(ROOT_PATH)/scripts/check_lp_hp_performance.py \
|
||||||
|
--lp $(LP_COREMARK_REPORT) --hp $(HP_COREMARK_REPORT) \
|
||||||
|
--minimum-ratio $(HP_PERF_MIN_RATIO) --output $(META_DIR)/lp-hp-performance.json
|
||||||
|
|
||||||
setup: setup-mpw setup-clusterip setup-ip setup-pdk setup-app
|
setup: setup-mpw setup-clusterip setup-ip setup-pdk setup-app
|
||||||
|
|
||||||
setup-regression:
|
setup-regression:
|
||||||
@@ -417,6 +465,78 @@ setup-pdk:
|
|||||||
setup-app:
|
setup-app:
|
||||||
python3 $(ROOT_PATH)/app/setup.py
|
python3 $(ROOT_PATH)/app/setup.py
|
||||||
|
|
||||||
|
setup-hp-linux:
|
||||||
|
python3 $(ROOT_PATH)/scripts/setup_hp_linux.py
|
||||||
|
|
||||||
|
$(HP_LINUX_STAMP): $(ROOT_PATH)/scripts/build_hp_linux.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 \
|
||||||
|
$(ROOT_PATH)/app/ports/linux/linux/retrosoc_hp.dts \
|
||||||
|
$(ROOT_PATH)/app/ports/linux/opensbi/retrosoc_hp/Kconfig \
|
||||||
|
$(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
|
||||||
|
@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) \
|
||||||
|
--output $(HP_LINUX_BUILD_DIR) --jobs $(JOBS)
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
hp-linux: $(HP_LINUX_STAMP)
|
||||||
|
|
||||||
|
$(HP_BOOT_BUNDLE_BIN): $(FIRMWARE_ELF) $(HP_LINUX_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_LINUX_BUILD_DIR)/images --output $@ \
|
||||||
|
--manifest $(HP_BOOT_BUNDLE_MANIFEST)
|
||||||
|
|
||||||
|
$(HP_BOOT_BUNDLE_HEX): $(HP_BOOT_BUNDLE_BIN)
|
||||||
|
$(OBJC) -I binary -O verilog $< $@
|
||||||
|
|
||||||
|
hp-bundle: $(HP_BOOT_BUNDLE_BIN) $(HP_BOOT_BUNDLE_HEX)
|
||||||
|
|
||||||
|
$(HP_SMOKE_STAMP): $(ROOT_PATH)/scripts/build_hp_smoke.py \
|
||||||
|
$(ROOT_PATH)/app/ports/linux/smoke/start.S \
|
||||||
|
$(ROOT_PATH)/app/ports/linux/smoke/linker.ld
|
||||||
|
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)
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
$(HP_SMOKE_BUNDLE_BIN): $(FIRMWARE_ELF) $(HP_SMOKE_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_SMOKE_BUILD_DIR)/images --output $@ \
|
||||||
|
--manifest $(HP_SMOKE_MANIFEST)
|
||||||
|
|
||||||
|
$(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-smoke-sim: hp-smoke-bundle comp
|
||||||
|
@test '$(SIMU)' = VERILATOR
|
||||||
|
$(MAKE) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) SIM_FIRMWARE_NAME=$(HP_SMOKE_BUNDLE_NAME) sim
|
||||||
|
|
||||||
|
ifeq ($(HAVE_HP),YES)
|
||||||
|
$(HP_GENERATED_STAMP): $(ROOT_PATH)/scripts/generate_vexiiriscv.py \
|
||||||
|
$(ROOT_PATH)/scripts/vexiiriscv/GenerateRetroSocHp.scala $(LOCK_FILE)
|
||||||
|
python3 $(ROOT_PATH)/scripts/generate_vexiiriscv.py \
|
||||||
|
--root $(ROOT_PATH) --source $(VEXIIRISCV_ROOT) --output $(HP_GENERATED_DIR) \
|
||||||
|
--manifest $(HP_GENERATED_MANIFEST) --lock $(LOCK_FILE) --sbt $(SBT)
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
vexii-generate: $(HP_GENERATED_STAMP)
|
||||||
|
else
|
||||||
|
vexii-generate:
|
||||||
|
@printf '%s\n' 'HAVE_HP=NO; no VexiiRiscv RTL is required'
|
||||||
|
endif
|
||||||
|
|
||||||
clean-all:
|
clean-all:
|
||||||
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(abspath $(BUILD_ROOT))
|
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(abspath $(BUILD_ROOT))
|
||||||
|
|
||||||
@@ -523,4 +643,4 @@ regress-nightly:
|
|||||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite nightly
|
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite nightly
|
||||||
|
|
||||||
sim-asm: asm
|
sim-asm: asm
|
||||||
$(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim
|
$(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim
|
||||||
@@ -21,6 +21,11 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
|
|||||||
- A fixed Hazard3 management core with a permanent JTAG Debug Module, plus
|
- A fixed Hazard3 management core with a permanent JTAG Debug Module, plus
|
||||||
software-selected user-core and user-IP extension slots. The active user
|
software-selected user-core and user-IP extension slots. The active user
|
||||||
cores are KianV RV32I, SERV, FemtoRV32, and DarkRISCV at slots C0-C3.
|
cores are KianV RV32I, SERV, FemtoRV32, and DarkRISCV at slots C0-C3.
|
||||||
|
- An experimental IHP130 [LP/HP profile](docs/lp-hp-architecture.md) that keeps
|
||||||
|
Hazard3 as LP and adds a generated dual-issue RV32IMAFDC VexiiRiscv HP core,
|
||||||
|
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)
|
- 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,
|
anchored by Mini and a trusted Hazard3 management model. The higher Linux,
|
||||||
graphics, AI, and RV64 configurations are roadmap targets, not supported
|
graphics, AI, and RV64 configurations are roadmap targets, not supported
|
||||||
@@ -82,6 +87,7 @@ because their fixed data placement and SRAM-resident image require the larger ca
|
|||||||
| [`configs/ci/sky130.mk`](configs/ci/sky130.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, Icarus netlist, and OpenSTA coverage with a 32 KiB OpenRAM SRAM. |
|
| [`configs/ci/sky130.mk`](configs/ci/sky130.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, Icarus netlist, and OpenSTA coverage with a 32 KiB OpenRAM SRAM. |
|
||||||
| [`configs/ci/ihp130-shell.mk`](configs/ci/ihp130-shell.mk) | RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
|
| [`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-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 RV32IMAFDC | `hp_boot` | Experimental fixed-72-MHz LP/HP integration, generated VexiiRiscv RTL, Linux image/bundle flow, and HP RTL validation. |
|
||||||
| [`configs/benchmark/ihp130-hazard3-coremark.mk`](configs/benchmark/ihp130-hazard3-coremark.mk) | RV32IM | `coremark` | Fixed four-iteration SRAM CoreMark quick measurement, recorded by nightly IHP130 regression. |
|
| [`configs/benchmark/ihp130-hazard3-coremark.mk`](configs/benchmark/ihp130-hazard3-coremark.mk) | RV32IM | `coremark` | Fixed four-iteration SRAM CoreMark quick measurement, recorded by nightly IHP130 regression. |
|
||||||
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | RV32IM | `bringup` | Compatibility profile for site-specific ICS55 runs. |
|
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | RV32IM | `bringup` | Compatibility profile for site-specific ICS55 runs. |
|
||||||
|
|
||||||
@@ -220,6 +226,8 @@ make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG \
|
|||||||
| OpenSTA core timing analysis after synthesis | `make CONFIG=configs/ci/ihp130.mk STA=OPENSTA sta` |
|
| 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` |
|
| 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 coremark-report` |
|
| Hazard3 CoreMark quick report | `make CONFIG=configs/benchmark/ihp130-hazard3-coremark.mk SIMU=VERILATOR 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` |
|
| IHP130 fast smoke suite | `make regress-smoke` |
|
||||||
| Pull-request regression suite | `make regress-pr` |
|
| Pull-request regression suite | `make regress-pr` |
|
||||||
| Nightly regression suite | `make regress-nightly` |
|
| Nightly regression suite | `make regress-nightly` |
|
||||||
|
|||||||
+6
-1
@@ -13,7 +13,7 @@ application policy separate from common runtime and HAL code.
|
|||||||
| `media/` | WAV, video, and visual-demo components with public media headers. |
|
| `media/` | WAV, video, and visual-demo components with public media headers. |
|
||||||
| `middleware/` | Application middleware configuration and integration, including FatFs. |
|
| `middleware/` | Application middleware configuration and integration, including FatFs. |
|
||||||
| `network/` | Optional network or user-IP integration. |
|
| `network/` | Optional network or user-IP integration. |
|
||||||
| `ports/` | Ports and configuration for external libraries, such as LVGL. |
|
| `ports/` | Ports and configuration for external libraries, including LVGL and the HP Linux/OpenSBI platform. |
|
||||||
| `benchmark/` | Project integration for benchmark workloads, including CoreMark. |
|
| `benchmark/` | Project integration for benchmark workloads, including CoreMark. |
|
||||||
| `asm/` | Standalone assembly firmware used by low-level simulation self-tests. |
|
| `asm/` | Standalone assembly firmware used by low-level simulation self-tests. |
|
||||||
|
|
||||||
@@ -32,6 +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, RNG, crypto AES/SHA, SDRAM mapped access, and test-status completion. |
|
| `ci_smoke` | Fast deterministic CI smoke test for UART, ARCHINFO V2, RNG, crypto AES/SHA, SDRAM mapped access, and test-status completion. |
|
||||||
| `coremark` | SRAM-resident Hazard3 CoreMark measurement; use the committed quick or standard profile. |
|
| `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. |
|
| `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. |
|
||||||
| `shell` | Interactive application that adds shell services, board drivers, media, FatFs, CoreMark, and UserIP integration. |
|
| `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. |
|
| `xpi_flash_loader` | SRAM-resident, GDB-called service image for sector-preserving JTAG programming of the qualified NSS0 NOR. |
|
||||||
|
|
||||||
@@ -60,6 +61,10 @@ make CONFIG=configs/benchmark/ihp130-hazard3-coremark.mk SIMU=VERILATOR coremark
|
|||||||
# Hazard3 remote-bitbang, OpenOCD, and GDB acceptance flow
|
# Hazard3 remote-bitbang, OpenOCD, and GDB acceptance flow
|
||||||
make CONFIG=configs/ci/ihp130-debug.mk SIMU=VERILATOR debug-sim
|
make CONFIG=configs/ci/ihp130-debug.mk SIMU=VERILATOR debug-sim
|
||||||
|
|
||||||
|
# Build the locked OpenSBI/Linux/initramfs set and LP/HP flash bundle
|
||||||
|
make setup-hp-linux
|
||||||
|
make CONFIG=configs/ci/ihp130-hp.mk hp-bundle
|
||||||
|
|
||||||
# Build the SRAM-resident XPI NOR loader used by the host JTAG tool
|
# Build the SRAM-resident XPI NOR loader used by the host JTAG tool
|
||||||
make CONFIG=configs/ci/ihp130-xpi-flash-loader.mk firmware
|
make CONFIG=configs/ci/ihp130-xpi-flash-loader.mk firmware
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
APP_SRCS += $(ROOT_PATH)/app/apps/hp_boot/main.c
|
||||||
|
APP_INC_DIRS += $(ROOT_PATH)/app/apps/hp_boot
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef RETROSOC_HP_BOOT_BUNDLE_H
|
||||||
|
#define RETROSOC_HP_BOOT_BUNDLE_H
|
||||||
|
|
||||||
|
#include <stdint.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_ENTRY_COUNT UINT32_C(4)
|
||||||
|
#define RS_HP_BOOT_BUNDLE_REQUIRED UINT32_C(1)
|
||||||
|
|
||||||
|
#define RS_HP_BOOT_TYPE_OPENSBI UINT32_C(1)
|
||||||
|
#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_OPENSBI_ADDRESS UINT32_C(0x38000000)
|
||||||
|
#define RS_HP_BOOT_OPENSBI_MAX_SIZE UINT32_C(0x00080000)
|
||||||
|
#define RS_HP_BOOT_DTB_ADDRESS UINT32_C(0x38080000)
|
||||||
|
#define RS_HP_BOOT_DTB_MAX_SIZE UINT32_C(0x00010000)
|
||||||
|
#define RS_HP_BOOT_LINUX_ADDRESS UINT32_C(0x38400000)
|
||||||
|
#define RS_HP_BOOT_LINUX_MAX_SIZE UINT32_C(0x00C00000)
|
||||||
|
#define RS_HP_BOOT_INITRAMFS_ADDRESS UINT32_C(0x39000000)
|
||||||
|
#define RS_HP_BOOT_INITRAMFS_MAX_SIZE UINT32_C(0x00800000)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t flash_offset;
|
||||||
|
uint32_t load_address;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t flags;
|
||||||
|
} rs_hp_boot_entry_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t header_size;
|
||||||
|
uint32_t entry_count;
|
||||||
|
uint32_t total_size;
|
||||||
|
uint32_t header_crc32;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t reserved;
|
||||||
|
rs_hp_boot_entry_t entries[RS_HP_BOOT_BUNDLE_ENTRY_COUNT];
|
||||||
|
} rs_hp_boot_header_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <retrosoc/core/soc.h>
|
||||||
|
#include <retrosoc/hal/hp_mailbox.h>
|
||||||
|
#include <retrosoc/hal/sdram.h>
|
||||||
|
#include <retrosoc/hal/sysctrl.h>
|
||||||
|
#include <retrosoc/hal/uart.h>
|
||||||
|
#include <retrosoc/lib/printf.h>
|
||||||
|
#include <retrosoc/service/test.h>
|
||||||
|
|
||||||
|
#include "hp_boot_bundle.h"
|
||||||
|
|
||||||
|
#define RS_HP_BOOT_HEADER_SIZE UINT32_C(128)
|
||||||
|
#define RS_HP_BOOT_READY_EVENT UINT32_C(1)
|
||||||
|
#define RS_HP_BOOT_READY_ARG UINT32_C(0x4C4E5801)
|
||||||
|
#define RS_HP_BOOT_READBACK_STRIDE_BYTES UINT32_C(1024)
|
||||||
|
|
||||||
|
_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);
|
||||||
|
uint8_t *destination = (uint8_t *)header;
|
||||||
|
|
||||||
|
for (uint32_t index = 0U; index < sizeof(*header); ++index) {
|
||||||
|
destination[index] = source[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
volatile uint32_t *destination_words = (volatile uint32_t *)(uintptr_t)entry->load_address;
|
||||||
|
uint32_t word_count = entry->size / (uint32_t)sizeof(uint32_t);
|
||||||
|
uint32_t crc = UINT32_C(0xFFFFFFFF);
|
||||||
|
bool verify_full = entry->size <= RS_HP_BOOT_READBACK_STRIDE_BYTES;
|
||||||
|
|
||||||
|
for (uint32_t index = 0U; index < word_count; ++index) {
|
||||||
|
uint32_t value = source_words[index];
|
||||||
|
destination_words[index] = value;
|
||||||
|
if (verify_full && (destination_words[index] != value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
crc = rs_hp_boot_crc32_byte(crc, (uint8_t)value);
|
||||||
|
crc = rs_hp_boot_crc32_byte(crc, (uint8_t)(value >> 8U));
|
||||||
|
crc = rs_hp_boot_crc32_byte(crc, (uint8_t)(value >> 16U));
|
||||||
|
crc = rs_hp_boot_crc32_byte(crc, (uint8_t)(value >> 24U));
|
||||||
|
}
|
||||||
|
for (uint32_t index = word_count * (uint32_t)sizeof(uint32_t); index < entry->size; ++index) {
|
||||||
|
volatile const uint8_t *source_bytes =
|
||||||
|
(volatile const uint8_t *)(uintptr_t)(RS_SOC_FLASH_BASE + entry->flash_offset);
|
||||||
|
volatile uint8_t *destination_bytes = (volatile uint8_t *)(uintptr_t)entry->load_address;
|
||||||
|
uint8_t value = source_bytes[index];
|
||||||
|
destination_bytes[index] = value;
|
||||||
|
if (verify_full && (destination_bytes[index] != value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
crc = rs_hp_boot_crc32_byte(crc, value);
|
||||||
|
}
|
||||||
|
return (~crc) == entry->crc32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rs_hp_boot_wait_sdram(void) {
|
||||||
|
rs_sdram_status_t status;
|
||||||
|
|
||||||
|
for (uint32_t timeout = 0U; timeout < RS_TIMEOUT_DEFAULT; ++timeout) {
|
||||||
|
if ((rs_sdram_get_status(&status) == RS_OK) && status.ready && !status.init_busy &&
|
||||||
|
!status.error) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rs_hp_boot_fail(uint8_t code) {
|
||||||
|
(void)rs_sysctrl_set_hp_release(false);
|
||||||
|
printf("HP_BOOT_FAILED:%u\n", (unsigned int)code);
|
||||||
|
rs_test_finish(RS_TEST_FAILED, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
rs_hp_boot_header_t header;
|
||||||
|
rs_sysctrl_hp_status_t hp_status;
|
||||||
|
rs_hp_mailbox_message_t message;
|
||||||
|
|
||||||
|
if (rs_uart_init(CPU_FREQ * UINT32_C(1000000), UART_BPS) != RS_OK) {
|
||||||
|
rs_test_finish(RS_TEST_FAILED, UINT8_C(1));
|
||||||
|
}
|
||||||
|
if ((rs_sysctrl_set_hp_release(false) != RS_OK) ||
|
||||||
|
(rs_sysctrl_select_hp_debug(false) != RS_OK) ||
|
||||||
|
(rs_sysctrl_get_hp_status(&hp_status) != RS_OK) || !hp_status.present ||
|
||||||
|
!hp_status.reset_asserted) {
|
||||||
|
rs_hp_boot_fail(UINT8_C(2));
|
||||||
|
}
|
||||||
|
if (!rs_hp_boot_wait_sdram()) {
|
||||||
|
rs_hp_boot_fail(UINT8_C(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_hp_boot_read_header(&header);
|
||||||
|
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) {
|
||||||
|
printf("HP_BOOT_LOAD:%u:%u\n", (unsigned int)header.entries[index].type,
|
||||||
|
(unsigned int)header.entries[index].size);
|
||||||
|
if (!rs_hp_boot_copy_entry(&header.entries[index])) {
|
||||||
|
rs_hp_boot_fail((uint8_t)(UINT8_C(5) + (uint8_t)index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm__ volatile("fence rw, rw" ::: "memory");
|
||||||
|
if ((rs_hp_mailbox_clear_lp_interrupt() != RS_OK) ||
|
||||||
|
(rs_sysctrl_set_hp_release(true) != RS_OK) ||
|
||||||
|
(rs_sysctrl_get_hp_status(&hp_status) != RS_OK) || !hp_status.released) {
|
||||||
|
rs_hp_boot_fail(UINT8_C(9));
|
||||||
|
}
|
||||||
|
printf("HP_BOOT_RELEASED\n");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if ((rs_hp_mailbox_receive_from_hp(&message) == RS_OK) && (message.sequence != 0U)) {
|
||||||
|
if ((message.code == RS_HP_BOOT_READY_EVENT) &&
|
||||||
|
(message.argument == RS_HP_BOOT_READY_ARG)) {
|
||||||
|
printf("HP_LINUX_READY\n");
|
||||||
|
rs_test_finish(RS_TEST_PASSED, UINT8_C(0));
|
||||||
|
}
|
||||||
|
rs_hp_boot_fail(UINT8_C(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# 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,
|
||||||
|
OpenSBI, Buildroot, toolchains, and all generated images remain below `.cache/`
|
||||||
|
or `build/` and are not tracked.
|
||||||
|
|
||||||
|
The MVP uses OpenSBI `FW_JUMP` without U-Boot. Its fixed SDRAM layout is:
|
||||||
|
|
||||||
|
| Artifact | Address | Maximum size |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| OpenSBI | `0x38000000` | 512 KiB |
|
||||||
|
| DTB | `0x38080000` | 64 KiB |
|
||||||
|
| Linux Image | `0x38400000` | 12 MiB |
|
||||||
|
| initramfs | `0x39000000` | 8 MiB |
|
||||||
|
|
||||||
|
Run `make setup-hp-linux` to install the locked sources, then use the
|
||||||
|
`hp-linux` target from an `HAVE_HP=YES` committed profile. The initial Linux
|
||||||
|
console uses SBI; the UART1 and mailbox nodes reserve their stable platform
|
||||||
|
ABI for the native drivers.
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
CONFIG_DEVMEM=y
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
BR2_riscv=y
|
||||||
|
BR2_RISCV_32=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_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_TARGET_ROOTFS_CPIO=y
|
||||||
|
BR2_TARGET_ROOTFS_CPIO_GZIP=y
|
||||||
|
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_RETROSOC_HP_PATH)/rootfs-overlay"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
name: RETROSOC_HP
|
||||||
|
desc: retroSoC RV32 HP Linux system
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
CONFIG_ARCH_RV32I=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_HVC_RISCV_SBI=y
|
||||||
|
CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
|
||||||
|
CONFIG_SIFIVE_PLIC=y
|
||||||
|
CONFIG_BLK_DEV_INITRD=y
|
||||||
|
CONFIG_RD_GZIP=y
|
||||||
|
CONFIG_DEVTMPFS=y
|
||||||
|
CONFIG_DEVTMPFS_MOUNT=y
|
||||||
|
CONFIG_DEVMEM=y
|
||||||
|
CONFIG_TMPFS=y
|
||||||
|
CONFIG_PRINTK_TIME=y
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
compatible = "retrosoc,mini-hp";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
chosen {
|
||||||
|
bootargs = "console=hvc0 earlycon=sbi rdinit=/sbin/init";
|
||||||
|
linux,initrd-start = <0x39000000>;
|
||||||
|
/* build_hp_linux.py replaces this with the actual rootfs end. */
|
||||||
|
linux,initrd-end = <0x39000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
timebase-frequency = <1000000>;
|
||||||
|
|
||||||
|
cpu@1 {
|
||||||
|
compatible = "spinal,vexiiriscv", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <1>;
|
||||||
|
clock-frequency = <72000000>;
|
||||||
|
mmu-type = "riscv,sv32";
|
||||||
|
riscv,isa-base = "rv32i";
|
||||||
|
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicsr",
|
||||||
|
"zifencei";
|
||||||
|
|
||||||
|
hp_cpu_intc: interrupt-controller {
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <0>;
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
memory@38000000 {
|
||||||
|
device_type = "memory";
|
||||||
|
reg = <0x38000000 0x04000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
soc {
|
||||||
|
compatible = "simple-bus";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
hp_aclint: timer@2000000 {
|
||||||
|
compatible = "sifive,clint0";
|
||||||
|
reg = <0x02000000 0x00010000>;
|
||||||
|
interrupts-extended = <&hp_cpu_intc 3>, <&hp_cpu_intc 7>;
|
||||||
|
};
|
||||||
|
|
||||||
|
hp_plic: interrupt-controller@c000000 {
|
||||||
|
compatible = "sifive,plic-1.0.0";
|
||||||
|
reg = <0x0c000000 0x04000000>;
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <0>;
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
riscv,ndev = <31>;
|
||||||
|
interrupts-extended = <&hp_cpu_intc 11>, <&hp_cpu_intc 9>;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart1: serial@10018000 {
|
||||||
|
compatible = "retrosoc,uart-v3";
|
||||||
|
reg = <0x10018000 0x1000>;
|
||||||
|
interrupt-parent = <&hp_plic>;
|
||||||
|
interrupts = <1>;
|
||||||
|
clock-frequency = <72000000>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
hp_mailbox: mailbox@10019000 {
|
||||||
|
compatible = "retrosoc,hp-mailbox-v1";
|
||||||
|
reg = <0x10019000 0x1000>;
|
||||||
|
interrupt-parent = <&hp_plic>;
|
||||||
|
interrupts = <2>;
|
||||||
|
#mbox-cells = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
config PLATFORM_RETROSOC_HP
|
||||||
|
bool
|
||||||
|
select IPI_MSWI
|
||||||
|
select TIMER_MTIMER
|
||||||
|
default y
|
||||||
Whitespace-only changes.
@@ -0,0 +1,3 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
platform-objs-y += platform.o
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
|
/* Copyright (c) 2026 Yuchi Miao */
|
||||||
|
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_platform.h>
|
||||||
|
#include <sbi_utils/ipi/aclint_mswi.h>
|
||||||
|
#include <sbi_utils/timer/aclint_mtimer.h>
|
||||||
|
|
||||||
|
#define RETROSOC_HP_ACLINT_BASE 0x02000000UL
|
||||||
|
#define RETROSOC_HP_UART_BASE 0x10018000UL
|
||||||
|
#define RETROSOC_HP_UART_BAUD_INT 78U
|
||||||
|
#define RETROSOC_HP_UART_BAUD_FRAC 32U
|
||||||
|
#define RETROSOC_HP_UART_BAUD_INT_REG 0x00UL
|
||||||
|
#define RETROSOC_HP_UART_BAUD_FRAC_REG 0x04UL
|
||||||
|
#define RETROSOC_HP_UART_LINE_CTRL_REG 0x08UL
|
||||||
|
#define RETROSOC_HP_UART_CTRL_REG 0x0CUL
|
||||||
|
#define RETROSOC_HP_UART_TXDATA_REG 0x10UL
|
||||||
|
#define RETROSOC_HP_UART_RXDATA_REG 0x14UL
|
||||||
|
#define RETROSOC_HP_UART_STATUS_REG 0x18UL
|
||||||
|
#define RETROSOC_HP_UART_FIFO_CTRL_REG 0x20UL
|
||||||
|
#define RETROSOC_HP_UART_ERROR_REG 0x30UL
|
||||||
|
#define RETROSOC_HP_UART_INTR_ENABLE_REG 0x38UL
|
||||||
|
#define RETROSOC_HP_UART_TX_FULL 0x20U
|
||||||
|
#define RETROSOC_HP_UART_RX_EMPTY 0x40U
|
||||||
|
#define RETROSOC_HP_UART_ENABLE 0x03U
|
||||||
|
#define RETROSOC_HP_UART_FIFO_FLUSH 0x03U
|
||||||
|
#define RETROSOC_HP_UART_ERROR_ALL 0x7FU
|
||||||
|
|
||||||
|
static const u32 s_hart_index_to_id[] = {1U};
|
||||||
|
|
||||||
|
static struct aclint_mswi_data s_mswi = {
|
||||||
|
.addr = RETROSOC_HP_ACLINT_BASE,
|
||||||
|
.size = ACLINT_MSWI_SIZE,
|
||||||
|
.first_hartid = 0U,
|
||||||
|
.hart_count = 2U,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct aclint_mtimer_data s_mtimer = {
|
||||||
|
.mtime_freq = 1000000UL,
|
||||||
|
.mtime_addr = RETROSOC_HP_ACLINT_BASE + 0xBFF8UL,
|
||||||
|
.mtime_size = ACLINT_DEFAULT_MTIME_SIZE,
|
||||||
|
.mtimecmp_addr = RETROSOC_HP_ACLINT_BASE + 0x4000UL,
|
||||||
|
.mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE,
|
||||||
|
.first_hartid = 0U,
|
||||||
|
.hart_count = 2U,
|
||||||
|
.has_64bit_mmio = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void retrosoc_hp_uart_write(u32 offset, u32 value) {
|
||||||
|
writel(value, (void *)(RETROSOC_HP_UART_BASE + offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 retrosoc_hp_uart_read(u32 offset) {
|
||||||
|
return readl((const void *)(RETROSOC_HP_UART_BASE + offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void retrosoc_hp_console_putc(char value) {
|
||||||
|
while ((retrosoc_hp_uart_read(RETROSOC_HP_UART_STATUS_REG) & RETROSOC_HP_UART_TX_FULL) != 0U) {
|
||||||
|
}
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_TXDATA_REG, (u32)(unsigned char)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int retrosoc_hp_console_getc(void) {
|
||||||
|
if ((retrosoc_hp_uart_read(RETROSOC_HP_UART_STATUS_REG) & RETROSOC_HP_UART_RX_EMPTY) != 0U) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (int)(retrosoc_hp_uart_read(RETROSOC_HP_UART_RXDATA_REG) & 0xFFU);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sbi_console_device s_console = {
|
||||||
|
.name = "retrosoc-uart1",
|
||||||
|
.console_putc = retrosoc_hp_console_putc,
|
||||||
|
.console_getc = retrosoc_hp_console_getc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int retrosoc_hp_early_init(bool cold_boot) {
|
||||||
|
if (!cold_boot) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_CTRL_REG, 0U);
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_FIFO_CTRL_REG, RETROSOC_HP_UART_FIFO_FLUSH);
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_ERROR_REG, RETROSOC_HP_UART_ERROR_ALL);
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_INTR_ENABLE_REG, 0U);
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_BAUD_INT_REG, RETROSOC_HP_UART_BAUD_INT);
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_BAUD_FRAC_REG, RETROSOC_HP_UART_BAUD_FRAC);
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_LINE_CTRL_REG, 3U);
|
||||||
|
retrosoc_hp_uart_write(RETROSOC_HP_UART_CTRL_REG, RETROSOC_HP_UART_ENABLE);
|
||||||
|
sbi_console_set_device(&s_console);
|
||||||
|
|
||||||
|
return aclint_mswi_cold_init(&s_mswi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int retrosoc_hp_timer_init(void) {
|
||||||
|
return aclint_mtimer_cold_init(&s_mtimer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sbi_platform_operations s_platform_operations = {
|
||||||
|
.early_init = retrosoc_hp_early_init,
|
||||||
|
.timer_init = retrosoc_hp_timer_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct sbi_platform platform = {
|
||||||
|
.opensbi_version = OPENSBI_VERSION,
|
||||||
|
.platform_version = SBI_PLATFORM_VERSION(1U, 0U),
|
||||||
|
.name = "retroSoC RV32 HP",
|
||||||
|
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
||||||
|
.hart_count = 1U,
|
||||||
|
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
||||||
|
.heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(1U),
|
||||||
|
.platform_ops_addr = (unsigned long)&s_platform_operations,
|
||||||
|
.hart_index2id = s_hart_index_to_id,
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#!/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
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x38000000;
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
KEEP(*(.text.start))
|
||||||
|
*(.text*)
|
||||||
|
*(.rodata*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
.section .text.start
|
||||||
|
.global _start
|
||||||
|
.type _start, @function
|
||||||
|
|
||||||
|
.equ UART1_BASE, 0x10018000
|
||||||
|
.equ UART_BAUD_INT, 0x00
|
||||||
|
.equ UART_BAUD_FRAC, 0x04
|
||||||
|
.equ UART_LINE_CTRL, 0x08
|
||||||
|
.equ UART_CTRL, 0x0c
|
||||||
|
.equ UART_TXDATA, 0x10
|
||||||
|
.equ UART_STATUS, 0x18
|
||||||
|
.equ UART_FIFO_CTRL, 0x20
|
||||||
|
.equ UART_ERROR, 0x30
|
||||||
|
.equ UART_INTR_ENABLE, 0x38
|
||||||
|
.equ UART_TX_FULL, 0x20
|
||||||
|
|
||||||
|
.equ MAILBOX_BASE, 0x10019000
|
||||||
|
.equ HP_EVENT, 0x20
|
||||||
|
.equ HP_ARG0, 0x24
|
||||||
|
.equ HP_SEQUENCE, 0x28
|
||||||
|
.equ HP_DOORBELL, 0x2c
|
||||||
|
.equ HP_READY_ARG, 0x4c4e5801
|
||||||
|
|
||||||
|
_start:
|
||||||
|
li t0, UART1_BASE
|
||||||
|
sw zero, UART_CTRL(t0)
|
||||||
|
li t1, 3
|
||||||
|
sw t1, UART_FIFO_CTRL(t0)
|
||||||
|
li t1, 0x7f
|
||||||
|
sw t1, UART_ERROR(t0)
|
||||||
|
sw zero, UART_INTR_ENABLE(t0)
|
||||||
|
li t1, 78
|
||||||
|
sw t1, UART_BAUD_INT(t0)
|
||||||
|
li t1, 32
|
||||||
|
sw t1, UART_BAUD_FRAC(t0)
|
||||||
|
li t1, 3
|
||||||
|
sw t1, UART_LINE_CTRL(t0)
|
||||||
|
sw t1, UART_CTRL(t0)
|
||||||
|
|
||||||
|
la a0, hp_message
|
||||||
|
write_character:
|
||||||
|
lbu a1, 0(a0)
|
||||||
|
beqz a1, publish_ready
|
||||||
|
wait_tx_space:
|
||||||
|
lw a2, UART_STATUS(t0)
|
||||||
|
andi a2, a2, UART_TX_FULL
|
||||||
|
bnez a2, wait_tx_space
|
||||||
|
sw a1, UART_TXDATA(t0)
|
||||||
|
addi a0, a0, 1
|
||||||
|
j write_character
|
||||||
|
|
||||||
|
publish_ready:
|
||||||
|
li t0, MAILBOX_BASE
|
||||||
|
li t1, 1
|
||||||
|
sw t1, HP_EVENT(t0)
|
||||||
|
li t1, HP_READY_ARG
|
||||||
|
sw t1, HP_ARG0(t0)
|
||||||
|
li t1, 1
|
||||||
|
sw t1, HP_SEQUENCE(t0)
|
||||||
|
fence w, w
|
||||||
|
sw t1, HP_DOORBELL(t0)
|
||||||
|
|
||||||
|
halt:
|
||||||
|
j halt
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
hp_message:
|
||||||
|
.asciz "HP_SMOKE_READY\n"
|
||||||
@@ -12,6 +12,11 @@ profiles. The `ihp130-hazard3-coremark.mk` profile is the automated SRAM
|
|||||||
CoreMark quick measurement; its `-standard` counterpart is reserved for a
|
CoreMark quick measurement; its `-standard` counterpart is reserved for a
|
||||||
10-second hardware run. The nightly workflow reuses the IHP130 CI profile and
|
10-second hardware run. The nightly workflow reuses the IHP130 CI profile and
|
||||||
runs the quick CoreMark profile.
|
runs the quick CoreMark profile.
|
||||||
|
`ci/ihp130-hp.mk` is the experimental asymmetric Linux profile. It fixes both
|
||||||
|
LP and HP at 72 MHz, runs `hp_boot` entirely from 32 KiB on-chip SRAM, 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-xpi-flash-loader.mk` builds the SRAM-only XPI NOR service image used
|
`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.
|
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
|
Start builds from a committed profile rather than setting an unreviewed mix of
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
SOC := MINI
|
||||||
|
PDK := IHP130
|
||||||
|
HAVE_PLL := NO
|
||||||
|
HAVE_HP := YES
|
||||||
|
HP_CONFIG := rv32imafdc_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
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef RETROSOC_HAL_HP_MAILBOX_H
|
||||||
|
#define RETROSOC_HAL_HP_MAILBOX_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <retrosoc/core/status.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t code;
|
||||||
|
uint32_t argument;
|
||||||
|
uint32_t sequence;
|
||||||
|
} rs_hp_mailbox_message_t;
|
||||||
|
|
||||||
|
rs_status_t rs_hp_mailbox_probe(void);
|
||||||
|
rs_status_t rs_hp_mailbox_send_to_hp(const rs_hp_mailbox_message_t *message);
|
||||||
|
rs_status_t rs_hp_mailbox_receive_from_hp(rs_hp_mailbox_message_t *message);
|
||||||
|
rs_status_t rs_hp_mailbox_enable_lp_interrupt(bool enable);
|
||||||
|
rs_status_t rs_hp_mailbox_lp_interrupt_pending(bool *pending);
|
||||||
|
rs_status_t rs_hp_mailbox_clear_lp_interrupt(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -50,6 +50,12 @@ typedef struct {
|
|||||||
bool capable;
|
bool capable;
|
||||||
} rs_sysctrl_pll_status_t;
|
} rs_sysctrl_pll_status_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool present;
|
||||||
|
bool released;
|
||||||
|
bool reset_asserted;
|
||||||
|
} rs_sysctrl_hp_status_t;
|
||||||
|
|
||||||
rs_status_t rs_sysctrl_get_core_select(uint8_t *core_id);
|
rs_status_t rs_sysctrl_get_core_select(uint8_t *core_id);
|
||||||
rs_status_t rs_sysctrl_set_core_select(uint8_t core_id);
|
rs_status_t rs_sysctrl_set_core_select(uint8_t core_id);
|
||||||
rs_status_t rs_sysctrl_get_ip_select(uint8_t *ip_id);
|
rs_status_t rs_sysctrl_get_ip_select(uint8_t *ip_id);
|
||||||
@@ -70,5 +76,8 @@ void rs_sysctrl_write_test_status(bool pass, uint8_t code);
|
|||||||
rs_status_t rs_sysctrl_get_test_status(bool *done, bool *pass, uint8_t *code);
|
rs_status_t rs_sysctrl_get_test_status(bool *done, bool *pass, uint8_t *code);
|
||||||
rs_status_t rs_sysctrl_get_rtc_wake_status(bool *live, bool *seen);
|
rs_status_t rs_sysctrl_get_rtc_wake_status(bool *live, bool *seen);
|
||||||
rs_status_t rs_sysctrl_clear_rtc_wake(void);
|
rs_status_t rs_sysctrl_clear_rtc_wake(void);
|
||||||
|
rs_status_t rs_sysctrl_set_hp_release(bool release);
|
||||||
|
rs_status_t rs_sysctrl_get_hp_status(rs_sysctrl_hp_status_t *status);
|
||||||
|
rs_status_t rs_sysctrl_select_hp_debug(bool select_hp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <retrosoc/core/soc.h>
|
||||||
|
#include <retrosoc/hal/hp_mailbox.h>
|
||||||
|
|
||||||
|
#define RS_HP_MAILBOX_IP_VERSION_OFFSET UINT32_C(0x000)
|
||||||
|
#define RS_HP_MAILBOX_CAPABILITY_OFFSET UINT32_C(0x004)
|
||||||
|
#define RS_HP_MAILBOX_LP_COMMAND_OFFSET UINT32_C(0x010)
|
||||||
|
#define RS_HP_MAILBOX_LP_ARG0_OFFSET UINT32_C(0x014)
|
||||||
|
#define RS_HP_MAILBOX_LP_SEQUENCE_OFFSET UINT32_C(0x018)
|
||||||
|
#define RS_HP_MAILBOX_LP_DOORBELL_OFFSET UINT32_C(0x01C)
|
||||||
|
#define RS_HP_MAILBOX_HP_EVENT_OFFSET UINT32_C(0x020)
|
||||||
|
#define RS_HP_MAILBOX_HP_ARG0_OFFSET UINT32_C(0x024)
|
||||||
|
#define RS_HP_MAILBOX_HP_SEQUENCE_OFFSET UINT32_C(0x028)
|
||||||
|
#define RS_HP_MAILBOX_LP_INTR_STATE_OFFSET UINT32_C(0x030)
|
||||||
|
#define RS_HP_MAILBOX_LP_INTR_ENABLE_OFFSET UINT32_C(0x034)
|
||||||
|
|
||||||
|
#define RS_HP_MAILBOX_IP_VERSION_VALUE UINT32_C(0x00010000)
|
||||||
|
#define RS_HP_MAILBOX_CAPABILITY_VALUE UINT32_C(0x00000007)
|
||||||
|
|
||||||
|
static volatile uint32_t *rs_hp_mailbox_register(uint32_t offset) {
|
||||||
|
return (volatile uint32_t *)(uintptr_t)(RS_SOC_APB4_HP_MAILBOX_BASE + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_hp_mailbox_probe(void) {
|
||||||
|
return ((*rs_hp_mailbox_register(RS_HP_MAILBOX_IP_VERSION_OFFSET) ==
|
||||||
|
RS_HP_MAILBOX_IP_VERSION_VALUE) &&
|
||||||
|
(*rs_hp_mailbox_register(RS_HP_MAILBOX_CAPABILITY_OFFSET) ==
|
||||||
|
RS_HP_MAILBOX_CAPABILITY_VALUE))
|
||||||
|
? RS_OK
|
||||||
|
: RS_ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_hp_mailbox_send_to_hp(const rs_hp_mailbox_message_t *message) {
|
||||||
|
if ((message == NULL) || (message->sequence == 0U)) {
|
||||||
|
return RS_EINVAL;
|
||||||
|
}
|
||||||
|
*rs_hp_mailbox_register(RS_HP_MAILBOX_LP_COMMAND_OFFSET) = message->code;
|
||||||
|
*rs_hp_mailbox_register(RS_HP_MAILBOX_LP_ARG0_OFFSET) = message->argument;
|
||||||
|
*rs_hp_mailbox_register(RS_HP_MAILBOX_LP_SEQUENCE_OFFSET) = message->sequence;
|
||||||
|
__asm__ volatile("fence w, w" ::: "memory");
|
||||||
|
*rs_hp_mailbox_register(RS_HP_MAILBOX_LP_DOORBELL_OFFSET) = UINT32_C(1);
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_hp_mailbox_receive_from_hp(rs_hp_mailbox_message_t *message) {
|
||||||
|
uint32_t sequence;
|
||||||
|
|
||||||
|
if (message == NULL) {
|
||||||
|
return RS_EINVAL;
|
||||||
|
}
|
||||||
|
sequence = *rs_hp_mailbox_register(RS_HP_MAILBOX_HP_SEQUENCE_OFFSET);
|
||||||
|
__asm__ volatile("fence r, r" ::: "memory");
|
||||||
|
message->code = *rs_hp_mailbox_register(RS_HP_MAILBOX_HP_EVENT_OFFSET);
|
||||||
|
message->argument = *rs_hp_mailbox_register(RS_HP_MAILBOX_HP_ARG0_OFFSET);
|
||||||
|
message->sequence = sequence;
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_hp_mailbox_enable_lp_interrupt(bool enable) {
|
||||||
|
*rs_hp_mailbox_register(RS_HP_MAILBOX_LP_INTR_ENABLE_OFFSET) =
|
||||||
|
enable ? UINT32_C(1) : UINT32_C(0);
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_hp_mailbox_lp_interrupt_pending(bool *pending) {
|
||||||
|
if (pending == NULL) {
|
||||||
|
return RS_EINVAL;
|
||||||
|
}
|
||||||
|
*pending = (*rs_hp_mailbox_register(RS_HP_MAILBOX_LP_INTR_STATE_OFFSET) & UINT32_C(1)) != 0U;
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_hp_mailbox_clear_lp_interrupt(void) {
|
||||||
|
*rs_hp_mailbox_register(RS_HP_MAILBOX_LP_INTR_STATE_OFFSET) = UINT32_C(1);
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
@@ -40,6 +40,9 @@
|
|||||||
#define RS_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET
|
#define RS_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET
|
||||||
#define RS_SYSCTRL_TEST_STATUS_OFFSET RS_SOC_SYSCTRL_TEST_STATUS_OFFSET
|
#define RS_SYSCTRL_TEST_STATUS_OFFSET RS_SOC_SYSCTRL_TEST_STATUS_OFFSET
|
||||||
#define RS_SYSCTRL_RTC_WAKE_STATUS_OFFSET RS_SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET
|
#define RS_SYSCTRL_RTC_WAKE_STATUS_OFFSET RS_SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET
|
||||||
|
#define RS_SYSCTRL_HP_CTRL_OFFSET RS_SOC_SYSCTRL_HP_CTRL_OFFSET
|
||||||
|
#define RS_SYSCTRL_HP_STATUS_OFFSET RS_SOC_SYSCTRL_HP_STATUS_OFFSET
|
||||||
|
#define RS_SYSCTRL_DEBUG_SELECT_OFFSET RS_SOC_SYSCTRL_DEBUG_SELECT_OFFSET
|
||||||
|
|
||||||
#define RS_SYSCTRL_PLL_CMD_APPLY UINT32_C(0x00000001)
|
#define RS_SYSCTRL_PLL_CMD_APPLY UINT32_C(0x00000001)
|
||||||
#define RS_SYSCTRL_PLL_CMD_CLEAR_ERROR UINT32_C(0x00000002)
|
#define RS_SYSCTRL_PLL_CMD_CLEAR_ERROR UINT32_C(0x00000002)
|
||||||
@@ -66,6 +69,9 @@
|
|||||||
#define RS_SYSCTRL_PLL_CAPABLE UINT32_C(0x00000400)
|
#define RS_SYSCTRL_PLL_CAPABLE UINT32_C(0x00000400)
|
||||||
#define RS_SYSCTRL_RTC_WAKE_LIVE UINT32_C(0x00000001)
|
#define RS_SYSCTRL_RTC_WAKE_LIVE UINT32_C(0x00000001)
|
||||||
#define RS_SYSCTRL_RTC_WAKE_SEEN UINT32_C(0x00000002)
|
#define RS_SYSCTRL_RTC_WAKE_SEEN UINT32_C(0x00000002)
|
||||||
|
#define RS_SYSCTRL_HP_PRESENT UINT32_C(0x00000001)
|
||||||
|
#define RS_SYSCTRL_HP_RELEASED UINT32_C(0x00000002)
|
||||||
|
#define RS_SYSCTRL_HP_RESET_ASSERTED UINT32_C(0x00000004)
|
||||||
|
|
||||||
static volatile uint32_t *rs_sysctrl_register(uint32_t offset) {
|
static volatile uint32_t *rs_sysctrl_register(uint32_t offset) {
|
||||||
return (volatile uint32_t *)(RS_SOC_APB4_SYSCTRL_BASE + (uintptr_t)offset);
|
return (volatile uint32_t *)(RS_SOC_APB4_SYSCTRL_BASE + (uintptr_t)offset);
|
||||||
@@ -253,6 +259,47 @@ rs_status_t rs_sysctrl_clear_fault(void) {
|
|||||||
return RS_OK;
|
return RS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_sysctrl_set_hp_release(bool release) {
|
||||||
|
rs_sysctrl_hp_status_t status;
|
||||||
|
|
||||||
|
if ((rs_sysctrl_get_hp_status(&status) != RS_OK) || !status.present) {
|
||||||
|
return RS_ENOTSUP;
|
||||||
|
}
|
||||||
|
*rs_sysctrl_register(RS_SYSCTRL_HP_CTRL_OFFSET) = release ? UINT32_C(1) : UINT32_C(0);
|
||||||
|
if (rs_sysctrl_get_hp_status(&status) != RS_OK) {
|
||||||
|
return RS_EIO;
|
||||||
|
}
|
||||||
|
return (status.released == release) && (status.reset_asserted != release) ? RS_OK : RS_EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_sysctrl_get_hp_status(rs_sysctrl_hp_status_t *status) {
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
if (status == NULL) {
|
||||||
|
return RS_EINVAL;
|
||||||
|
}
|
||||||
|
value = *rs_sysctrl_register(RS_SYSCTRL_HP_STATUS_OFFSET);
|
||||||
|
status->present = (value & RS_SYSCTRL_HP_PRESENT) != 0U;
|
||||||
|
status->released = (value & RS_SYSCTRL_HP_RELEASED) != 0U;
|
||||||
|
status->reset_asserted = (value & RS_SYSCTRL_HP_RESET_ASSERTED) != 0U;
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_status_t rs_sysctrl_select_hp_debug(bool select_hp) {
|
||||||
|
rs_sysctrl_hp_status_t status;
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
if ((rs_sysctrl_get_hp_status(&status) != RS_OK) || !status.present) {
|
||||||
|
return RS_ENOTSUP;
|
||||||
|
}
|
||||||
|
if (status.released) {
|
||||||
|
return RS_EIO;
|
||||||
|
}
|
||||||
|
*rs_sysctrl_register(RS_SYSCTRL_DEBUG_SELECT_OFFSET) = select_hp ? UINT32_C(1) : UINT32_C(0);
|
||||||
|
value = *rs_sysctrl_register(RS_SYSCTRL_DEBUG_SELECT_OFFSET) & UINT32_C(1);
|
||||||
|
return (value == (select_hp ? UINT32_C(1) : UINT32_C(0))) ? RS_OK : RS_EIO;
|
||||||
|
}
|
||||||
|
|
||||||
rs_status_t rs_sysctrl_set_perf_control(bool enable, bool clear, bool snapshot) {
|
rs_status_t rs_sysctrl_set_perf_control(bool enable, bool clear, bool snapshot) {
|
||||||
uint32_t control = 0U;
|
uint32_t control = 0U;
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
@@ -20,3 +20,9 @@ The locked SKY130 OpenRAM SRAM archive is generated and published by the
|
|||||||
manifest, geometry, source revisions, generated-file hashes, and TT/SS views
|
manifest, geometry, source revisions, generated-file hashes, and TT/SS views
|
||||||
before materializing it below `.cache/retrosoc/pdk/sky130/openram/`. Generated
|
before materializing it below `.cache/retrosoc/pdk/sky130/openram/`. Generated
|
||||||
Verilog, Liberty, LEF, GDS, and SPICE views are never committed here.
|
Verilog, Liberty, LEF, GDS, and SPICE views are never committed here.
|
||||||
|
|
||||||
|
The HP profile additionally locks VexiiRiscv, OpenSBI, Linux stable, and
|
||||||
|
Buildroot source revisions. `make setup-hp-linux` installs the software sources
|
||||||
|
below `.cache/retrosoc/sources/`; VexiiRiscv may be supplied through
|
||||||
|
`VEXIIRISCV_ROOT`, but its revision is still checked before generated RTL is
|
||||||
|
accepted. No generated CPU RTL or Linux build output belongs in Git.
|
||||||
Vendored
+26
-1
@@ -13,6 +13,31 @@
|
|||||||
"destination": "rtl/managed/hazard3",
|
"destination": "rtl/managed/hazard3",
|
||||||
"license": "NOASSERTION"
|
"license": "NOASSERTION"
|
||||||
},
|
},
|
||||||
|
"vexiiriscv": {
|
||||||
|
"url": "https://github.com/SpinalHDL/VexiiRiscv.git",
|
||||||
|
"revision": "ef7da4134ff11ec6a681d0632123b232b853b046",
|
||||||
|
"destination": ".cache/retrosoc/sources/vexiiriscv",
|
||||||
|
"recursive": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"opensbi_hp": {
|
||||||
|
"url": "https://github.com/riscv-software-src/opensbi.git",
|
||||||
|
"revision": "cbf9f6734dd85a982c63e3cb5db7ffe09da839ca",
|
||||||
|
"destination": ".cache/retrosoc/sources/opensbi-hp",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
|
"linux_hp": {
|
||||||
|
"url": "https://github.com/gregkh/linux.git",
|
||||||
|
"revision": "14c37ff05f22da2fa7076d10f6a07c7ede330c83",
|
||||||
|
"destination": ".cache/retrosoc/sources/linux-hp",
|
||||||
|
"license": "GPL-2.0-only"
|
||||||
|
},
|
||||||
|
"buildroot_hp": {
|
||||||
|
"url": "https://gitlab.com/buildroot.org/buildroot.git",
|
||||||
|
"revision": "cb857ba4c87a93e5265a9e4a3f32071abf39e14a",
|
||||||
|
"destination": ".cache/retrosoc/sources/buildroot-hp",
|
||||||
|
"license": "GPL-2.0-or-later"
|
||||||
|
},
|
||||||
"ibex": {
|
"ibex": {
|
||||||
"url": "https://github.com/lowRISC/ibex.git",
|
"url": "https://github.com/lowRISC/ibex.git",
|
||||||
"revision": "0c233f54361d769f370889223acc456f2ac19d46",
|
"revision": "0c233f54361d769f370889223acc456f2ac19d46",
|
||||||
@@ -61,7 +86,7 @@
|
|||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"cluster_archinfo": {"url": "https://github.com/retroSoC/archinfo.git", "revision": "78505969a0afdbc887cdd9b36eda228b4afb616e", "destination": "rtl/managed/clusterip/archinfo", "license": "MulanPSL-2.0"},
|
"cluster_archinfo": {"url": "https://github.com/retroSoC/archinfo.git", "revision": "78505969a0afdbc887cdd9b36eda228b4afb616e", "destination": "rtl/managed/clusterip/archinfo", "license": "MulanPSL-2.0"},
|
||||||
"cluster_common": {"url": "https://github.com/retroSoC/common.git", "revision": "5604bd5899bcc3a937cef55db4bac3b5102e562c", "destination": "rtl/managed/clusterip/common", "license": "NOASSERTION"},
|
"cluster_common": {"url": "https://github.com/retroSoC/common.git", "revision": "964a54d70cb78e394ba9a25c05f2aa2b02941fb7", "destination": "rtl/managed/clusterip/common", "license": "NOASSERTION"},
|
||||||
"cluster_crc": {"url": "https://github.com/retroSoC/crc.git", "revision": "8c1a5664c4d23d005c1afad432372a13ca967cc8", "destination": "rtl/managed/clusterip/crc", "license": "MulanPSL-2.0"},
|
"cluster_crc": {"url": "https://github.com/retroSoC/crc.git", "revision": "8c1a5664c4d23d005c1afad432372a13ca967cc8", "destination": "rtl/managed/clusterip/crc", "license": "MulanPSL-2.0"},
|
||||||
"cluster_ps2": {"url": "https://github.com/retroSoC/ps2.git", "revision": "2097a0d41b07573ff0453d65ba9a1670b3df7b9c", "destination": "rtl/managed/clusterip/ps2", "license": "MulanPSL-2.0"},
|
"cluster_ps2": {"url": "https://github.com/retroSoC/ps2.git", "revision": "2097a0d41b07573ff0453d65ba9a1670b3df7b9c", "destination": "rtl/managed/clusterip/ps2", "license": "MulanPSL-2.0"},
|
||||||
"cluster_pwm": {"url": "https://github.com/retroSoC/pwm.git", "revision": "79ae32f725e848a1e7f6134847b3fb032ed64006", "destination": "rtl/managed/clusterip/pwm", "license": "MulanPSL-2.0"},
|
"cluster_pwm": {"url": "https://github.com/retroSoC/pwm.git", "revision": "79ae32f725e848a1e7f6134847b3fb032ed64006", "destination": "rtl/managed/clusterip/pwm", "license": "MulanPSL-2.0"},
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ the root README and subsystem guides.
|
|||||||
register protocol and software quiesce contract.
|
register protocol and software quiesce contract.
|
||||||
- [hazard3-debug.md](hazard3-debug.md) defines the management Hazard3 JTAG
|
- [hazard3-debug.md](hazard3-debug.md) defines the management Hazard3 JTAG
|
||||||
Debug Module integration, reset boundary, and Verilator/OpenOCD/GDB flow.
|
Debug Module integration, reset boundary, and Verilator/OpenOCD/GDB flow.
|
||||||
|
- [lp-hp-architecture.md](lp-hp-architecture.md) defines the implemented
|
||||||
|
Hazard3 LP/VexiiRiscv HP topology, Linux boot ABI, MVP evidence, and
|
||||||
|
commercial-alignment roadmap.
|
||||||
- [coremark.md](coremark.md) defines the SRAM-resident Hazard3 CoreMark quick
|
- [coremark.md](coremark.md) defines the SRAM-resident Hazard3 CoreMark quick
|
||||||
measurement, optional standard hardware run, and structured result format.
|
measurement, optional standard hardware run, and structured result format.
|
||||||
- [soc-family-positioning.md](soc-family-positioning.md) defines the planned
|
- [soc-family-positioning.md](soc-family-positioning.md) defines the planned
|
||||||
@@ -46,6 +49,8 @@ the root README and subsystem guides.
|
|||||||
counting modes, interrupt, debug-freeze, HAL, and verification contracts.
|
counting modes, interrupt, debug-freeze, HAL, and verification contracts.
|
||||||
- [ip/sysctrl.md](ip/sysctrl.md) defines the SystemCtrl register ABI, user-core
|
- [ip/sysctrl.md](ip/sysctrl.md) defines the SystemCtrl register ABI, user-core
|
||||||
lifecycle, PLL/fault/performance/RTC/test contracts, HAL, and verification.
|
lifecycle, PLL/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.
|
||||||
- [ip/onchip-sram.md](ip/onchip-sram.md) defines the configurable native-AXI4
|
- [ip/onchip-sram.md](ip/onchip-sram.md) defines the configurable native-AXI4
|
||||||
SRAM architecture, APB capability ABI, technology mapping, verification, and
|
SRAM architecture, APB capability ABI, technology mapping, verification, and
|
||||||
reliability roadmap.
|
reliability roadmap.
|
||||||
|
|||||||
@@ -21,14 +21,21 @@ Read and write ordering is therefore program order at each master. Different
|
|||||||
masters may use different targets concurrently; requests to one target use a
|
masters may use different targets concurrently; requests to one target use a
|
||||||
Common round-robin arbiter and retain ownership through `B` or `RLAST`.
|
Common round-robin arbiter and retain ownership through `B` or `RLAST`.
|
||||||
|
|
||||||
The three masters are the Hazard3 management core, the selected user core, and
|
The integrated fabric has eight master slots: Hazard3 management (0), selected
|
||||||
DMA. Hazard3 AHB-Lite and the current user-core RIBP ABI issue single-beat AXI4
|
user core (1), central DMA (2), SDIO0 (3), SDIO1 (4), the retained SPI-SD slot
|
||||||
transactions through adapters. DMA is a native AXI4 master: its production
|
(5), USB2 (6), and optional HP (7). Hazard3 AHB-Lite and the current user-core
|
||||||
|
RIBP ABI issue single-beat AXI4 transactions through adapters. DMA is a native AXI4 master: its production
|
||||||
six-channel engine uses fixed ID zero, independently schedules one read and
|
six-channel engine uses fixed ID zero, independently schedules one read and
|
||||||
one write transaction, and issues aligned `INCR` bursts up to sixteen beats.
|
one write transaction, and issues aligned `INCR` bursts up to sixteen beats.
|
||||||
Fixed-address and APB4/MMIO endpoints are always single-beat. See the
|
Fixed-address and APB4/MMIO endpoints are always single-beat. See the
|
||||||
[DMA MVP](ip/dma.md) for its ownership, abort, and FIFO-credit contract.
|
[DMA MVP](ip/dma.md) for its ownership, abort, and FIFO-credit contract.
|
||||||
|
|
||||||
|
HP presents separate 64-bit instruction-cache, data-cache, and uncached-MMIO
|
||||||
|
ports. Self-owned downsizers and a transaction mux serialize them onto master
|
||||||
|
7. A maximum eight-beat 64-bit transfer becomes the fabric maximum sixteen
|
||||||
|
32-bit beats. This is a compatibility plane without coherency; see the
|
||||||
|
[LP/HP contract](lp-hp-architecture.md).
|
||||||
|
|
||||||
## Targets and Access Control
|
## Targets and Access Control
|
||||||
|
|
||||||
The fixed targets are the APB4 configuration plane (`apb4_periph`), APB
|
The fixed targets are the APB4 configuration plane (`apb4_periph`), APB
|
||||||
@@ -66,7 +73,9 @@ access-control rejection to `PROTERR`.
|
|||||||
|
|
||||||
## Verification and Performance Gates
|
## Verification and Performance Gates
|
||||||
|
|
||||||
`tests/test_axi4.py` covers fabric classification. `tests/test_onchip_ram.py`
|
`tests/test_axi4.py` covers fabric classification, HP master 7 attribution,
|
||||||
|
64-to-32 burst/lane conversion, response identity, and backpressure.
|
||||||
|
`tests/test_onchip_ram.py`
|
||||||
covers all five capacities, sixteen-beat reads/writes, response backpressure,
|
covers all five capacities, sixteen-beat reads/writes, response backpressure,
|
||||||
partial writes, technology mapping, and error termination. The bridge unit
|
partial writes, technology mapping, and error termination. The bridge unit
|
||||||
test also covers Common address generation for FIXED and WRAP sequencing. The
|
test also covers Common address generation for FIXED and WRAP sequencing. The
|
||||||
|
|||||||
+8
-2
@@ -1,7 +1,9 @@
|
|||||||
# Core-Local Interruptor
|
# Core-Local Interruptor
|
||||||
|
|
||||||
The Mini SoC CLINT provides machine software and machine timer interrupts for
|
The baseline Mini SoC CLINT provides machine software and machine timer
|
||||||
the management hart. Its register layout follows the conventional SiFive
|
interrupts for the management hart. The HP profile adds an independent
|
||||||
|
two-slot instance at `0x02000000` and connects slot 1 to HP hart 1. Its register
|
||||||
|
layout follows the conventional SiFive
|
||||||
CLINT and RISC-V ACLINT-compatible offsets, while its bus-facing logic uses the
|
CLINT and RISC-V ACLINT-compatible offsets, while its bus-facing logic uses the
|
||||||
retroSoC APB4 target protocol.
|
retroSoC APB4 target protocol.
|
||||||
|
|
||||||
@@ -18,6 +20,10 @@ retroSoC APB4 target protocol.
|
|||||||
| User-core access | denied by the AXI4 interconnect access policy |
|
| User-core access | denied by the AXI4 interconnect access policy |
|
||||||
| User-core interrupt visibility | masked |
|
| User-core interrupt visibility | masked |
|
||||||
|
|
||||||
|
The HP instance uses the same 1 MHz reference timebase. OpenSBI programs hart
|
||||||
|
1 `MSIP` at `0x02000004`, `MTIMECMP` at `0x02004008`, and shared `MTIME` at
|
||||||
|
`0x0200BFF8`. The baseline management CLINT remains at `0x10020000`.
|
||||||
|
|
||||||
The timebase divider runs from the buffered external reference clock, not the
|
The timebase divider runs from the buffered external reference clock, not the
|
||||||
PLL-selected system clock. A toggle crosses into the system domain through the
|
PLL-selected system clock. A toggle crosses into the system domain through the
|
||||||
Common `edge_det` synchronizer and produces one system-clock pulse per
|
Common `edge_det` synchronizer and produces one system-clock pulse per
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# HP Interrupt and Mailbox Platform
|
||||||
|
|
||||||
|
The experimental LP/HP profile adds a 32-source, two-context PLIC at
|
||||||
|
`0x0C000000` and a bidirectional mailbox at `0x10019000`. Both are self-owned
|
||||||
|
APB4 peripherals. Their role in boot and lifecycle control is defined by
|
||||||
|
[LP/HP Architecture](../lp-hp-architecture.md).
|
||||||
|
|
||||||
|
## PLIC
|
||||||
|
|
||||||
|
Source 0 is permanently reserved. Source 1 is UART1 and source 2 is the
|
||||||
|
HP-side mailbox doorbell; sources 3 through 31 are reserved and tied low. Each
|
||||||
|
source has a three-bit priority. Context 0 drives HP machine external interrupt
|
||||||
|
and context 1 drives HP supervisor external interrupt.
|
||||||
|
|
||||||
|
| Address offset | Register | Access |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `0x000000 + 4 * source` | source priority | RW |
|
||||||
|
| `0x001000` | pending bits 31:0 | RO |
|
||||||
|
| `0x002000 + 0x80 * context` | enable bits 31:0 | RW |
|
||||||
|
| `0x200000 + 0x1000 * context` | threshold | RW |
|
||||||
|
| `0x200004 + 0x1000 * context` | claim/complete | RO/RW |
|
||||||
|
|
||||||
|
Claim returns the lowest source ID at the greatest priority strictly above the
|
||||||
|
context threshold, clears its pending bit, and marks it claimed. Writing that
|
||||||
|
nonzero ID to the same context's claim/complete register completes it. A level
|
||||||
|
source that remains asserted becomes pending again after completion. Priority
|
||||||
|
zero disables delivery. The MVP implements one 32-bit pending/enable word and
|
||||||
|
does not implement MSI, AIA, virtualization, or affinity routing.
|
||||||
|
|
||||||
|
## Mailbox
|
||||||
|
|
||||||
|
LP writes the `LP_*` bank and rings `LP_DOORBELL`, which sets the HP interrupt
|
||||||
|
state. HP writes the `HP_*` bank and rings `HP_DOORBELL`, which sets the LP
|
||||||
|
interrupt state. State is sticky W1C and is qualified by a separate enable for
|
||||||
|
each destination.
|
||||||
|
|
||||||
|
| Offset | Register | Access | Purpose |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `0x000` | `IP_VERSION` | RO | `0x00010000` |
|
||||||
|
| `0x004` | `CAPABILITY` | RO | `0x00000007` |
|
||||||
|
| `0x010` | `LP_COMMAND` | RW | LP-to-HP message code |
|
||||||
|
| `0x014` | `LP_ARG0` | RW | LP-to-HP argument |
|
||||||
|
| `0x018` | `LP_SEQUENCE` | RW | LP publication sequence; zero means none |
|
||||||
|
| `0x01C` | `LP_DOORBELL` | WO | Set HP interrupt state |
|
||||||
|
| `0x020` | `HP_EVENT` | RW | HP-to-LP event code |
|
||||||
|
| `0x024` | `HP_ARG0` | RW | HP-to-LP argument |
|
||||||
|
| `0x028` | `HP_SEQUENCE` | RW | HP publication sequence; zero means none |
|
||||||
|
| `0x02C` | `HP_DOORBELL` | WO | Set LP interrupt state |
|
||||||
|
| `0x030`/`0x034`/`0x038`/`0x03C` | LP interrupt state/enable/status/test | mixed | LP destination IRQ control |
|
||||||
|
| `0x040`/`0x044`/`0x048`/`0x04C` | HP interrupt state/enable/status/test | mixed | HP destination IRQ control |
|
||||||
|
|
||||||
|
The publication order is code, argument, sequence, memory fence, then
|
||||||
|
doorbell. `<retrosoc/hal/hp_mailbox.h>` supplies the LP-side API. The initial
|
||||||
|
Linux userspace acceptance script reports event 1, argument `0x4C4E5801`, and
|
||||||
|
sequence 1 after init; this is a bring-up verdict, not a general Linux mailbox
|
||||||
|
driver ABI.
|
||||||
|
|
||||||
|
`tests/rtl/plic_tb.sv` and `tests/rtl/hp_mailbox_tb.sv` cover register and
|
||||||
|
interrupt behavior. `tests/test_hp_boot_bundle.py` enforces the handwritten
|
||||||
|
mailbox RTL/C offset parity. Production work still requires a Linux mailbox
|
||||||
|
driver, concurrent sequence/wrap policy, malformed-message tests, lifecycle
|
||||||
|
timeouts, and fault-injection coverage.
|
||||||
+6
-2
@@ -3,7 +3,8 @@
|
|||||||
SystemCtrl is the Mini SoC control-plane peripheral at
|
SystemCtrl is the Mini SoC control-plane peripheral at
|
||||||
`0x1000B000`. It owns user-core/IP selection, the PLL request protocol,
|
`0x1000B000`. It owns user-core/IP selection, the PLL request protocol,
|
||||||
bus-fault retention, performance-counter snapshots, RTC wake observation, and
|
bus-fault retention, performance-counter snapshots, RTC wake observation, and
|
||||||
the terminal simulation result. The integration wrapper is `apb4_sysctrl`;
|
the terminal simulation result. In the HP profile it also owns HP reset release
|
||||||
|
and shared-JTAG selection. The integration wrapper is `apb4_sysctrl`;
|
||||||
the implementation is separated into `sysctrl_reg`, `sysctrl_core`, and
|
the implementation is separated into `sysctrl_reg`, `sysctrl_core`, and
|
||||||
`sysctrl_if`.
|
`sysctrl_if`.
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ offset macros.
|
|||||||
| `0x01C` | `PLL_STATUS` | RO | Active profile, valid, busy, error/error reason, safe clock, lock, and capability. |
|
| `0x01C` | `PLL_STATUS` | RO | Active profile, valid, busy, error/error reason, safe clock, lock, and capability. |
|
||||||
| `0x020` | `USER_CORE_RESET` | RW | Per-user-core active-high reset mask. All ones stops the user bus; a one-hot deassertion starts the selected core. |
|
| `0x020` | `USER_CORE_RESET` | RW | Per-user-core active-high reset mask. All ones stops the user bus; a one-hot deassertion starts the selected core. |
|
||||||
| `0x024` | `USER_CORE_STATUS` | RW1C/RO | Selected core, user-bus enabled/idle/draining, and bit 11 configuration-error W1C. |
|
| `0x024` | `USER_CORE_STATUS` | RW1C/RO | Selected core, user-bus enabled/idle/draining, and bit 11 configuration-error W1C. |
|
||||||
| `0x028` | `FAULT_MASTER` | RO | First fault master, a three-bit AXI master ID (0..4). |
|
| `0x028` | `FAULT_MASTER` | RO | First fault master, a three-bit AXI master ID (0..7); HP is 7. |
|
||||||
| `0x02C` | `FAULT_DETAIL` | RO | First raw RIB response code. |
|
| `0x02C` | `FAULT_DETAIL` | RO | First raw RIB response code. |
|
||||||
| `0x040` | `PERF_CTRL` | RW | Bit 0 enable, bit 1 clear pulse, bit 2 snapshot pulse. |
|
| `0x040` | `PERF_CTRL` | RW | Bit 0 enable, bit 1 clear pulse, bit 2 snapshot pulse. |
|
||||||
| `0x044`-`0x098` | `PERF_*_WAIT_{LO,HI}` | RO | Snapshot of management, user, central DMA, SDIO0, SDIO1, APB4, SDRAM, PSRAM, and flash wait counters. |
|
| `0x044`-`0x098` | `PERF_*_WAIT_{LO,HI}` | RO | Snapshot of management, user, central DMA, SDIO0, SDIO1, APB4, SDRAM, PSRAM, and flash wait counters. |
|
||||||
@@ -60,6 +61,9 @@ offset macros.
|
|||||||
| `0x094`/`0x098` | `PERF_SDIO1_WAIT_LO/HI` | RO | Independent SDIO1 AXI master wait snapshot. |
|
| `0x094`/`0x098` | `PERF_SDIO1_WAIT_LO/HI` | RO | Independent SDIO1 AXI master wait snapshot. |
|
||||||
| `0x084` | `TEST_STATUS` | RW-once/RO | Full-word write with bit 31 set records sticky done, bit 0 pass, and bits `[15:8]` result code. |
|
| `0x084` | `TEST_STATUS` | RW-once/RO | Full-word write with bit 31 set records sticky done, bit 0 pass, and bits `[15:8]` result code. |
|
||||||
| `0x088` | `RTC_WAKE_STATUS` | RW1C/RO | Bit 0 synchronized live wake; bit 1 sticky wake, cleared by writing one to bit 1. |
|
| `0x088` | `RTC_WAKE_STATUS` | RW1C/RO | Bit 0 synchronized live wake; bit 1 sticky wake, cleared by writing one to bit 1. |
|
||||||
|
| `0x0A4` | `HP_CTRL` | RW | Bit 0 releases HP reset when the HP profile is present. Reset value 0. |
|
||||||
|
| `0x0A8` | `HP_STATUS` | RO | Bits 0/1/2 report present, released, and reset asserted. |
|
||||||
|
| `0x0AC` | `DEBUG_SELECT` | RW | Bit 0 selects HP on shared JTAG only while HP remains in reset. Reset value 0 selects LP. |
|
||||||
|
|
||||||
The first fault remains visible until software clears pending; later faults
|
The first fault remains visible until software clears pending; later faults
|
||||||
increase only the saturating count. A hardware fault in the clear cycle
|
increase only the saturating count. A hardware fault in the clear cycle
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ fractional baud-rate generation, configurable framing, receive diagnostics,
|
|||||||
watermark and timeout interrupts, internal loopback, break generation,
|
watermark and timeout interrupts, internal loopback, break generation,
|
||||||
generic-DMA request pacing, and automatic active-low RTS/CTS flow control.
|
generic-DMA request pacing, and automatic active-low RTS/CTS flow control.
|
||||||
|
|
||||||
|
The HP profile instantiates the same UART v3 register ABI as UART1 at
|
||||||
|
`0x10018000`, with dedicated `uart1_tx`/`uart1_rx` pads and PLIC source 1.
|
||||||
|
UART1 has no DMA or RTS/CTS connection in the MVP. The external OpenSBI platform
|
||||||
|
uses UART1 as the SBI debug console, and Linux initially consumes it through
|
||||||
|
`hvc0`; a native Linux UART driver is a later delivery item.
|
||||||
|
|
||||||
## Integration
|
## Integration
|
||||||
|
|
||||||
| Property | Value |
|
| Property | Value |
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
# LP/HP Architecture and Delivery Contract
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
The committed `configs/ci/ihp130-hp.mk` profile is the executable MVP for the
|
||||||
|
retroSoC asymmetric LP/HP architecture. Hazard3 is the low-performance control
|
||||||
|
core (LP, hart 0) and a generated RV32 VexiiRiscv instance is the
|
||||||
|
high-performance Linux core (HP, hart 1). Both run from the fixed 72 MHz system
|
||||||
|
clock in this profile.
|
||||||
|
|
||||||
|
The profile proves integration, build, and lint readiness. A repeatable Linux
|
||||||
|
boot, the 2.5x performance gate, physical timing closure, and hardware
|
||||||
|
qualification remain release gates until their evidence is recorded. This MVP
|
||||||
|
must not be described as cache coherent, hot-reset safe, secure boot capable,
|
||||||
|
or power isolated.
|
||||||
|
|
||||||
|
The commercial reference analysis and product positioning are in
|
||||||
|
[SoC Family Product Positioning](soc-family-positioning.md). The implementation
|
||||||
|
reuses the most relevant patterns from heterogeneous Linux/MCU devices:
|
||||||
|
|
||||||
|
- an always-available management core owns application-core release;
|
||||||
|
- Linux receives standard CLINT/PLIC privilege interrupts and a dedicated
|
||||||
|
console;
|
||||||
|
- a mailbox is the versioned cross-core control path;
|
||||||
|
- boot artifacts and generated CPU RTL have locked, reviewable provenance;
|
||||||
|
- performance claims are machine checked from measurements, not inferred from
|
||||||
|
CPU configuration.
|
||||||
|
|
||||||
|
The MVP deliberately avoids presenting the HP core as an ordinary C0-C3 user
|
||||||
|
core. Those legacy slots remain available and software selected. HP has a
|
||||||
|
fixed hart ID, reset vector, bus master, interrupt topology, and Linux ABI.
|
||||||
|
|
||||||
|
## Compute and Memory Topology
|
||||||
|
|
||||||
|
| Property | LP | HP |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Core | Hazard3 | generated VexiiRiscv |
|
||||||
|
| Hart ID | 0 | 1 |
|
||||||
|
| ISA | RV32IM plus existing CSR/debug profile | RV32IMAFDC, S/U mode, Sv32 |
|
||||||
|
| Clock | 72 MHz | 72 MHz |
|
||||||
|
| Primary role | boot, lifecycle, diagnostics, recovery | OpenSBI and Linux |
|
||||||
|
| Reset | root reset controller | SYSCTRL release plus HP debug reset request |
|
||||||
|
| JTAG | shared pads, reset default owner | selectable only while HP is held reset |
|
||||||
|
| Main-memory view | 32-bit AXI4 | three AXI64 planes converted to one 32-bit AXI4 master |
|
||||||
|
|
||||||
|
HP instruction-cache, data-cache, and uncached MMIO ports each pass through a
|
||||||
|
64-to-32 adapter. The adapters preserve IDs and responses, split or combine
|
||||||
|
64-bit beats, honor backpressure, and track lanes across AXI burst types. The
|
||||||
|
transaction mux prioritizes uncached MMIO, then data cache, then instruction
|
||||||
|
cache and permits one transaction at a time. A Common `axi4_regslice` separates
|
||||||
|
the HP compatibility plane from the legacy system fabric.
|
||||||
|
|
||||||
|
The current system interconnect accepts up to sixteen 32-bit beats. Therefore
|
||||||
|
an HP 64-bit burst is limited to eight source beats. The generated 16 KiB,
|
||||||
|
four-way instruction and data caches use eight-beat refill/writeback geometry.
|
||||||
|
This is a compatibility architecture for the current 64 MiB SDRAM, not the
|
||||||
|
native 64-bit memory plane required for a later performance product.
|
||||||
|
|
||||||
|
There is no hardware cache coherency between LP, HP, DMA, or user cores. LP
|
||||||
|
loads HP memory before releasing HP, when HP caches are cold. Any later shared
|
||||||
|
buffer protocol must define ownership transfer and explicit cache maintenance.
|
||||||
|
Linux must not map device registers as cacheable.
|
||||||
|
|
||||||
|
## Platform ABI
|
||||||
|
|
||||||
|
| Block | Address | Purpose |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| HP ACLINT | `0x02000000` | hart 1 machine software/timer interrupts, 1 MHz timebase |
|
||||||
|
| HP PLIC | `0x0C000000` | 31 usable sources and M/S contexts |
|
||||||
|
| UART1 | `0x10018000` | dedicated HP/SBI console pads; no DMA in MVP |
|
||||||
|
| HP mailbox | `0x10019000` | command/event, argument, sequence, and dual doorbells |
|
||||||
|
| SDRAM | `0x38000000`-`0x3BFFFFFF` | shared 64 MiB Linux main memory |
|
||||||
|
|
||||||
|
PLIC source 1 is UART1 and source 2 is the HP mailbox. The LP interrupt map
|
||||||
|
retains existing assignments and adds mailbox IRQ 25 and UART1 IRQ 26. The
|
||||||
|
PLIC implements the priority, enable, pending, threshold, claim, and complete
|
||||||
|
registers needed by the Linux SiFive PLIC driver; it is not an AIA, MSI, or
|
||||||
|
virtualization interrupt controller.
|
||||||
|
|
||||||
|
SYSCTRL adds `HP_CTRL` at `0xA4`, `HP_STATUS` at `0xA8`, and `DEBUG_SELECT` at
|
||||||
|
`0xAC`. Reset defaults keep HP asserted and JTAG connected to LP. Selecting HP
|
||||||
|
debug while HP is running is rejected by hardware. The MVP release bit does
|
||||||
|
not drain transactions before reasserting reset, so software must not use it
|
||||||
|
as a safe hot-reset interface.
|
||||||
|
|
||||||
|
The mailbox RTL and `<retrosoc/hal/hp_mailbox.h>` are handwritten definitions.
|
||||||
|
`tests/test_hp_boot_bundle.py` checks their register offsets against each other.
|
||||||
|
Sequence zero means no message. Writers publish code and argument before the
|
||||||
|
nonzero sequence and doorbell; readers use the sequence as the validity token.
|
||||||
|
|
||||||
|
## Generated Core Contract
|
||||||
|
|
||||||
|
`make CONFIG=configs/ci/ihp130-hp.mk vexii-generate` runs the locked Scala
|
||||||
|
configuration in `scripts/vexiiriscv/GenerateRetroSocHp.scala`. It verifies the
|
||||||
|
source revision from `dependencies/dependencies.lock.json` and writes RTL,
|
||||||
|
filelist, source status, and SHA-256 provenance below the selected
|
||||||
|
`build/<variant>/generated/vexiiriscv/` directory. Generated VexiiRiscv RTL is
|
||||||
|
never Git tracked.
|
||||||
|
|
||||||
|
The fixed configuration enables dual issue, late ALU, full bypassing, branch
|
||||||
|
prediction, PMP, performance counters, debug triggers, RV32IMAFDC, Sv32, and
|
||||||
|
separate 16 KiB instruction/data caches. Changing any of these is a new
|
||||||
|
`HP_CONFIG` and requires a separate profile, software ABI review, synthesis,
|
||||||
|
timing, and benchmark evidence.
|
||||||
|
|
||||||
|
## Boot Flow
|
||||||
|
|
||||||
|
The `hp_boot` LP application is linked wholly into the 32 KiB on-chip SRAM so
|
||||||
|
loading OpenSBI at the SDRAM base cannot overwrite running management code.
|
||||||
|
The `hp-bundle` target combines LP firmware and the four HP artifacts in the
|
||||||
|
16 MiB boot flash:
|
||||||
|
|
||||||
|
| Artifact | Load address | Maximum |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| OpenSBI `fw_jump.bin` | `0x38000000` | 512 KiB |
|
||||||
|
| `retrosoc_hp.dtb` | `0x38080000` | 64 KiB |
|
||||||
|
| Linux `Image` | `0x38400000` | 12 MiB |
|
||||||
|
| `rootfs.cpio.gz` | `0x39000000` | 8 MiB |
|
||||||
|
|
||||||
|
The bundle starts at flash offset `0x00100000`. Its 128-byte v1 header contains
|
||||||
|
four whitelisted entries with type, flash offset, load address, byte count,
|
||||||
|
CRC32, and required flags. LP validates the header, flash and SDRAM bounds,
|
||||||
|
fixed destinations, sizes, alignment, and every payload CRC. It copies with
|
||||||
|
32-bit writes and full readback for control payloads; large payloads use full
|
||||||
|
flash CRC validation without destination rereads. It issues a memory fence
|
||||||
|
before releasing HP.
|
||||||
|
CRC detects accidental corruption; it is not authentication.
|
||||||
|
|
||||||
|
OpenSBI is built from an external repo-owned platform directory without
|
||||||
|
patching its locked source. The platform maps OpenSBI hart index 0 to hardware
|
||||||
|
hart ID 1, registers the HP ACLINT, and provides the SBI debug console through
|
||||||
|
UART1. OpenSBI starts at `0x38000000` and directly enters Linux at
|
||||||
|
`0x38400000`, passing the DTB at `0x38080000`; U-Boot is not part of the MVP.
|
||||||
|
|
||||||
|
Buildroot creates the RV32 glibc toolchain and a small initramfs. Linux starts
|
||||||
|
from `tinyconfig` and merges `app/ports/linux/linux/retrosoc_hp.config` so the
|
||||||
|
Image stays within the fixed flash budget. Its final init script prints
|
||||||
|
`retroSoC HP Linux ready` and posts mailbox event 1 with argument `0x4C4E5801`.
|
||||||
|
LP then writes the normal sticky `TEST_STATUS` pass result, giving simulation a
|
||||||
|
deterministic terminal verdict.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make setup-hp-linux
|
||||||
|
make CONFIG=configs/ci/ihp130-hp.mk hp-linux
|
||||||
|
make CONFIG=configs/ci/ihp130-hp.mk hp-bundle
|
||||||
|
make CONFIG=configs/ci/ihp130-hp.mk SIMU=VERILATOR comp sim
|
||||||
|
```
|
||||||
|
|
||||||
|
The setup flow locks VexiiRiscv, OpenSBI, Linux, and Buildroot by full Git
|
||||||
|
revision. Interrupted HP source fetches are repaired in place on retry.
|
||||||
|
|
||||||
|
## Performance and Verification
|
||||||
|
|
||||||
|
LP and HP claims use the same 72 MHz frequency and CoreMark mode. After both
|
||||||
|
machine-readable reports exist, enforce the selected requirement with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make hp-performance-check \
|
||||||
|
LP_COREMARK_REPORT=<lp-coremark.json> \
|
||||||
|
HP_COREMARK_REPORT=<hp-coremark.json>
|
||||||
|
```
|
||||||
|
|
||||||
|
The gate writes `meta/lp-hp-performance.json` and requires HP CoreMark/MHz to
|
||||||
|
be at least 2.5 times LP. An HP report must come from executed Linux, RTL
|
||||||
|
simulation, FPGA, or silicon with its provenance retained. A predicted score
|
||||||
|
is not acceptable evidence.
|
||||||
|
|
||||||
|
Current directed verification covers the AXI downsizer, 8-master interconnect,
|
||||||
|
mailbox, PLIC, topology generation, pad ring, generated-source boundary,
|
||||||
|
bundle CRC/layout, HAL/RTL offset parity, HP firmware build, RTL style, and
|
||||||
|
full-design Verilator lint. Release qualification additionally requires a
|
||||||
|
successful Linux boot log, both CoreMark reports, IHP130 synthesis/STA, and the
|
||||||
|
normal PR regression.
|
||||||
|
|
||||||
|
## Commercial Alignment Roadmap
|
||||||
|
|
||||||
|
The next phases are ordered by risk and dependency:
|
||||||
|
|
||||||
|
1. Complete repeatable Linux boot and native UART/mailbox kernel drivers;
|
||||||
|
retain boot-time and error-injection evidence.
|
||||||
|
2. Replace the serialized compatibility plane with a native burst-capable
|
||||||
|
memory path, add HP QoS/wait counters, and close the 2.5x performance gate.
|
||||||
|
3. Add lifecycle handshakes that block new HP requests, drain accepted traffic,
|
||||||
|
request Linux shutdown, apply cache maintenance, and only then reset.
|
||||||
|
4. Add clock gating, power isolation/retention controls, CDC/RDC signoff, and
|
||||||
|
measured state-transition latency and energy.
|
||||||
|
5. Add immutable boot ROM, signature verification, rollback protection, OTP
|
||||||
|
key/lifecycle state, debug authentication/disable, firewall regions, and a
|
||||||
|
documented threat model. CRC32 is then retained only for transport errors.
|
||||||
|
6. Add RAS evidence: ECC/parity coverage, watchdog escalation, bus timeout,
|
||||||
|
machine-check logging, fault injection, and recovery/reset campaigns.
|
||||||
|
7. Add production DFT, MBIST, trace, PMU event definitions, coverage closure,
|
||||||
|
software update/recovery, long-duration stress, and PVT/package signoff.
|
||||||
|
|
||||||
|
Avoid claiming a commercial big.LITTLE-style coherent cluster: this design is
|
||||||
|
asymmetric multiprocessing with independent software roles. Also avoid direct
|
||||||
|
LP reset of a running HP, shared cacheable buffers without an ownership
|
||||||
|
protocol, Linux control over root lifecycle registers, and per-PDK frequency
|
||||||
|
claims derived only from RTL simulation.
|
||||||
@@ -98,11 +98,13 @@ feature reference when Wi-Fi is included.
|
|||||||
|
|
||||||
### Status and Position
|
### Status and Position
|
||||||
|
|
||||||
retroSoC Mini is currently an open-source RISC-V microcontroller-class SoC
|
retroSoC Mini is an open-source RISC-V microcontroller-class SoC with a fixed
|
||||||
with a fixed Hazard3 management core and one software-selected user core. The
|
Hazard3 management core and one software-selected user core. The experimental
|
||||||
planned Linux-capable configuration adds a 32-bit VexiiRiscv user core. The
|
`configs/ci/ihp130-hp.mk` profile now adds a separate 32-bit VexiiRiscv Linux
|
||||||
VexiiRiscv integration and Linux boot flow are product targets, not supported
|
core without consuming the C0-C3 slots. RTL integration, a direct-Linux image
|
||||||
repository configurations yet.
|
flow, and LP boot firmware are implemented; repeatable Linux boot,
|
||||||
|
performance, synthesis, timing, and hardware evidence are still qualification
|
||||||
|
gates rather than supported product claims.
|
||||||
|
|
||||||
Mini is the price, complexity, and Linux-capability anchor for the family. It
|
Mini is the price, complexity, and Linux-capability anchor for the family. It
|
||||||
targets industrial control, protocol gateways, compact human-machine
|
targets industrial control, protocol gateways, compact human-machine
|
||||||
@@ -137,7 +139,7 @@ capabilities:
|
|||||||
- SYSCTRL controls user-core selection, reset, interrupt admission, and bus
|
- SYSCTRL controls user-core selection, reset, interrupt admission, and bus
|
||||||
admission. A stop request blocks new user transactions, drains an accepted
|
admission. A stop request blocks new user transactions, drains an accepted
|
||||||
transaction, and then asserts reset.
|
transaction, and then asserts reset.
|
||||||
- The canonical address map exposes 128 KiB of on-chip SRAM, a 32 MiB SDRAM
|
- The canonical address map exposes configurable on-chip SRAM, a 64 MiB SDRAM
|
||||||
window, and an 8 MiB PSRAM window. Address-window capacity does not guarantee
|
window, and an 8 MiB PSRAM window. Address-window capacity does not guarantee
|
||||||
that every implementation includes the corresponding physical memory.
|
that every implementation includes the corresponding physical memory.
|
||||||
- AXI4 is the active 32-bit interconnect. It supports linear one- through
|
- AXI4 is the active 32-bit interconnect. It supports linear one- through
|
||||||
@@ -147,12 +149,16 @@ capabilities:
|
|||||||
scalar engine accesses. They do not yet combine a burst into a native SDRAM,
|
scalar engine accesses. They do not yet combine a burst into a native SDRAM,
|
||||||
PSRAM, flash, or SPI-SD physical transaction.
|
PSRAM, flash, or SPI-SD physical transaction.
|
||||||
|
|
||||||
|
The experimental HP profile adds the fixed hart 1 core, a compatibility AXI
|
||||||
|
plane, HP ACLINT/PLIC, UART1, mailbox, reset release, and shared-JTAG selection.
|
||||||
|
Its detailed executable contract is [LP/HP Architecture](lp-hp-architecture.md).
|
||||||
|
|
||||||
The generated address map, user-extension map,
|
The generated address map, user-extension map,
|
||||||
[AXI4 contract](axi4-interconnect.md), and retained
|
[AXI4 contract](axi4-interconnect.md), and retained
|
||||||
[RIB protocol contract](rib-interconnect.md) remain the integration references
|
[RIB protocol contract](rib-interconnect.md) remain the integration references
|
||||||
for the implemented baseline.
|
for the implemented baseline.
|
||||||
|
|
||||||
### Planned Linux Configuration
|
### Experimental Linux Configuration
|
||||||
|
|
||||||
The Linux configuration keeps Hazard3 as the always-available trusted
|
The Linux configuration keeps Hazard3 as the always-available trusted
|
||||||
management core and adds VexiiRiscv as the application processor. Hazard3 is
|
management core and adds VexiiRiscv as the application processor. Hazard3 is
|
||||||
@@ -162,7 +168,7 @@ able to reconfigure the management-core lifecycle controls.
|
|||||||
|
|
||||||
The initial VexiiRiscv configuration should provide:
|
The initial VexiiRiscv configuration should provide:
|
||||||
|
|
||||||
- RV32IMAC with machine, supervisor, and user modes.
|
- RV32IMAFDC with machine, supervisor, and user modes.
|
||||||
- Sv32 virtual memory, hardware page-table walking, and the privileged CSRs
|
- Sv32 virtual memory, hardware page-table walking, and the privileged CSRs
|
||||||
required by the supported Linux kernel.
|
required by the supported Linux kernel.
|
||||||
- LR/SC atomics, separate 16 KiB instruction and data caches, and uncached MMIO
|
- LR/SC atomics, separate 16 KiB instruction and data caches, and uncached MMIO
|
||||||
@@ -172,13 +178,15 @@ The initial VexiiRiscv configuration should provide:
|
|||||||
- A documented DMA cache-maintenance contract unless the memory system supplies
|
- A documented DMA cache-maintenance contract unless the memory system supplies
|
||||||
hardware coherency.
|
hardware coherency.
|
||||||
|
|
||||||
The management firmware initializes external memory, verifies and places the
|
The implemented management firmware waits for external memory, validates and
|
||||||
OpenSBI firmware, device tree, kernel, and initial filesystem, programs the
|
places the OpenSBI firmware, device tree, kernel, and initial filesystem at
|
||||||
VexiiRiscv entry point, and then enables its bus access and releases reset. A
|
fixed addresses, and then releases the fixed VexiiRiscv reset vector. The
|
||||||
normal stop first requests Linux shutdown through a mailbox. After Linux
|
bundle uses CRC32 for accidental-corruption detection, not secure boot. A
|
||||||
acknowledges and flushes persistent data, the management core disables new bus
|
future normal stop must first request Linux shutdown through the mailbox. After
|
||||||
transactions, drains the final accepted transaction, and asserts reset. A
|
Linux acknowledges and flushes persistent data, the management core must
|
||||||
bounded timeout permits fault recovery through forced isolation and reset.
|
disable new bus transactions, drain the final accepted transaction, and assert
|
||||||
|
reset. A bounded timeout permits fault recovery through forced isolation and
|
||||||
|
reset.
|
||||||
|
|
||||||
### Product Targets
|
### Product Targets
|
||||||
|
|
||||||
@@ -194,8 +202,9 @@ implemented or cross-PDK guarantee:
|
|||||||
| Boot storage | SPI NAND or qualified SDIO path | SDIO/eMMC plus recovery image |
|
| Boot storage | SPI NAND or qualified SDIO path | SDIO/eMMC plus recovery image |
|
||||||
| Linux platform devices | UART, timer, interrupt controller, storage | Ethernet or USB selected by the product profile |
|
| Linux platform devices | UART, timer, interrupt controller, storage | Ethernet or USB selected by the product profile |
|
||||||
|
|
||||||
Meeting these targets requires enlarging the current 32 MiB SDRAM address
|
The current 64 MiB SDRAM window meets the minimum address-capacity target, but
|
||||||
window and replacing the scalar external-memory bottleneck. A dedicated memory
|
meeting the bandwidth target requires replacing the scalar external-memory
|
||||||
|
bottleneck. A dedicated memory
|
||||||
fabric may evolve independently while APB4 and APB remain the stable peripheral
|
fabric may evolve independently while APB4 and APB remain the stable peripheral
|
||||||
register interfaces. Frequency claims must be qualified separately for each
|
register interfaces. Frequency claims must be qualified separately for each
|
||||||
PDK and physical implementation.
|
PDK and physical implementation.
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ package locations remain in the board `.xdc` file.
|
|||||||
The dedicated SDIO1 pads are intentionally left unbound by the FPGA profile
|
The dedicated SDIO1 pads are intentionally left unbound by the FPGA profile
|
||||||
until a board package location and 3.3 V I/O-bank assignment are approved;
|
until a board package location and 3.3 V I/O-bank assignment are approved;
|
||||||
the existing LVCMOS18 constraints do not establish SDIO electrical support.
|
the existing LVCMOS18 constraints do not establish SDIO electrical support.
|
||||||
|
The new UART1 HP-console ports are likewise left unbound until two StarrySky
|
||||||
|
package pins and their I/O voltage are reviewed. The ASIC profile still owns
|
||||||
|
dedicated UART1 pads; this FPGA constraint gap is intentional and must be
|
||||||
|
resolved before generating an HP board bitstream.
|
||||||
|
|
||||||
FPGA constraints are board-specific implementation inputs, not generic ASIC
|
FPGA constraints are board-specific implementation inputs, not generic ASIC
|
||||||
RTL. Validate changes with the relevant FPGA tool flow and hardware target; do
|
RTL. Validate changes with the relevant FPGA tool flow and hardware target; do
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ module retrosoc_top (
|
|||||||
inout gpio_io30,
|
inout gpio_io30,
|
||||||
output uart0_tx_o,
|
output uart0_tx_o,
|
||||||
inout uart0_rx_i,
|
inout uart0_rx_i,
|
||||||
|
output uart1_tx_o,
|
||||||
|
inout uart1_rx_i,
|
||||||
output xpi_sck_o,
|
output xpi_sck_o,
|
||||||
output xpi_nss0_o,
|
output xpi_nss0_o,
|
||||||
inout xpi_dat0_io,
|
inout xpi_dat0_io,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ make CONFIG=configs/ci/ihp130.mk librelane-core-package
|
|||||||
make CONFIG=configs/ci/ihp130.mk librelane-package
|
make CONFIG=configs/ci/ihp130.mk librelane-package
|
||||||
```
|
```
|
||||||
|
|
||||||
The chip target places all 109 signal pads, 80 core/IO power and ground pads,
|
The chip target places all 111 signal pads, 80 core/IO power and ground pads,
|
||||||
four corners, I/O fillers, and 70 um bondpads. It is a bare-die plan, not a
|
four corners, I/O fillers, and 70 um bondpads. It is a bare-die plan, not a
|
||||||
QFN/BGA package definition. The SDC constrains the external clock at 72 MHz;
|
QFN/BGA package definition. The SDC constrains the external clock at 72 MHz;
|
||||||
mid-PnR timing report passes are skipped because LibreLane 3.0.5 emits 1000
|
mid-PnR timing report passes are skipped because LibreLane 3.0.5 emits 1000
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from scripts.setup_helpers import atomic_write # noqa: E402
|
|||||||
|
|
||||||
EXPECTED_LIBRELANE_VERSION = "LibreLane v3.0.5"
|
EXPECTED_LIBRELANE_VERSION = "LibreLane v3.0.5"
|
||||||
EXPECTED_OPENSTA_VERSION = "3.0.0"
|
EXPECTED_OPENSTA_VERSION = "3.0.0"
|
||||||
EXPECTED_SIGNAL_PADS = 109
|
EXPECTED_SIGNAL_PADS = 111
|
||||||
|
|
||||||
|
|
||||||
def command_output(command: list[str]) -> str:
|
def command_output(command: list[str]) -> str:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from scripts.setup_helpers import atomic_write # noqa: E402
|
|||||||
|
|
||||||
|
|
||||||
SIDE_ORDER = ("south", "east", "north", "west")
|
SIDE_ORDER = ("south", "east", "north", "west")
|
||||||
EXPECTED_SIGNAL_PADS = 109
|
EXPECTED_SIGNAL_PADS = 111
|
||||||
CLOCK_PORTS = (
|
CLOCK_PORTS = (
|
||||||
"extclk_i_pad",
|
"extclk_i_pad",
|
||||||
"audclk_i_pad",
|
"audclk_i_pad",
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ notices. `filelist/` selects PDK-specific RTL sources; `tech/` contains
|
|||||||
technology wrappers. Respect managed upstream boundaries and use setup helpers
|
technology wrappers. Respect managed upstream boundaries and use setup helpers
|
||||||
rather than editing generated MPW output.
|
rather than editing generated MPW output.
|
||||||
|
|
||||||
|
The optional IHP130 LP/HP profile integrates VexiiRiscv through self-owned
|
||||||
|
wrappers, a 64-to-32 compatibility plane, HP ACLINT/PLIC, mailbox, UART1, and
|
||||||
|
SYSCTRL lifecycle signals. The generated CPU Verilog lives only below
|
||||||
|
`build/<variant>/generated/vexiiriscv/` and is an external lint boundary. See
|
||||||
|
[LP/HP Architecture](../docs/lp-hp-architecture.md).
|
||||||
|
|
||||||
RTL changes require an affected firmware build and simulation. Use
|
RTL changes require an affected firmware build and simulation. Use
|
||||||
`make regress-pr` or `make regress-nightly` for supported regression coverage;
|
`make regress-pr` or `make regress-nightly` for supported regression coverage;
|
||||||
see [Engineering Workflow](../docs/engineering.md) for results and artifacts.
|
see [Engineering Workflow](../docs/engineering.md) for results and artifacts.
|
||||||
|
|||||||
@@ -55,5 +55,6 @@ module apb4_clint #(
|
|||||||
|
|
||||||
assign clint.software_irq_o = s_msip;
|
assign clint.software_irq_o = s_msip;
|
||||||
assign clint.timer_irq_o = s_timer_irq;
|
assign clint.timer_irq_o = s_timer_irq;
|
||||||
|
assign clint.mtime_o = s_mtime;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||||
|
// SPDX-License-Identifier: MulanPSL-2.0
|
||||||
|
|
||||||
|
`include "hp_mailbox_define.svh"
|
||||||
|
|
||||||
|
module apb4_hp_mailbox (
|
||||||
|
// verilog_format: off -- preserve APB and interrupt alignment
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_n_i,
|
||||||
|
apb4_if.slave apb4,
|
||||||
|
output logic lp_irq_o,
|
||||||
|
output logic hp_irq_o
|
||||||
|
// verilog_format: on
|
||||||
|
);
|
||||||
|
localparam logic [31:0] IpVersion = 32'h0001_0000;
|
||||||
|
localparam logic [31:0] Capability = 32'h0000_0007;
|
||||||
|
|
||||||
|
logic s_req_accept;
|
||||||
|
logic s_write;
|
||||||
|
logic [11:0] s_offset;
|
||||||
|
logic s_access_err;
|
||||||
|
logic s_ready_d, s_ready_q;
|
||||||
|
logic s_resp_err_d, s_resp_err_q;
|
||||||
|
logic [31:0] s_rdata_d, s_rdata_q;
|
||||||
|
logic [31:0] s_lp_cmd_d, s_lp_cmd_q;
|
||||||
|
logic [31:0] s_lp_arg0_d, s_lp_arg0_q;
|
||||||
|
logic [31:0] s_lp_sequence_d, s_lp_sequence_q;
|
||||||
|
logic [31:0] s_hp_event_d, s_hp_event_q;
|
||||||
|
logic [31:0] s_hp_arg0_d, s_hp_arg0_q;
|
||||||
|
logic [31:0] s_hp_sequence_d, s_hp_sequence_q;
|
||||||
|
logic s_lp_intr_state_d, s_lp_intr_state_q;
|
||||||
|
logic s_lp_intr_en_d, s_lp_intr_en_q;
|
||||||
|
logic s_hp_intr_state_d, s_hp_intr_state_q;
|
||||||
|
logic s_hp_intr_en_d, s_hp_intr_en_q;
|
||||||
|
|
||||||
|
function automatic logic [31:0] merge_wstrb(input logic [31:0] current, input logic [31:0] value,
|
||||||
|
input logic [3:0] strobe);
|
||||||
|
logic [31:0] merged;
|
||||||
|
begin
|
||||||
|
merged = current;
|
||||||
|
for (int byte_index = 0; byte_index < 4; byte_index++) begin
|
||||||
|
if (strobe[byte_index]) merged[byte_index*8+:8] = value[byte_index*8+:8];
|
||||||
|
end
|
||||||
|
return merged;
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
assign s_req_accept = apb4.psel && apb4.penable && !s_ready_q;
|
||||||
|
assign s_write = apb4.pwrite;
|
||||||
|
assign s_offset = apb4.paddr[11:0];
|
||||||
|
assign apb4.pready = s_ready_q;
|
||||||
|
assign apb4.pslverr = s_resp_err_q;
|
||||||
|
assign apb4.prdata = s_rdata_q;
|
||||||
|
assign lp_irq_o = s_lp_intr_state_q && s_lp_intr_en_q;
|
||||||
|
assign hp_irq_o = s_hp_intr_state_q && s_hp_intr_en_q;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_access_err = 1'b0;
|
||||||
|
s_rdata_d = '0;
|
||||||
|
unique case (s_offset)
|
||||||
|
`APB4_HP_MAILBOX__IP_VERSION: s_rdata_d = IpVersion;
|
||||||
|
`APB4_HP_MAILBOX__CAPABILITY: s_rdata_d = Capability;
|
||||||
|
`APB4_HP_MAILBOX__LP_COMMAND: s_rdata_d = s_lp_cmd_q;
|
||||||
|
`APB4_HP_MAILBOX__LP_ARG0: s_rdata_d = s_lp_arg0_q;
|
||||||
|
`APB4_HP_MAILBOX__LP_SEQUENCE: s_rdata_d = s_lp_sequence_q;
|
||||||
|
`APB4_HP_MAILBOX__HP_EVENT: s_rdata_d = s_hp_event_q;
|
||||||
|
`APB4_HP_MAILBOX__HP_ARG0: s_rdata_d = s_hp_arg0_q;
|
||||||
|
`APB4_HP_MAILBOX__HP_SEQUENCE: s_rdata_d = s_hp_sequence_q;
|
||||||
|
`APB4_HP_MAILBOX__LP_INTR_STATE: s_rdata_d = {31'd0, s_lp_intr_state_q};
|
||||||
|
`APB4_HP_MAILBOX__LP_INTR_ENABLE: s_rdata_d = {31'd0, s_lp_intr_en_q};
|
||||||
|
`APB4_HP_MAILBOX__LP_INTR_STATUS: s_rdata_d = {31'd0, lp_irq_o};
|
||||||
|
`APB4_HP_MAILBOX__HP_INTR_STATE: s_rdata_d = {31'd0, s_hp_intr_state_q};
|
||||||
|
`APB4_HP_MAILBOX__HP_INTR_ENABLE: s_rdata_d = {31'd0, s_hp_intr_en_q};
|
||||||
|
`APB4_HP_MAILBOX__HP_INTR_STATUS: s_rdata_d = {31'd0, hp_irq_o};
|
||||||
|
`APB4_HP_MAILBOX__LP_DOORBELL, `APB4_HP_MAILBOX__HP_DOORBELL,
|
||||||
|
`APB4_HP_MAILBOX__LP_INTR_TEST, `APB4_HP_MAILBOX__HP_INTR_TEST: begin
|
||||||
|
s_access_err = !s_write;
|
||||||
|
end
|
||||||
|
default: s_access_err = 1'b1;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_lp_cmd_d = s_lp_cmd_q;
|
||||||
|
s_lp_arg0_d = s_lp_arg0_q;
|
||||||
|
s_lp_sequence_d = s_lp_sequence_q;
|
||||||
|
s_hp_event_d = s_hp_event_q;
|
||||||
|
s_hp_arg0_d = s_hp_arg0_q;
|
||||||
|
s_hp_sequence_d = s_hp_sequence_q;
|
||||||
|
s_lp_intr_state_d = s_lp_intr_state_q;
|
||||||
|
s_lp_intr_en_d = s_lp_intr_en_q;
|
||||||
|
s_hp_intr_state_d = s_hp_intr_state_q;
|
||||||
|
s_hp_intr_en_d = s_hp_intr_en_q;
|
||||||
|
if (s_req_accept && s_write && !s_access_err) begin
|
||||||
|
unique case (s_offset)
|
||||||
|
`APB4_HP_MAILBOX__LP_COMMAND: s_lp_cmd_d = merge_wstrb(s_lp_cmd_q, apb4.pwdata, apb4.pstrb);
|
||||||
|
`APB4_HP_MAILBOX__LP_ARG0: s_lp_arg0_d = merge_wstrb(s_lp_arg0_q, apb4.pwdata, apb4.pstrb);
|
||||||
|
`APB4_HP_MAILBOX__LP_SEQUENCE:
|
||||||
|
s_lp_sequence_d = merge_wstrb(s_lp_sequence_q, apb4.pwdata, apb4.pstrb);
|
||||||
|
`APB4_HP_MAILBOX__LP_DOORBELL: s_hp_intr_state_d = 1'b1;
|
||||||
|
`APB4_HP_MAILBOX__HP_EVENT:
|
||||||
|
s_hp_event_d = merge_wstrb(s_hp_event_q, apb4.pwdata, apb4.pstrb);
|
||||||
|
`APB4_HP_MAILBOX__HP_ARG0: s_hp_arg0_d = merge_wstrb(s_hp_arg0_q, apb4.pwdata, apb4.pstrb);
|
||||||
|
`APB4_HP_MAILBOX__HP_SEQUENCE:
|
||||||
|
s_hp_sequence_d = merge_wstrb(s_hp_sequence_q, apb4.pwdata, apb4.pstrb);
|
||||||
|
`APB4_HP_MAILBOX__HP_DOORBELL: s_lp_intr_state_d = 1'b1;
|
||||||
|
`APB4_HP_MAILBOX__LP_INTR_STATE:
|
||||||
|
if (apb4.pstrb[0] && apb4.pwdata[0]) s_lp_intr_state_d = 1'b0;
|
||||||
|
`APB4_HP_MAILBOX__LP_INTR_ENABLE: if (apb4.pstrb[0]) s_lp_intr_en_d = apb4.pwdata[0];
|
||||||
|
`APB4_HP_MAILBOX__LP_INTR_TEST:
|
||||||
|
if (apb4.pstrb[0] && apb4.pwdata[0]) s_lp_intr_state_d = 1'b1;
|
||||||
|
`APB4_HP_MAILBOX__HP_INTR_STATE:
|
||||||
|
if (apb4.pstrb[0] && apb4.pwdata[0]) s_hp_intr_state_d = 1'b0;
|
||||||
|
`APB4_HP_MAILBOX__HP_INTR_ENABLE: if (apb4.pstrb[0]) s_hp_intr_en_d = apb4.pwdata[0];
|
||||||
|
`APB4_HP_MAILBOX__HP_INTR_TEST:
|
||||||
|
if (apb4.pstrb[0] && apb4.pwdata[0]) s_hp_intr_state_d = 1'b1;
|
||||||
|
default: begin
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign s_ready_d = s_req_accept;
|
||||||
|
assign s_resp_err_d = s_req_accept && s_access_err;
|
||||||
|
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_ready_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_ready_d),
|
||||||
|
.dat_o (s_ready_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_resp_err_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_resp_err_d),
|
||||||
|
.dat_o (s_resp_err_q)
|
||||||
|
);
|
||||||
|
dffer #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_rdata_dffer (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.en_i (s_req_accept && !s_write),
|
||||||
|
.dat_i (s_rdata_d),
|
||||||
|
.dat_o (s_rdata_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_lp_command_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_lp_cmd_d),
|
||||||
|
.dat_o (s_lp_cmd_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_lp_arg0_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_lp_arg0_d),
|
||||||
|
.dat_o (s_lp_arg0_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_lp_sequence_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_lp_sequence_d),
|
||||||
|
.dat_o (s_lp_sequence_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_hp_event_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_hp_event_d),
|
||||||
|
.dat_o (s_hp_event_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_hp_arg0_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_hp_arg0_d),
|
||||||
|
.dat_o (s_hp_arg0_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_hp_sequence_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_hp_sequence_d),
|
||||||
|
.dat_o (s_hp_sequence_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_lp_intr_state_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_lp_intr_state_d),
|
||||||
|
.dat_o (s_lp_intr_state_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_lp_intr_enable_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_lp_intr_en_d),
|
||||||
|
.dat_o (s_lp_intr_en_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_hp_intr_state_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_hp_intr_state_d),
|
||||||
|
.dat_o (s_hp_intr_state_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_hp_intr_enable_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_hp_intr_en_d),
|
||||||
|
.dat_o (s_hp_intr_en_q)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||||
|
// SPDX-License-Identifier: MulanPSL-2.0
|
||||||
|
|
||||||
|
module apb4_plic #(
|
||||||
|
parameter int NumSources = 32,
|
||||||
|
parameter int NumContexts = 2
|
||||||
|
) (
|
||||||
|
// verilog_format: off -- preserve APB and interrupt alignment
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_n_i,
|
||||||
|
input logic [NumSources-1:0] source_i,
|
||||||
|
apb4_if.slave apb4,
|
||||||
|
output logic [NumContexts-1:0] context_irq_o
|
||||||
|
// verilog_format: on
|
||||||
|
);
|
||||||
|
localparam int SourceWidth = $clog2(NumSources);
|
||||||
|
|
||||||
|
logic s_req_accept;
|
||||||
|
logic s_write;
|
||||||
|
logic [25:0] s_offset;
|
||||||
|
logic s_ready_d, s_ready_q;
|
||||||
|
logic s_resp_err_d, s_resp_err_q;
|
||||||
|
logic [31:0] s_rdata_d, s_rdata_q;
|
||||||
|
logic [2:0] s_priority_d[NumSources], s_priority_q[NumSources];
|
||||||
|
logic [NumSources-1:0] s_pending_d, s_pending_q;
|
||||||
|
logic [NumSources-1:0] s_claimed_d, s_claimed_q;
|
||||||
|
logic [NumSources-1:0] s_en_d[NumContexts], s_en_q[NumContexts];
|
||||||
|
logic [2:0] s_threshold_d[NumContexts], s_threshold_q[NumContexts];
|
||||||
|
logic [SourceWidth-1:0] s_claim_id [NumContexts];
|
||||||
|
logic [ 2:0] s_claim_priority[NumContexts];
|
||||||
|
logic s_priority_sel;
|
||||||
|
logic s_pending_sel;
|
||||||
|
logic s_en_sel [NumContexts];
|
||||||
|
logic s_threshold_sel [NumContexts];
|
||||||
|
logic s_claim_sel [NumContexts];
|
||||||
|
logic [SourceWidth-1:0] s_priority_src;
|
||||||
|
|
||||||
|
assign s_req_accept = apb4.psel && apb4.penable && !s_ready_q;
|
||||||
|
assign s_write = apb4.pwrite;
|
||||||
|
assign s_offset = apb4.paddr[25:0];
|
||||||
|
assign s_priority_sel = (s_offset < 26'h0001000) && (s_offset[1:0] == 2'b00);
|
||||||
|
assign s_priority_src = s_offset[SourceWidth+1:2];
|
||||||
|
assign s_pending_sel = s_offset == 26'h0001000;
|
||||||
|
for (genvar ctx = 0; ctx < NumContexts; ctx++) begin : gen_select
|
||||||
|
assign s_en_sel[ctx] = s_offset == (26'h0002000 + 26'(ctx * 128));
|
||||||
|
assign s_threshold_sel[ctx] = s_offset == (26'h0200000 + 26'(ctx * 4096));
|
||||||
|
assign s_claim_sel[ctx] = s_offset == (26'h0200004 + 26'(ctx * 4096));
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
for (int ctx = 0; ctx < NumContexts; ctx++) begin
|
||||||
|
s_claim_id[ctx] = '0;
|
||||||
|
s_claim_priority[ctx] = '0;
|
||||||
|
for (int source = 1; source < NumSources; source++) begin
|
||||||
|
if (s_pending_q[source] && s_en_q[ctx][source] &&
|
||||||
|
(s_priority_q[source] > s_threshold_q[ctx]) &&
|
||||||
|
((s_priority_q[source] > s_claim_priority[ctx]) ||
|
||||||
|
((s_priority_q[source] == s_claim_priority[ctx]) &&
|
||||||
|
((s_claim_id[ctx] == '0) || (source < s_claim_id[ctx]))))) begin
|
||||||
|
s_claim_id[ctx] = SourceWidth'(source);
|
||||||
|
s_claim_priority[ctx] = s_priority_q[source];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context_irq_o[ctx] = s_claim_id[ctx] != '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_rdata_d = '0;
|
||||||
|
s_resp_err_d = 1'b0;
|
||||||
|
if (s_priority_sel && ({1'b0, s_priority_src} < (SourceWidth + 1)'(NumSources))) begin
|
||||||
|
s_rdata_d = {29'd0, s_priority_q[s_priority_src]};
|
||||||
|
end else if (s_pending_sel) begin
|
||||||
|
s_rdata_d = 32'(s_pending_q);
|
||||||
|
end else begin
|
||||||
|
s_resp_err_d = 1'b1;
|
||||||
|
for (int ctx = 0; ctx < NumContexts; ctx++) begin
|
||||||
|
if (s_en_sel[ctx]) begin
|
||||||
|
s_rdata_d = 32'(s_en_q[ctx]);
|
||||||
|
s_resp_err_d = 1'b0;
|
||||||
|
end
|
||||||
|
if (s_threshold_sel[ctx]) begin
|
||||||
|
s_rdata_d = {29'd0, s_threshold_q[ctx]};
|
||||||
|
s_resp_err_d = 1'b0;
|
||||||
|
end
|
||||||
|
if (s_claim_sel[ctx]) begin
|
||||||
|
s_rdata_d = 32'(s_claim_id[ctx]);
|
||||||
|
s_resp_err_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (s_write && s_pending_sel) s_resp_err_d = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
for (int source = 0; source < NumSources; source++) begin
|
||||||
|
s_priority_d[source] = s_priority_q[source];
|
||||||
|
end
|
||||||
|
for (int ctx = 0; ctx < NumContexts; ctx++) begin
|
||||||
|
s_en_d[ctx] = s_en_q[ctx];
|
||||||
|
s_threshold_d[ctx] = s_threshold_q[ctx];
|
||||||
|
end
|
||||||
|
s_pending_d = s_pending_q;
|
||||||
|
s_claimed_d = s_claimed_q;
|
||||||
|
s_pending_d[0] = 1'b0;
|
||||||
|
s_claimed_d[0] = 1'b0;
|
||||||
|
for (int source = 1; source < NumSources; source++) begin
|
||||||
|
if (source_i[source] && !s_claimed_q[source]) s_pending_d[source] = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (s_req_accept && s_write && !s_resp_err_d) begin
|
||||||
|
if (s_priority_sel && (s_priority_src != '0) && apb4.pstrb[0]) begin
|
||||||
|
s_priority_d[s_priority_src] = apb4.pwdata[2:0];
|
||||||
|
end
|
||||||
|
for (int ctx = 0; ctx < NumContexts; ctx++) begin
|
||||||
|
if (s_en_sel[ctx]) begin
|
||||||
|
for (int byte_index = 0; byte_index < 4; byte_index++) begin
|
||||||
|
if (apb4.pstrb[byte_index]) begin
|
||||||
|
s_en_d[ctx][byte_index*8+:8] = apb4.pwdata[byte_index*8+:8];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
s_en_d[ctx][0] = 1'b0;
|
||||||
|
end
|
||||||
|
if (s_threshold_sel[ctx] && apb4.pstrb[0]) begin
|
||||||
|
s_threshold_d[ctx] = apb4.pwdata[2:0];
|
||||||
|
end
|
||||||
|
if (s_claim_sel[ctx] && (apb4.pwdata[SourceWidth-1:0] != '0) &&
|
||||||
|
({1'b0, apb4.pwdata[SourceWidth-1:0]} < (SourceWidth + 1)'(NumSources))) begin
|
||||||
|
s_claimed_d[apb4.pwdata[SourceWidth-1:0]] = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (s_req_accept && !s_write) begin
|
||||||
|
for (int ctx = 0; ctx < NumContexts; ctx++) begin
|
||||||
|
if (s_claim_sel[ctx] && (s_claim_id[ctx] != '0)) begin
|
||||||
|
s_pending_d[s_claim_id[ctx]] = 1'b0;
|
||||||
|
s_claimed_d[s_claim_id[ctx]] = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign s_ready_d = s_req_accept;
|
||||||
|
assign apb4.pready = s_ready_q;
|
||||||
|
assign apb4.pslverr = s_resp_err_q;
|
||||||
|
assign apb4.prdata = s_rdata_q;
|
||||||
|
|
||||||
|
for (genvar source = 0; source < NumSources; source++) begin : gen_priority
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(3)
|
||||||
|
) u_priority_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_priority_d[source]),
|
||||||
|
.dat_o (s_priority_q[source])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
for (genvar ctx = 0; ctx < NumContexts; ctx++) begin : gen_context
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(NumSources)
|
||||||
|
) u_enable_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_en_d[ctx]),
|
||||||
|
.dat_o (s_en_q[ctx])
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(3)
|
||||||
|
) u_threshold_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_threshold_d[ctx]),
|
||||||
|
.dat_o (s_threshold_q[ctx])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(NumSources)
|
||||||
|
) u_pending_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_pending_d),
|
||||||
|
.dat_o (s_pending_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(NumSources)
|
||||||
|
) u_claimed_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_claimed_d),
|
||||||
|
.dat_o (s_claimed_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_ready_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_ready_d),
|
||||||
|
.dat_o (s_ready_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_resp_err_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_req_accept && s_resp_err_d),
|
||||||
|
.dat_o (s_resp_err_q)
|
||||||
|
);
|
||||||
|
dffer #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_rdata_dffer (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.en_i (s_req_accept && !s_write),
|
||||||
|
.dat_i (s_rdata_d),
|
||||||
|
.dat_o (s_rdata_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
`ifndef SYNTHESIS
|
||||||
|
initial begin
|
||||||
|
if ((NumSources != 32) || (NumContexts != 2)) begin
|
||||||
|
$fatal(1, "apb4_plic: Mini HP profile requires 32 sources and two contexts");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
`endif
|
||||||
|
endmodule
|
||||||
@@ -13,6 +13,7 @@ interface clint_if #(
|
|||||||
) ();
|
) ();
|
||||||
logic [HartNum-1:0] timer_irq_o;
|
logic [HartNum-1:0] timer_irq_o;
|
||||||
logic [HartNum-1:0] software_irq_o;
|
logic [HartNum-1:0] software_irq_o;
|
||||||
|
logic [ 63:0] mtime_o;
|
||||||
|
|
||||||
modport dut(output timer_irq_o, output software_irq_o);
|
modport dut(output timer_irq_o, output software_irq_o, output mtime_o);
|
||||||
endinterface
|
endinterface
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
`ifndef RETROSOC_HP_MAILBOX_DEFINE_SVH
|
||||||
|
`define RETROSOC_HP_MAILBOX_DEFINE_SVH
|
||||||
|
|
||||||
|
// verilog_format: off -- preserve software-visible register alignment
|
||||||
|
`define APB4_HP_MAILBOX__IP_VERSION 12'h000
|
||||||
|
`define APB4_HP_MAILBOX__CAPABILITY 12'h004
|
||||||
|
`define APB4_HP_MAILBOX__LP_COMMAND 12'h010
|
||||||
|
`define APB4_HP_MAILBOX__LP_ARG0 12'h014
|
||||||
|
`define APB4_HP_MAILBOX__LP_SEQUENCE 12'h018
|
||||||
|
`define APB4_HP_MAILBOX__LP_DOORBELL 12'h01C
|
||||||
|
`define APB4_HP_MAILBOX__HP_EVENT 12'h020
|
||||||
|
`define APB4_HP_MAILBOX__HP_ARG0 12'h024
|
||||||
|
`define APB4_HP_MAILBOX__HP_SEQUENCE 12'h028
|
||||||
|
`define APB4_HP_MAILBOX__HP_DOORBELL 12'h02C
|
||||||
|
`define APB4_HP_MAILBOX__LP_INTR_STATE 12'h030
|
||||||
|
`define APB4_HP_MAILBOX__LP_INTR_ENABLE 12'h034
|
||||||
|
`define APB4_HP_MAILBOX__LP_INTR_STATUS 12'h038
|
||||||
|
`define APB4_HP_MAILBOX__LP_INTR_TEST 12'h03C
|
||||||
|
`define APB4_HP_MAILBOX__HP_INTR_STATE 12'h040
|
||||||
|
`define APB4_HP_MAILBOX__HP_INTR_ENABLE 12'h044
|
||||||
|
`define APB4_HP_MAILBOX__HP_INTR_STATUS 12'h048
|
||||||
|
`define APB4_HP_MAILBOX__HP_INTR_TEST 12'h04C
|
||||||
|
// verilog_format: on
|
||||||
|
|
||||||
|
`endif
|
||||||
|
|
||||||
@@ -85,6 +85,9 @@ module sysctrl_core (
|
|||||||
sysctrl_offset_t'(`APB4_SYSCTRL__PERF_FLASH_WAIT_HI);
|
sysctrl_offset_t'(`APB4_SYSCTRL__PERF_FLASH_WAIT_HI);
|
||||||
localparam sysctrl_offset_t TestStatus = sysctrl_offset_t'(`APB4_SYSCTRL__TEST_STATUS);
|
localparam sysctrl_offset_t TestStatus = sysctrl_offset_t'(`APB4_SYSCTRL__TEST_STATUS);
|
||||||
localparam sysctrl_offset_t RtcWakeStatus = sysctrl_offset_t'(`APB4_SYSCTRL__RTC_WAKE_STATUS);
|
localparam sysctrl_offset_t RtcWakeStatus = sysctrl_offset_t'(`APB4_SYSCTRL__RTC_WAKE_STATUS);
|
||||||
|
localparam sysctrl_offset_t HpCtrl = sysctrl_offset_t'(`APB4_SYSCTRL__HP_CTRL);
|
||||||
|
localparam sysctrl_offset_t HpStatus = sysctrl_offset_t'(`APB4_SYSCTRL__HP_STATUS);
|
||||||
|
localparam sysctrl_offset_t DebugSelect = sysctrl_offset_t'(`APB4_SYSCTRL__DEBUG_SELECT);
|
||||||
|
|
||||||
logic [`USER_CORESEL_WIDTH-1:0] s_sysctrl_coresel_d, s_sysctrl_coresel_q;
|
logic [`USER_CORESEL_WIDTH-1:0] s_sysctrl_coresel_d, s_sysctrl_coresel_q;
|
||||||
logic [`USER_CORE_COUNT-1:0] s_user_reset_d, s_user_reset_q;
|
logic [`USER_CORE_COUNT-1:0] s_user_reset_d, s_user_reset_q;
|
||||||
@@ -124,6 +127,8 @@ module sysctrl_core (
|
|||||||
logic s_test_pass_d, s_test_pass_q;
|
logic s_test_pass_d, s_test_pass_q;
|
||||||
logic [7:0] s_test_code_d, s_test_code_q;
|
logic [7:0] s_test_code_d, s_test_code_q;
|
||||||
logic s_rtc_wake_seen_d, s_rtc_wake_seen_q;
|
logic s_rtc_wake_seen_d, s_rtc_wake_seen_q;
|
||||||
|
logic s_hp_release_d, s_hp_release_q;
|
||||||
|
logic s_debug_hp_sel_d, s_debug_hp_sel_q;
|
||||||
logic s_rtc_wake_sync;
|
logic s_rtc_wake_sync;
|
||||||
logic s_core_sel_write_valid;
|
logic s_core_sel_write_valid;
|
||||||
logic s_core_sel_write_en;
|
logic s_core_sel_write_en;
|
||||||
@@ -154,6 +159,8 @@ module sysctrl_core (
|
|||||||
assign sysctrl.test_done_o = s_test_done_q;
|
assign sysctrl.test_done_o = s_test_done_q;
|
||||||
assign sysctrl.test_pass_o = s_test_pass_q;
|
assign sysctrl.test_pass_o = s_test_pass_q;
|
||||||
assign sysctrl.test_code_o = s_test_code_q;
|
assign sysctrl.test_code_o = s_test_code_q;
|
||||||
|
assign sysctrl.hp_release_o = s_hp_release_q;
|
||||||
|
assign sysctrl.debug_hp_select_o = s_debug_hp_sel_q;
|
||||||
assign pll_ctrl.req_sel_o = s_pll_cfg_q;
|
assign pll_ctrl.req_sel_o = s_pll_cfg_q;
|
||||||
assign pll_ctrl.req_valid_o = s_pll_req_valid_q;
|
assign pll_ctrl.req_valid_o = s_pll_req_valid_q;
|
||||||
assign pll_ctrl.rsp_ready_o = 1'b1;
|
assign pll_ctrl.rsp_ready_o = 1'b1;
|
||||||
@@ -221,6 +228,35 @@ module sysctrl_core (
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_hp_release_d = s_hp_release_q;
|
||||||
|
s_debug_hp_sel_d = s_debug_hp_sel_q;
|
||||||
|
if (write_valid_i && (write_offset_i == HpCtrl) && write_strobe_i[0]) begin
|
||||||
|
s_hp_release_d = write_data_i[`APB4_SYSCTRL__HP_CTRL_RELEASE] && sysctrl.hp_present_i;
|
||||||
|
end
|
||||||
|
if (write_valid_i && (write_offset_i == DebugSelect) && write_strobe_i[0] &&
|
||||||
|
!s_hp_release_q) begin
|
||||||
|
s_debug_hp_sel_d = write_data_i[`APB4_SYSCTRL__DEBUG_SELECT_HP] && sysctrl.hp_present_i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_hp_release_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_hp_release_d),
|
||||||
|
.dat_o (s_hp_release_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_debug_hp_select_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_debug_hp_sel_d),
|
||||||
|
.dat_o (s_debug_hp_sel_q)
|
||||||
|
);
|
||||||
|
|
||||||
assign s_pll_cfg_write_en = write_valid_i && (write_offset_i == PllCfg) && write_strobe_i[0];
|
assign s_pll_cfg_write_en = write_valid_i && (write_offset_i == PllCfg) && write_strobe_i[0];
|
||||||
assign s_pll_apply = write_valid_i && (write_offset_i == PllCmd) && write_strobe_i[0] &&
|
assign s_pll_apply = write_valid_i && (write_offset_i == PllCmd) && write_strobe_i[0] &&
|
||||||
write_data_i[`APB4_SYSCTRL__PLL_CMD_APPLY];
|
write_data_i[`APB4_SYSCTRL__PLL_CMD_APPLY];
|
||||||
@@ -510,6 +546,12 @@ module sysctrl_core (
|
|||||||
PerfFlashWaitHi: read_data_o = s_perf_flash_wait_q[63:32];
|
PerfFlashWaitHi: read_data_o = s_perf_flash_wait_q[63:32];
|
||||||
TestStatus: read_data_o = {s_test_done_q, 15'd0, s_test_code_q, 7'd0, s_test_pass_q};
|
TestStatus: read_data_o = {s_test_done_q, 15'd0, s_test_code_q, 7'd0, s_test_pass_q};
|
||||||
RtcWakeStatus: read_data_o = {30'd0, s_rtc_wake_seen_q, s_rtc_wake_sync};
|
RtcWakeStatus: read_data_o = {30'd0, s_rtc_wake_seen_q, s_rtc_wake_sync};
|
||||||
|
HpCtrl: read_data_o = {31'd0, s_hp_release_q};
|
||||||
|
HpStatus:
|
||||||
|
read_data_o = {
|
||||||
|
29'd0, sysctrl.hp_present_i && !s_hp_release_q, s_hp_release_q, sysctrl.hp_present_i
|
||||||
|
};
|
||||||
|
DebugSelect: read_data_o = {31'd0, s_debug_hp_sel_q};
|
||||||
default: begin
|
default: begin
|
||||||
read_data_valid_o = 1'b0;
|
read_data_valid_o = 1'b0;
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -51,6 +51,9 @@
|
|||||||
`define APB4_SYSCTRL__RTC_WAKE_STATUS `SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET
|
`define APB4_SYSCTRL__RTC_WAKE_STATUS `SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET
|
||||||
`define APB4_SYSCTRL__PERF_USB2_WAIT_LO `SOC_SYSCTRL_PERF_USB2_WAIT_LO_OFFSET
|
`define APB4_SYSCTRL__PERF_USB2_WAIT_LO `SOC_SYSCTRL_PERF_USB2_WAIT_LO_OFFSET
|
||||||
`define APB4_SYSCTRL__PERF_USB2_WAIT_HI `SOC_SYSCTRL_PERF_USB2_WAIT_HI_OFFSET
|
`define APB4_SYSCTRL__PERF_USB2_WAIT_HI `SOC_SYSCTRL_PERF_USB2_WAIT_HI_OFFSET
|
||||||
|
`define APB4_SYSCTRL__HP_CTRL `SOC_SYSCTRL_HP_CTRL_OFFSET
|
||||||
|
`define APB4_SYSCTRL__HP_STATUS `SOC_SYSCTRL_HP_STATUS_OFFSET
|
||||||
|
`define APB4_SYSCTRL__DEBUG_SELECT `SOC_SYSCTRL_DEBUG_SELECT_OFFSET
|
||||||
|
|
||||||
`define APB4_SYSCTRL__PLL_CMD_APPLY 0
|
`define APB4_SYSCTRL__PLL_CMD_APPLY 0
|
||||||
`define APB4_SYSCTRL__PLL_CMD_CLEAR_ERROR 1
|
`define APB4_SYSCTRL__PLL_CMD_CLEAR_ERROR 1
|
||||||
@@ -63,6 +66,8 @@
|
|||||||
`define APB4_SYSCTRL__TEST_STATUS_VALID 31
|
`define APB4_SYSCTRL__TEST_STATUS_VALID 31
|
||||||
`define APB4_SYSCTRL__RTC_WAKE_STATUS_LIVE 0
|
`define APB4_SYSCTRL__RTC_WAKE_STATUS_LIVE 0
|
||||||
`define APB4_SYSCTRL__RTC_WAKE_STATUS_SEEN 1
|
`define APB4_SYSCTRL__RTC_WAKE_STATUS_SEEN 1
|
||||||
|
`define APB4_SYSCTRL__HP_CTRL_RELEASE 0
|
||||||
|
`define APB4_SYSCTRL__DEBUG_SELECT_HP 0
|
||||||
// verilog_format: on
|
// verilog_format: on
|
||||||
|
|
||||||
`endif
|
`endif
|
||||||
@@ -36,6 +36,9 @@ interface sysctrl_if ();
|
|||||||
logic test_pass_o;
|
logic test_pass_o;
|
||||||
logic [ 7:0] test_code_o;
|
logic [ 7:0] test_code_o;
|
||||||
logic [ `USER_IPSEL_WIDTH-1:0] ip_sel_o;
|
logic [ `USER_IPSEL_WIDTH-1:0] ip_sel_o;
|
||||||
|
logic hp_present_i;
|
||||||
|
logic hp_release_o;
|
||||||
|
logic debug_hp_select_o;
|
||||||
|
|
||||||
modport dut(
|
modport dut(
|
||||||
input user_bus_idle_i,
|
input user_bus_idle_i,
|
||||||
@@ -54,6 +57,7 @@ interface sysctrl_if ();
|
|||||||
input perf_psram_wait_i,
|
input perf_psram_wait_i,
|
||||||
input perf_flash_wait_i,
|
input perf_flash_wait_i,
|
||||||
input rtc_wake_i,
|
input rtc_wake_i,
|
||||||
|
input hp_present_i,
|
||||||
output core_sel_o,
|
output core_sel_o,
|
||||||
output core_reset_o,
|
output core_reset_o,
|
||||||
output user_bus_enable_o,
|
output user_bus_enable_o,
|
||||||
@@ -62,6 +66,8 @@ interface sysctrl_if ();
|
|||||||
output perf_clear_o,
|
output perf_clear_o,
|
||||||
output test_done_o,
|
output test_done_o,
|
||||||
output test_pass_o,
|
output test_pass_o,
|
||||||
output test_code_o
|
output test_code_o,
|
||||||
|
output hp_release_o,
|
||||||
|
output debug_hp_select_o
|
||||||
);
|
);
|
||||||
endinterface
|
endinterface
|
||||||
+2
-1
@@ -122,7 +122,7 @@ check-clock-reset-domains:
|
|||||||
|
|
||||||
$(FILELIST_STAMP): $(FILELIST_TEMPLATES) $(RTL_PATH)/script/generate_filelist.py \
|
$(FILELIST_STAMP): $(FILELIST_TEMPLATES) $(RTL_PATH)/script/generate_filelist.py \
|
||||||
$(RTL_PATH)/script/filelist.py $(MEMORY_MAP_STAMP) $(PIN_MAP_STAMP) $(SOC_TOPOLOGY_STAMP) \
|
$(RTL_PATH)/script/filelist.py $(MEMORY_MAP_STAMP) $(PIN_MAP_STAMP) $(SOC_TOPOLOGY_STAMP) \
|
||||||
$(USER_EXTENSIONS_STAMP) $(ARCHINFO_METADATA_STAMP)
|
$(USER_EXTENSIONS_STAMP) $(ARCHINFO_METADATA_STAMP) $(if $(filter YES,$(HAVE_HP)),$(HP_GENERATED_STAMP))
|
||||||
$(FLOW_PYTHON) $(RTL_PATH)/script/generate_filelist.py \
|
$(FLOW_PYTHON) $(RTL_PATH)/script/generate_filelist.py \
|
||||||
--output-dir $(GENERATED_FL_DIR) \
|
--output-dir $(GENERATED_FL_DIR) \
|
||||||
--incdir $(ARCHINFO_METADATA_DIR) \
|
--incdir $(ARCHINFO_METADATA_DIR) \
|
||||||
@@ -167,6 +167,7 @@ RTL_FILELISTS := $(MEMORY_MAP_FILELIST) $(SOC_TOPOLOGY_FILELIST) $(USER_EXTENSIO
|
|||||||
$(GENERATED_FL_DIR)/core_hazard3.fl \
|
$(GENERATED_FL_DIR)/core_hazard3.fl \
|
||||||
$(MPW_OUTPUT_DIR)/core/core.fl \
|
$(MPW_OUTPUT_DIR)/core/core.fl \
|
||||||
$(MPW_OUTPUT_DIR)/ip/ip.fl \
|
$(MPW_OUTPUT_DIR)/ip/ip.fl \
|
||||||
|
$(if $(filter YES,$(HAVE_HP)),$(HP_GENERATED_DIR)/vexiiriscv.fl) \
|
||||||
$(GENERATED_FL_DIR)/top.fl
|
$(GENERATED_FL_DIR)/top.fl
|
||||||
RTL_FLIST := $(foreach filelist,$(RTL_FILELISTS),-f $(filelist))
|
RTL_FLIST := $(foreach filelist,$(RTL_FILELISTS),-f $(filelist))
|
||||||
#====================== end ======================
|
#====================== end ======================
|
||||||
|
|||||||
@@ -149,6 +149,18 @@
|
|||||||
{
|
{
|
||||||
"symbol": "PERF_USB2_WAIT_HI",
|
"symbol": "PERF_USB2_WAIT_HI",
|
||||||
"offset": "0xA0"
|
"offset": "0xA0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"symbol": "HP_CTRL",
|
||||||
|
"offset": "0xA4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"symbol": "HP_STATUS",
|
||||||
|
"offset": "0xA8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"symbol": "DEBUG_SELECT",
|
||||||
|
"offset": "0xAC"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"regions": [
|
"regions": [
|
||||||
@@ -163,6 +175,24 @@
|
|||||||
"user_access": "ro",
|
"user_access": "ro",
|
||||||
"burst": "incr16"
|
"burst": "incr16"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"symbol": "HP_ACLINT",
|
||||||
|
"base": "0x02000000",
|
||||||
|
"size": "0x00010000",
|
||||||
|
"route": "apb4_periph",
|
||||||
|
"kind": "active",
|
||||||
|
"public": true,
|
||||||
|
"user_access": "rw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"symbol": "HP_PLIC",
|
||||||
|
"base": "0x0C000000",
|
||||||
|
"size": "0x04000000",
|
||||||
|
"route": "apb4_periph",
|
||||||
|
"kind": "active",
|
||||||
|
"public": true,
|
||||||
|
"user_access": "rw"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"symbol": "APB4_GPIO",
|
"symbol": "APB4_GPIO",
|
||||||
"base": "0x10000000",
|
"base": "0x10000000",
|
||||||
@@ -388,6 +418,24 @@
|
|||||||
"public": true,
|
"public": true,
|
||||||
"user_access": "none"
|
"user_access": "none"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"symbol": "APB4_UART1",
|
||||||
|
"base": "0x10018000",
|
||||||
|
"size": "0x00001000",
|
||||||
|
"route": "apb4_periph",
|
||||||
|
"kind": "active",
|
||||||
|
"public": true,
|
||||||
|
"user_access": "rw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"symbol": "APB4_HP_MAILBOX",
|
||||||
|
"base": "0x10019000",
|
||||||
|
"size": "0x00001000",
|
||||||
|
"route": "apb4_periph",
|
||||||
|
"kind": "active",
|
||||||
|
"public": true,
|
||||||
|
"user_access": "rw"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"symbol": "APB4_ARCHINFO",
|
"symbol": "APB4_ARCHINFO",
|
||||||
"base": "0x20000000",
|
"base": "0x20000000",
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ module retrosoc_tb;
|
|||||||
wire s_jtag_trst_n;
|
wire s_jtag_trst_n;
|
||||||
wire s_uart0_tx;
|
wire s_uart0_tx;
|
||||||
wire s_uart0_rx;
|
wire s_uart0_rx;
|
||||||
|
wire s_uart1_tx;
|
||||||
|
tri1 s_uart1_rx;
|
||||||
tri1 s_gpio_0_io;
|
tri1 s_gpio_0_io;
|
||||||
tri1 s_gpio_1_io;
|
tri1 s_gpio_1_io;
|
||||||
wire s_psram_sck;
|
wire s_psram_sck;
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ module retrosoc_top (
|
|||||||
wire s_jtag_tdi;
|
wire s_jtag_tdi;
|
||||||
wire s_jtag_trst_n;
|
wire s_jtag_trst_n;
|
||||||
wire s_jtag_tdo;
|
wire s_jtag_tdo;
|
||||||
|
wire s_uart1_tx;
|
||||||
|
tri1 s_uart1_rx;
|
||||||
wire s_usb2_ulpi_clk;
|
wire s_usb2_ulpi_clk;
|
||||||
tri0 s_usb2_ulpi_dir;
|
tri0 s_usb2_ulpi_dir;
|
||||||
tri0 s_usb2_ulpi_nxt;
|
tri0 s_usb2_ulpi_nxt;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
/clusterip/common/rtl/interface/ahbl_if.sv
|
/clusterip/common/rtl/interface/ahbl_if.sv
|
||||||
/clusterip/common/rtl/interface/axi4_if.sv
|
/clusterip/common/rtl/interface/axi4_if.sv
|
||||||
/clusterip/common/rtl/interface/axi4_addr_gen.sv
|
/clusterip/common/rtl/interface/axi4_addr_gen.sv
|
||||||
|
/clusterip/common/rtl/bus/axi4_regslice.sv
|
||||||
/clusterip/common/rtl/interface/axi4_stream_if.sv
|
/clusterip/common/rtl/interface/axi4_stream_if.sv
|
||||||
/clusterip/common/rtl/interface/ribp_if.sv
|
/clusterip/common/rtl/interface/ribp_if.sv
|
||||||
/clusterip/common/rtl/interface/ram_if.sv
|
/clusterip/common/rtl/interface/ram_if.sv
|
||||||
|
|||||||
@@ -111,6 +111,9 @@
|
|||||||
/ip/peripheral/clint_reg.sv
|
/ip/peripheral/clint_reg.sv
|
||||||
/ip/peripheral/clint_core.sv
|
/ip/peripheral/clint_core.sv
|
||||||
/ip/peripheral/apb4_clint.sv
|
/ip/peripheral/apb4_clint.sv
|
||||||
|
/ip/peripheral/hp_mailbox_define.svh
|
||||||
|
/ip/peripheral/apb4_hp_mailbox.sv
|
||||||
|
/ip/peripheral/apb4_plic.sv
|
||||||
/ip/memory/sdram_pkg.sv
|
/ip/memory/sdram_pkg.sv
|
||||||
/ip/memory/sdram_clkgen.sv
|
/ip/memory/sdram_clkgen.sv
|
||||||
/ip/memory/sdram_reg.sv
|
/ip/memory/sdram_reg.sv
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
/top/axi42apb4_system.sv
|
/top/axi42apb4_system.sv
|
||||||
/top/axi42apb4_periph.sv
|
/top/axi42apb4_periph.sv
|
||||||
/top/axi4_word_bridge.sv
|
/top/axi4_word_bridge.sv
|
||||||
|
/top/axi4_downsizer_64to32.sv
|
||||||
|
/top/hp_axi4_mux3.sv
|
||||||
/top/axi42ram.sv
|
/top/axi42ram.sv
|
||||||
/top/rib_error_slave.sv
|
/top/rib_error_slave.sv
|
||||||
/top/rib2ram.sv
|
/top/rib2ram.sv
|
||||||
@@ -29,6 +31,8 @@
|
|||||||
/top/mgmt_debug_reset.sv
|
/top/mgmt_debug_reset.sv
|
||||||
/top/mgmt_debug_wrapper.sv
|
/top/mgmt_debug_wrapper.sv
|
||||||
/top/mgmt_core_wrapper.sv
|
/top/mgmt_core_wrapper.sv
|
||||||
|
/top/hp_core_wrapper.sv
|
||||||
|
/top/hp_subsystem.sv
|
||||||
/top/user_core_design.sv
|
/top/user_core_design.sv
|
||||||
/top/user_core_top.sv
|
/top/user_core_top.sv
|
||||||
/top/user_ip_design_template.sv
|
/top/user_ip_design_template.sv
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ module sysctrl_formal_design (
|
|||||||
output logic [31:0] fault_count,
|
output logic [31:0] fault_count,
|
||||||
output logic test_done,
|
output logic test_done,
|
||||||
output logic test_pass,
|
output logic test_pass,
|
||||||
output logic [ 7:0] test_code
|
output logic [ 7:0] test_code,
|
||||||
|
output logic hp_release,
|
||||||
|
output logic debug_hp_select
|
||||||
);
|
);
|
||||||
|
|
||||||
apb4_if apb4 (
|
apb4_if apb4 (
|
||||||
@@ -85,12 +87,14 @@ module sysctrl_formal_design (
|
|||||||
assign sysctrl.perf_dma_wait_i = '0;
|
assign sysctrl.perf_dma_wait_i = '0;
|
||||||
assign sysctrl.perf_sdio0_wait_i = '0;
|
assign sysctrl.perf_sdio0_wait_i = '0;
|
||||||
assign sysctrl.perf_sdio1_wait_i = '0;
|
assign sysctrl.perf_sdio1_wait_i = '0;
|
||||||
|
assign sysctrl.perf_usb2_wait_i = '0;
|
||||||
assign sysctrl.perf_apb4_periph_wait_i = '0;
|
assign sysctrl.perf_apb4_periph_wait_i = '0;
|
||||||
assign sysctrl.perf_apb4_system_wait_i = '0;
|
assign sysctrl.perf_apb4_system_wait_i = '0;
|
||||||
assign sysctrl.perf_sdram_wait_i = '0;
|
assign sysctrl.perf_sdram_wait_i = '0;
|
||||||
assign sysctrl.perf_psram_wait_i = '0;
|
assign sysctrl.perf_psram_wait_i = '0;
|
||||||
assign sysctrl.perf_flash_wait_i = '0;
|
assign sysctrl.perf_flash_wait_i = '0;
|
||||||
assign sysctrl.rtc_wake_i = 1'b0;
|
assign sysctrl.rtc_wake_i = 1'b0;
|
||||||
|
assign sysctrl.hp_present_i = 1'b1;
|
||||||
assign pll_ctrl.req_ready_i = f_pll_req_ready;
|
assign pll_ctrl.req_ready_i = f_pll_req_ready;
|
||||||
assign pll_ctrl.rsp_active_sel_i = f_pll_active_sel;
|
assign pll_ctrl.rsp_active_sel_i = f_pll_active_sel;
|
||||||
assign pll_ctrl.rsp_active_valid_i = f_pll_active_valid;
|
assign pll_ctrl.rsp_active_valid_i = f_pll_active_valid;
|
||||||
@@ -131,6 +135,8 @@ module sysctrl_formal_design (
|
|||||||
assign test_done = sysctrl.test_done_o;
|
assign test_done = sysctrl.test_done_o;
|
||||||
assign test_pass = sysctrl.test_pass_o;
|
assign test_pass = sysctrl.test_pass_o;
|
||||||
assign test_code = sysctrl.test_code_o;
|
assign test_code = sysctrl.test_code_o;
|
||||||
|
assign hp_release = sysctrl.hp_release_o;
|
||||||
|
assign debug_hp_select = sysctrl.debug_hp_select_o;
|
||||||
|
|
||||||
apb4_sysctrl u_dut (
|
apb4_sysctrl u_dut (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ module sysctrl_formal;
|
|||||||
localparam [7:0] SYSCTRL_FAULT_STATUS_OFFSET = 8'h10;
|
localparam [7:0] SYSCTRL_FAULT_STATUS_OFFSET = 8'h10;
|
||||||
localparam [7:0] SYSCTRL_USER_CORE_RESET_OFFSET = 8'h20;
|
localparam [7:0] SYSCTRL_USER_CORE_RESET_OFFSET = 8'h20;
|
||||||
localparam [7:0] SYSCTRL_TEST_STATUS_OFFSET = 8'h84;
|
localparam [7:0] SYSCTRL_TEST_STATUS_OFFSET = 8'h84;
|
||||||
|
localparam [7:0] SYSCTRL_HP_CTRL_OFFSET = 8'hA4;
|
||||||
|
localparam [7:0] SYSCTRL_DEBUG_SELECT_OFFSET = 8'hAC;
|
||||||
|
|
||||||
(* anyseq *) (* gclk *)reg clk_i;
|
(* anyseq *) (* gclk *)reg clk_i;
|
||||||
wire rst_n_i;
|
wire rst_n_i;
|
||||||
@@ -51,6 +53,8 @@ module sysctrl_formal;
|
|||||||
wire test_done;
|
wire test_done;
|
||||||
wire test_pass;
|
wire test_pass;
|
||||||
wire [ 7:0] test_code;
|
wire [ 7:0] test_code;
|
||||||
|
wire hp_release;
|
||||||
|
wire debug_hp_select;
|
||||||
|
|
||||||
sysctrl_formal_design u_design (
|
sysctrl_formal_design u_design (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
@@ -86,7 +90,9 @@ module sysctrl_formal;
|
|||||||
.fault_count (fault_count),
|
.fault_count (fault_count),
|
||||||
.test_done (test_done),
|
.test_done (test_done),
|
||||||
.test_pass (test_pass),
|
.test_pass (test_pass),
|
||||||
.test_code (test_code)
|
.test_code (test_code),
|
||||||
|
.hp_release (hp_release),
|
||||||
|
.debug_hp_select (debug_hp_select)
|
||||||
);
|
);
|
||||||
|
|
||||||
always @(posedge clk_i) begin
|
always @(posedge clk_i) begin
|
||||||
@@ -187,12 +193,28 @@ module sysctrl_formal;
|
|||||||
assert (test_pass == $past(test_pass));
|
assert (test_pass == $past(test_pass));
|
||||||
assert (test_code == $past(test_code));
|
assert (test_code == $past(test_code));
|
||||||
end
|
end
|
||||||
|
if ($past(
|
||||||
|
rst_n_i && rib_valid && !rib_ready && rib_wstrb[0] &&
|
||||||
|
rib_addr[7:0] == SYSCTRL_HP_CTRL_OFFSET
|
||||||
|
)) begin
|
||||||
|
assert (hp_release == $past(rib_wdata[0]));
|
||||||
|
end
|
||||||
|
if ($past(
|
||||||
|
rst_n_i && rib_valid && !rib_ready && rib_wstrb[0] &&
|
||||||
|
rib_addr[7:0] == SYSCTRL_DEBUG_SELECT_OFFSET && !hp_release
|
||||||
|
)) begin
|
||||||
|
assert (debug_hp_select == $past(rib_wdata[0]));
|
||||||
|
end
|
||||||
|
if ($past(rst_n_i && hp_release)) begin
|
||||||
|
assert (debug_hp_select == $past(debug_hp_select));
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (rst_n_i) begin
|
if (rst_n_i) begin
|
||||||
cover (pll_busy && pll_req_valid);
|
cover (pll_busy && pll_req_valid);
|
||||||
cover (pll_error && pll_error_reason == 2'd3);
|
cover (pll_error && pll_error_reason == 2'd3);
|
||||||
cover (fault_pending && fault_reason == 2'd2);
|
cover (fault_pending && fault_reason == 2'd2);
|
||||||
|
cover (hp_release);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -198,6 +198,14 @@
|
|||||||
"path": "rtl/managed/hazard3/hdl/debug/dtm/hazard3_jtag_dtm_core.v",
|
"path": "rtl/managed/hazard3/hdl/debug/dtm/hazard3_jtag_dtm_core.v",
|
||||||
"instance": "inst_hazard3_apb_async_bridge"
|
"instance": "inst_hazard3_apb_async_bridge"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "hp_debug_select",
|
||||||
|
"source": "system",
|
||||||
|
"destination": "jtag",
|
||||||
|
"primitive": "cdc_sync",
|
||||||
|
"path": "rtl/mini/top/retrosoc.sv",
|
||||||
|
"instance": "u_debug_select_sync"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "wdg_command",
|
"name": "wdg_command",
|
||||||
"source": "system",
|
"source": "system",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"irq_groups": [
|
"irq_groups": [
|
||||||
{
|
{
|
||||||
"name": "apb4_periph",
|
"name": "apb4_periph",
|
||||||
"width": 20,
|
"width": 22,
|
||||||
"top_signal": "s_apb4_periph_irq"
|
"top_signal": "s_apb4_periph_irq"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -222,6 +222,24 @@
|
|||||||
"core_bit": 24,
|
"core_bit": 24,
|
||||||
"signal": "s_usb2_irq",
|
"signal": "s_usb2_irq",
|
||||||
"user_visible": false
|
"user_visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hp_mailbox_lp",
|
||||||
|
"description": "HP-to-LP mailbox doorbell",
|
||||||
|
"group": "apb4_periph",
|
||||||
|
"group_bit": 20,
|
||||||
|
"core_bit": 25,
|
||||||
|
"signal": "s_mailbox_lp_irq",
|
||||||
|
"user_visible": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "uart1",
|
||||||
|
"description": "HP Linux UART interrupt",
|
||||||
|
"group": "apb4_periph",
|
||||||
|
"group_bit": 21,
|
||||||
|
"core_bit": 26,
|
||||||
|
"signal": "uart1.irq_o",
|
||||||
|
"user_visible": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"wake_sources": [
|
"wake_sources": [
|
||||||
@@ -437,6 +455,34 @@
|
|||||||
"pure_interface": "sram_cfg_pure",
|
"pure_interface": "sram_cfg_pure",
|
||||||
"region": "APB4_SRAM",
|
"region": "APB4_SRAM",
|
||||||
"external": true
|
"external": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 22,
|
||||||
|
"name": "uart1",
|
||||||
|
"timed_interface": "u_uart1_apb4_if",
|
||||||
|
"pure_interface": "u_uart1_apb4_pure_if",
|
||||||
|
"region": "APB4_UART1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 23,
|
||||||
|
"name": "hp_mailbox",
|
||||||
|
"timed_interface": "u_hp_mailbox_apb4_if",
|
||||||
|
"pure_interface": "u_hp_mailbox_apb4_pure_if",
|
||||||
|
"region": "APB4_HP_MAILBOX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 24,
|
||||||
|
"name": "hp_aclint",
|
||||||
|
"timed_interface": "u_hp_aclint_apb4_if",
|
||||||
|
"pure_interface": "u_hp_aclint_apb4_pure_if",
|
||||||
|
"region": "HP_ACLINT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 25,
|
||||||
|
"name": "hp_plic",
|
||||||
|
"timed_interface": "u_hp_plic_apb4_if",
|
||||||
|
"pure_interface": "u_hp_plic_apb4_pure_if",
|
||||||
|
"region": "HP_PLIC"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"apb4_system_targets": [
|
"apb4_system_targets": [
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
|||||||
$(ROOT_PATH)/crt/src/hal/uart.c \
|
$(ROOT_PATH)/crt/src/hal/uart.c \
|
||||||
$(ROOT_PATH)/crt/src/hal/gpio_math.c \
|
$(ROOT_PATH)/crt/src/hal/gpio_math.c \
|
||||||
$(ROOT_PATH)/crt/src/hal/gpio.c \
|
$(ROOT_PATH)/crt/src/hal/gpio.c \
|
||||||
|
$(ROOT_PATH)/crt/src/hal/hp_mailbox.c \
|
||||||
$(ROOT_PATH)/crt/src/hal/timer_math.c \
|
$(ROOT_PATH)/crt/src/hal/timer_math.c \
|
||||||
$(ROOT_PATH)/crt/src/hal/timer.c \
|
$(ROOT_PATH)/crt/src/hal/timer.c \
|
||||||
$(ROOT_PATH)/crt/src/hal/pwm.c \
|
$(ROOT_PATH)/crt/src/hal/pwm.c \
|
||||||
|
|||||||
@@ -139,6 +139,20 @@
|
|||||||
{"name": "uart0_rx_i_pad", "signal": "s_uart0_rx"}
|
{"name": "uart0_rx_i_pad", "signal": "s_uart0_rx"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "tri_output",
|
||||||
|
"direction": "output",
|
||||||
|
"ports": [
|
||||||
|
{"name": "uart1_tx_o_pad", "signal": "s_uart1_tx"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "tri_input",
|
||||||
|
"direction": "inout",
|
||||||
|
"ports": [
|
||||||
|
{"name": "uart1_rx_i_pad", "signal": "s_uart1_rx"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "tri_output",
|
"kind": "tri_output",
|
||||||
"direction": "output",
|
"direction": "output",
|
||||||
@@ -260,6 +274,8 @@
|
|||||||
"usb2_ulpi_reset_n_o_pad": "s_usb2_ulpi_reset_n",
|
"usb2_ulpi_reset_n_o_pad": "s_usb2_ulpi_reset_n",
|
||||||
"uart0_tx_o_pad": "uart0_tx_o",
|
"uart0_tx_o_pad": "uart0_tx_o",
|
||||||
"uart0_rx_i_pad": "uart0_rx_i",
|
"uart0_rx_i_pad": "uart0_rx_i",
|
||||||
|
"uart1_tx_o_pad": "uart1_tx_o",
|
||||||
|
"uart1_rx_i_pad": "uart1_rx_i",
|
||||||
"xpi_sck_o_pad": "xpi_sck_o",
|
"xpi_sck_o_pad": "xpi_sck_o",
|
||||||
"xpi_nss0_o_pad": "xpi_nss0_o",
|
"xpi_nss0_o_pad": "xpi_nss0_o",
|
||||||
"xpi_dat0_io_pad": "xpi_dat0_io",
|
"xpi_dat0_io_pad": "xpi_dat0_io",
|
||||||
@@ -316,6 +332,8 @@
|
|||||||
"jtag_tdi_i_pad": "s_jtag_tdi",
|
"jtag_tdi_i_pad": "s_jtag_tdi",
|
||||||
"jtag_trst_n_i_pad": "s_jtag_trst_n",
|
"jtag_trst_n_i_pad": "s_jtag_trst_n",
|
||||||
"jtag_tdo_o_pad": "s_jtag_tdo",
|
"jtag_tdo_o_pad": "s_jtag_tdo",
|
||||||
|
"uart1_tx_o_pad": "s_uart1_tx",
|
||||||
|
"uart1_rx_i_pad": "s_uart1_rx",
|
||||||
"gpio_21_io_pad": "s_psram_sck",
|
"gpio_21_io_pad": "s_psram_sck",
|
||||||
"gpio_22_io_pad": "s_psram_nss0",
|
"gpio_22_io_pad": "s_psram_nss0",
|
||||||
"gpio_23_io_pad": "s_psram_dat0",
|
"gpio_23_io_pad": "s_psram_dat0",
|
||||||
@@ -436,6 +454,8 @@
|
|||||||
"usb2_ulpi_reset_n_o_pad": "s_usb2_ulpi_reset_n",
|
"usb2_ulpi_reset_n_o_pad": "s_usb2_ulpi_reset_n",
|
||||||
"uart0_tx_o_pad": "s_uart0_tx",
|
"uart0_tx_o_pad": "s_uart0_tx",
|
||||||
"uart0_rx_i_pad": "s_uart0_rx",
|
"uart0_rx_i_pad": "s_uart0_rx",
|
||||||
|
"uart1_tx_o_pad": "s_uart1_tx",
|
||||||
|
"uart1_rx_i_pad": "s_uart1_rx",
|
||||||
"xpi_sck_o_pad": "s_xpi_sck_o",
|
"xpi_sck_o_pad": "s_xpi_sck_o",
|
||||||
"xpi_nss0_o_pad": "s_xpi_nss0_o",
|
"xpi_nss0_o_pad": "s_xpi_nss0_o",
|
||||||
"xpi_nss1_o_pad": "s_xpi_nss1_o",
|
"xpi_nss1_o_pad": "s_xpi_nss1_o",
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ module apb4_periph (
|
|||||||
gpio_if.dut gpio,
|
gpio_if.dut gpio,
|
||||||
user_gpio_if.padctrl user_gpio,
|
user_gpio_if.padctrl user_gpio,
|
||||||
uart_if.dut uart,
|
uart_if.dut uart,
|
||||||
|
uart_if.dut uart1,
|
||||||
psram_if.dut psram,
|
psram_if.dut psram,
|
||||||
spi_if.dut spisd,
|
spi_if.dut spisd,
|
||||||
i2c_if.dut i2c0,
|
i2c_if.dut i2c0,
|
||||||
@@ -52,6 +53,11 @@ module apb4_periph (
|
|||||||
input logic [31:0] fault_addr_i,
|
input logic [31:0] fault_addr_i,
|
||||||
input logic [3:0] fault_wstrb_i,
|
input logic [3:0] fault_wstrb_i,
|
||||||
input logic fault_reserved_i,
|
input logic fault_reserved_i,
|
||||||
|
output logic [63:0] hp_time_o,
|
||||||
|
output logic hp_timer_irq_o,
|
||||||
|
output logic hp_software_irq_o,
|
||||||
|
output logic hp_machine_external_irq_o,
|
||||||
|
output logic hp_supervisor_external_irq_o,
|
||||||
output logic [`SOC_IRQ_APB4_PERIPH_WIDTH-1:0] irq_o
|
output logic [`SOC_IRQ_APB4_PERIPH_WIDTH-1:0] irq_o
|
||||||
// verilog_format: on
|
// verilog_format: on
|
||||||
);
|
);
|
||||||
@@ -107,6 +113,7 @@ axi4_stream_if #(
|
|||||||
);
|
);
|
||||||
|
|
||||||
clint_if u_clint_if ();
|
clint_if u_clint_if ();
|
||||||
|
clint_if #(.HartNum(2)) u_hp_clint_if ();
|
||||||
dma_req_if u_dma_req_if ();
|
dma_req_if u_dma_req_if ();
|
||||||
|
|
||||||
logic s_dma_i2s_tx_stall, s_dma_i2s_rx_stall;
|
logic s_dma_i2s_tx_stall, s_dma_i2s_rx_stall;
|
||||||
@@ -123,6 +130,9 @@ axi4_stream_if #(
|
|||||||
logic s_tim0_irq, s_tim1_irq;
|
logic s_tim0_irq, s_tim1_irq;
|
||||||
logic s_dvp_irq;
|
logic s_dvp_irq;
|
||||||
logic s_xpi_irq;
|
logic s_xpi_irq;
|
||||||
|
logic s_mailbox_lp_irq, s_mailbox_hp_irq;
|
||||||
|
logic [31:0] s_hp_plic_source;
|
||||||
|
logic [ 1:0] s_hp_plic_context_irq;
|
||||||
|
|
||||||
`ifdef PDK_GF180
|
`ifdef PDK_GF180
|
||||||
localparam bit GPIO_HAS_INPUT_CMOS = 1'b1;
|
localparam bit GPIO_HAS_INPUT_CMOS = 1'b1;
|
||||||
@@ -161,6 +171,17 @@ axi4_stream_if #(
|
|||||||
assign u_dma_req_if.i2c1_rx_proc = ~s_dma_i2c1_rx_stall;
|
assign u_dma_req_if.i2c1_rx_proc = ~s_dma_i2c1_rx_stall;
|
||||||
assign u_dma_req_if.crypto_in_proc = s_dma_crypto_in_proc;
|
assign u_dma_req_if.crypto_in_proc = s_dma_crypto_in_proc;
|
||||||
assign u_dma_req_if.crypto_out_proc = s_dma_crypto_out_proc;
|
assign u_dma_req_if.crypto_out_proc = s_dma_crypto_out_proc;
|
||||||
|
assign hp_time_o = u_hp_clint_if.mtime_o;
|
||||||
|
assign hp_timer_irq_o = u_hp_clint_if.timer_irq_o[1];
|
||||||
|
assign hp_software_irq_o = u_hp_clint_if.software_irq_o[1];
|
||||||
|
assign hp_machine_external_irq_o = s_hp_plic_context_irq[0];
|
||||||
|
assign hp_supervisor_external_irq_o = s_hp_plic_context_irq[1];
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_hp_plic_source = '0;
|
||||||
|
s_hp_plic_source[1] = uart1.irq_o;
|
||||||
|
s_hp_plic_source[2] = s_mailbox_hp_irq;
|
||||||
|
end
|
||||||
|
|
||||||
`include "apb4_periph_irq_bindings.svh"
|
`include "apb4_periph_irq_bindings.svh"
|
||||||
|
|
||||||
@@ -189,6 +210,42 @@ axi4_stream_if #(
|
|||||||
.uart (uart)
|
.uart (uart)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// UART1 is dedicated to HP Linux and intentionally has no central-DMA route in the MVP.
|
||||||
|
apb4_uart u_apb4_uart1 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i (rst_n_i),
|
||||||
|
.dma_tx_stall_o(),
|
||||||
|
.dma_rx_stall_o(),
|
||||||
|
.apb4 (u_uart1_apb4_if),
|
||||||
|
.uart (uart1)
|
||||||
|
);
|
||||||
|
|
||||||
|
apb4_hp_mailbox u_apb4_hp_mailbox (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i (rst_n_i),
|
||||||
|
.apb4 (u_hp_mailbox_apb4_if),
|
||||||
|
.lp_irq_o(s_mailbox_lp_irq),
|
||||||
|
.hp_irq_o(s_mailbox_hp_irq)
|
||||||
|
);
|
||||||
|
|
||||||
|
apb4_clint #(
|
||||||
|
.HartNum(2)
|
||||||
|
) u_apb4_hp_aclint (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i (rst_n_i),
|
||||||
|
.timebase_tick_i(timebase_tick_i),
|
||||||
|
.apb4 (u_hp_aclint_apb4_if),
|
||||||
|
.clint (u_hp_clint_if)
|
||||||
|
);
|
||||||
|
|
||||||
|
apb4_plic u_apb4_hp_plic (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i (rst_n_i),
|
||||||
|
.source_i (s_hp_plic_source),
|
||||||
|
.apb4 (u_hp_plic_apb4_if),
|
||||||
|
.context_irq_o(s_hp_plic_context_irq)
|
||||||
|
);
|
||||||
|
|
||||||
apb4_timer u_apb4_timer0 (
|
apb4_timer u_apb4_timer0 (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
.rst_n_i (rst_n_i),
|
.rst_n_i (rst_n_i),
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ always_comb begin
|
|||||||
s_resp_d = `AXI4_RESP_OKAY;
|
s_resp_d = `AXI4_RESP_OKAY;
|
||||||
if (axi4.arvalid && axi4.arready) begin
|
if (axi4.arvalid && axi4.arready) begin
|
||||||
s_addr_d = axi4.araddr;
|
s_addr_d = axi4.araddr;
|
||||||
|
s_wstrb_d = '0;
|
||||||
s_write_d = 1'b0;
|
s_write_d = 1'b0;
|
||||||
s_id_d = axi4.arid;
|
s_id_d = axi4.arid;
|
||||||
s_len_d = axi4.arlen;
|
s_len_d = axi4.arlen;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ module axi4_bus (
|
|||||||
axi4_if.slave sdio1_axi4,
|
axi4_if.slave sdio1_axi4,
|
||||||
axi4_if.slave usb2_axi4,
|
axi4_if.slave usb2_axi4,
|
||||||
axi4_if.slave spisd_axi4,
|
axi4_if.slave spisd_axi4,
|
||||||
|
axi4_if.slave hp_axi4,
|
||||||
axi4_if.master cfg_axi4,
|
axi4_if.master cfg_axi4,
|
||||||
axi4_if.master system_axi4,
|
axi4_if.master system_axi4,
|
||||||
axi4_if.master sram_axi4,
|
axi4_if.master sram_axi4,
|
||||||
@@ -51,7 +52,7 @@ module axi4_bus (
|
|||||||
output logic [63:0] perf_opipsram_wait_o
|
output logic [63:0] perf_opipsram_wait_o
|
||||||
// verilog_format: on
|
// verilog_format: on
|
||||||
);
|
);
|
||||||
localparam int NumMasters = 7;
|
localparam int NumMasters = 8;
|
||||||
localparam int NumTargets = 10;
|
localparam int NumTargets = 10;
|
||||||
|
|
||||||
axi4_if #(
|
axi4_if #(
|
||||||
@@ -109,6 +110,11 @@ module axi4_bus (
|
|||||||
.sink (u_master_axi4_if[6])
|
.sink (u_master_axi4_if[6])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
axi4_connector u_hp_connector (
|
||||||
|
.source(hp_axi4),
|
||||||
|
.sink (u_master_axi4_if[7])
|
||||||
|
);
|
||||||
|
|
||||||
axi4_connector u_cfg_connector (
|
axi4_connector u_cfg_connector (
|
||||||
.source(u_target_axi4_if[0]),
|
.source(u_target_axi4_if[0]),
|
||||||
.sink (cfg_axi4)
|
.sink (cfg_axi4)
|
||||||
|
|||||||
@@ -0,0 +1,372 @@
|
|||||||
|
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||||
|
// SPDX-License-Identifier: MulanPSL-2.0
|
||||||
|
|
||||||
|
`include "axi4_define.svh"
|
||||||
|
|
||||||
|
// Converts one outstanding 64-bit AXI4 transaction into a 32-bit transaction.
|
||||||
|
module axi4_downsizer_64to32 (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_n_i,
|
||||||
|
axi4_if.slave wide,
|
||||||
|
axi4_if.master narrow
|
||||||
|
);
|
||||||
|
typedef enum logic {
|
||||||
|
Idle,
|
||||||
|
Active
|
||||||
|
} channel_state_e;
|
||||||
|
|
||||||
|
channel_state_e s_read_state_d, s_read_state_q;
|
||||||
|
channel_state_e s_write_state_d, s_write_state_q;
|
||||||
|
logic [2:0] s_read_id_d, s_read_id_q;
|
||||||
|
logic [2:0] s_write_id_d, s_write_id_q;
|
||||||
|
logic [2:0] s_read_size_d, s_read_size_q;
|
||||||
|
logic [2:0] s_write_size_d, s_write_size_q;
|
||||||
|
logic [7:0] s_read_len_d, s_read_len_q;
|
||||||
|
logic [7:0] s_write_len_d, s_write_len_q;
|
||||||
|
logic [1:0] s_read_burst_d, s_read_burst_q;
|
||||||
|
logic [1:0] s_write_burst_d, s_write_burst_q;
|
||||||
|
logic [31:0] s_read_addr_d, s_read_addr_q;
|
||||||
|
logic [31:0] s_write_addr_d, s_write_addr_q;
|
||||||
|
logic [31:0] s_read_next_addr;
|
||||||
|
logic [31:0] s_write_next_addr;
|
||||||
|
logic s_read_upper_d, s_read_upper_q;
|
||||||
|
logic s_write_upper_d, s_write_upper_q;
|
||||||
|
logic [31:0] s_read_lower_d, s_read_lower_q;
|
||||||
|
logic [1:0] s_read_resp_d, s_read_resp_q;
|
||||||
|
logic s_read_accept;
|
||||||
|
logic s_write_addr_accept;
|
||||||
|
logic s_narrow_read_accept;
|
||||||
|
logic s_narrow_write_accept;
|
||||||
|
logic s_wide_read_accept;
|
||||||
|
logic s_wide_write_accept;
|
||||||
|
logic s_b_pending_d, s_b_pending_q;
|
||||||
|
logic [1:0] s_b_resp_d, s_b_resp_q;
|
||||||
|
logic [8:0] s_read_beats;
|
||||||
|
logic [8:0] s_write_beats;
|
||||||
|
|
||||||
|
assign s_read_beats = {1'b0, wide.arlen} + 9'd1;
|
||||||
|
assign s_write_beats = {1'b0, wide.awlen} + 9'd1;
|
||||||
|
|
||||||
|
assign wide.arready = (s_read_state_q == Idle) && narrow.arready;
|
||||||
|
assign narrow.arvalid = (s_read_state_q == Idle) && wide.arvalid;
|
||||||
|
assign narrow.arid = '0;
|
||||||
|
assign narrow.araddr = wide.araddr;
|
||||||
|
assign narrow.arlen = (wide.arsize == 3'd3) ? 8'((s_read_beats << 1) - 9'd1) : wide.arlen;
|
||||||
|
assign narrow.arsize = (wide.arsize == 3'd3) ? 3'd2 : wide.arsize;
|
||||||
|
assign narrow.arburst = wide.arburst;
|
||||||
|
assign narrow.arlock = wide.arlock;
|
||||||
|
assign narrow.arcache = wide.arcache;
|
||||||
|
assign narrow.arprot = wide.arprot;
|
||||||
|
assign narrow.arqos = wide.arqos;
|
||||||
|
assign narrow.arregion = wide.arregion;
|
||||||
|
assign narrow.aruser = '0;
|
||||||
|
assign s_read_accept = wide.arvalid && wide.arready;
|
||||||
|
|
||||||
|
assign wide.rid = s_read_id_q;
|
||||||
|
assign wide.rdata = (s_read_size_q == 3'd3) ? {narrow.rdata, s_read_lower_q} :
|
||||||
|
s_read_addr_q[2] ? {narrow.rdata, 32'd0} : {32'd0, narrow.rdata};
|
||||||
|
assign wide.rresp = (s_read_size_q == 3'd3) && (s_read_resp_q != `AXI4_RESP_OKAY) ?
|
||||||
|
s_read_resp_q : narrow.rresp;
|
||||||
|
assign wide.rlast = narrow.rlast;
|
||||||
|
assign wide.ruser = '0;
|
||||||
|
assign wide.rvalid = (s_read_state_q == Active) && narrow.rvalid &&
|
||||||
|
((s_read_size_q != 3'd3) || s_read_upper_q);
|
||||||
|
assign narrow.rready = (s_read_state_q == Active) &&
|
||||||
|
(((s_read_size_q == 3'd3) && !s_read_upper_q) || wide.rready);
|
||||||
|
assign s_narrow_read_accept = narrow.rvalid && narrow.rready;
|
||||||
|
assign s_wide_read_accept = wide.rvalid && wide.rready;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_read_state_d = s_read_state_q;
|
||||||
|
s_read_id_d = s_read_id_q;
|
||||||
|
s_read_size_d = s_read_size_q;
|
||||||
|
s_read_len_d = s_read_len_q;
|
||||||
|
s_read_burst_d = s_read_burst_q;
|
||||||
|
s_read_addr_d = s_read_addr_q;
|
||||||
|
s_read_upper_d = s_read_upper_q;
|
||||||
|
s_read_lower_d = s_read_lower_q;
|
||||||
|
s_read_resp_d = s_read_resp_q;
|
||||||
|
|
||||||
|
if (s_read_accept) begin
|
||||||
|
s_read_state_d = Active;
|
||||||
|
s_read_id_d = wide.arid;
|
||||||
|
s_read_size_d = wide.arsize;
|
||||||
|
s_read_len_d = wide.arlen;
|
||||||
|
s_read_burst_d = wide.arburst;
|
||||||
|
s_read_addr_d = wide.araddr;
|
||||||
|
s_read_upper_d = 1'b0;
|
||||||
|
s_read_resp_d = `AXI4_RESP_OKAY;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (s_narrow_read_accept && (s_read_size_q == 3'd3)) begin
|
||||||
|
if (!s_read_upper_q) begin
|
||||||
|
s_read_lower_d = narrow.rdata;
|
||||||
|
s_read_resp_d = narrow.rresp;
|
||||||
|
s_read_upper_d = 1'b1;
|
||||||
|
end else begin
|
||||||
|
s_read_upper_d = 1'b0;
|
||||||
|
s_read_resp_d = `AXI4_RESP_OKAY;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (s_wide_read_accept) begin
|
||||||
|
s_read_addr_d = s_read_next_addr;
|
||||||
|
if (narrow.rlast) s_read_state_d = Idle;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign wide.awready = (s_write_state_q == Idle) && narrow.awready;
|
||||||
|
assign narrow.awvalid = (s_write_state_q == Idle) && wide.awvalid;
|
||||||
|
assign narrow.awid = '0;
|
||||||
|
assign narrow.awaddr = wide.awaddr;
|
||||||
|
assign narrow.awlen = (wide.awsize == 3'd3) ? 8'((s_write_beats << 1) - 9'd1) : wide.awlen;
|
||||||
|
assign narrow.awsize = (wide.awsize == 3'd3) ? 3'd2 : wide.awsize;
|
||||||
|
assign narrow.awburst = wide.awburst;
|
||||||
|
assign narrow.awlock = wide.awlock;
|
||||||
|
assign narrow.awcache = wide.awcache;
|
||||||
|
assign narrow.awprot = wide.awprot;
|
||||||
|
assign narrow.awqos = wide.awqos;
|
||||||
|
assign narrow.awregion = wide.awregion;
|
||||||
|
assign narrow.awuser = '0;
|
||||||
|
assign s_write_addr_accept = wide.awvalid && wide.awready;
|
||||||
|
|
||||||
|
assign narrow.wdata = (s_write_size_q == 3'd3) ?
|
||||||
|
(s_write_upper_q ? wide.wdata[63:32] : wide.wdata[31:0]) :
|
||||||
|
(s_write_addr_q[2] ? wide.wdata[63:32] : wide.wdata[31:0]);
|
||||||
|
assign narrow.wstrb = (s_write_size_q == 3'd3) ?
|
||||||
|
(s_write_upper_q ? wide.wstrb[7:4] : wide.wstrb[3:0]) :
|
||||||
|
(s_write_addr_q[2] ? wide.wstrb[7:4] : wide.wstrb[3:0]);
|
||||||
|
assign narrow.wlast = wide.wlast && ((s_write_size_q != 3'd3) || s_write_upper_q);
|
||||||
|
assign narrow.wuser = '0;
|
||||||
|
assign narrow.wvalid = (s_write_state_q == Active) && wide.wvalid;
|
||||||
|
assign wide.wready = (s_write_state_q == Active) && narrow.wready &&
|
||||||
|
((s_write_size_q != 3'd3) || s_write_upper_q);
|
||||||
|
assign s_narrow_write_accept = narrow.wvalid && narrow.wready;
|
||||||
|
assign s_wide_write_accept = wide.wvalid && wide.wready;
|
||||||
|
|
||||||
|
assign wide.bid = s_write_id_q;
|
||||||
|
assign wide.bresp = s_b_resp_q;
|
||||||
|
assign wide.buser = '0;
|
||||||
|
assign wide.bvalid = s_b_pending_q;
|
||||||
|
assign narrow.bready = (s_write_state_q == Active) && !s_b_pending_q;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_write_state_d = s_write_state_q;
|
||||||
|
s_write_id_d = s_write_id_q;
|
||||||
|
s_write_size_d = s_write_size_q;
|
||||||
|
s_write_len_d = s_write_len_q;
|
||||||
|
s_write_burst_d = s_write_burst_q;
|
||||||
|
s_write_addr_d = s_write_addr_q;
|
||||||
|
s_write_upper_d = s_write_upper_q;
|
||||||
|
s_b_pending_d = s_b_pending_q;
|
||||||
|
s_b_resp_d = s_b_resp_q;
|
||||||
|
|
||||||
|
if (s_write_addr_accept) begin
|
||||||
|
s_write_state_d = Active;
|
||||||
|
s_write_id_d = wide.awid;
|
||||||
|
s_write_size_d = wide.awsize;
|
||||||
|
s_write_len_d = wide.awlen;
|
||||||
|
s_write_burst_d = wide.awburst;
|
||||||
|
s_write_addr_d = wide.awaddr;
|
||||||
|
s_write_upper_d = 1'b0;
|
||||||
|
s_b_pending_d = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (s_narrow_write_accept && (s_write_size_q == 3'd3)) begin
|
||||||
|
s_write_upper_d = !s_write_upper_q;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (s_wide_write_accept) s_write_addr_d = s_write_next_addr;
|
||||||
|
|
||||||
|
if (narrow.bvalid && narrow.bready) begin
|
||||||
|
s_b_pending_d = 1'b1;
|
||||||
|
s_b_resp_d = narrow.bresp;
|
||||||
|
end
|
||||||
|
if (wide.bvalid && wide.bready) begin
|
||||||
|
s_b_pending_d = 1'b0;
|
||||||
|
s_write_state_d = Idle;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
axi4_addr_gen #(
|
||||||
|
.ADDR_WIDTH(32)
|
||||||
|
) u_read_addr_gen (
|
||||||
|
.alen_i (s_read_len_q),
|
||||||
|
.asize_i (s_read_size_q),
|
||||||
|
.aburst_i(s_read_burst_q),
|
||||||
|
.addr_i (s_read_addr_q),
|
||||||
|
.addr_o (s_read_next_addr)
|
||||||
|
);
|
||||||
|
axi4_addr_gen #(
|
||||||
|
.ADDR_WIDTH(32)
|
||||||
|
) u_write_addr_gen (
|
||||||
|
.alen_i (s_write_len_q),
|
||||||
|
.asize_i (s_write_size_q),
|
||||||
|
.aburst_i(s_write_burst_q),
|
||||||
|
.addr_i (s_write_addr_q),
|
||||||
|
.addr_o (s_write_next_addr)
|
||||||
|
);
|
||||||
|
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_read_state_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_state_d),
|
||||||
|
.dat_o (s_read_state_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_write_state_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_state_d),
|
||||||
|
.dat_o (s_write_state_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(3)
|
||||||
|
) u_read_id_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_id_d),
|
||||||
|
.dat_o (s_read_id_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(3)
|
||||||
|
) u_write_id_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_id_d),
|
||||||
|
.dat_o (s_write_id_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(3)
|
||||||
|
) u_read_size_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_size_d),
|
||||||
|
.dat_o (s_read_size_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(3)
|
||||||
|
) u_write_size_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_size_d),
|
||||||
|
.dat_o (s_write_size_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(8)
|
||||||
|
) u_read_len_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_len_d),
|
||||||
|
.dat_o (s_read_len_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(8)
|
||||||
|
) u_write_len_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_len_d),
|
||||||
|
.dat_o (s_write_len_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(2)
|
||||||
|
) u_read_burst_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_burst_d),
|
||||||
|
.dat_o (s_read_burst_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(2)
|
||||||
|
) u_write_burst_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_burst_d),
|
||||||
|
.dat_o (s_write_burst_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_read_addr_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_addr_d),
|
||||||
|
.dat_o (s_read_addr_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_write_addr_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_addr_d),
|
||||||
|
.dat_o (s_write_addr_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_read_upper_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_upper_d),
|
||||||
|
.dat_o (s_read_upper_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_write_upper_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_upper_d),
|
||||||
|
.dat_o (s_write_upper_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(32)
|
||||||
|
) u_read_lower_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_lower_d),
|
||||||
|
.dat_o (s_read_lower_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(2)
|
||||||
|
) u_read_resp_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_read_resp_d),
|
||||||
|
.dat_o (s_read_resp_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_b_pending_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_b_pending_d),
|
||||||
|
.dat_o (s_b_pending_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(2)
|
||||||
|
) u_b_resp_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_b_resp_d),
|
||||||
|
.dat_o (s_b_resp_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
`ifndef SYNTHESIS
|
||||||
|
property p_wide_read_geometry;
|
||||||
|
@(posedge clk_i) disable iff (!rst_n_i) wide.arvalid |->
|
||||||
|
((wide.arsize <= 3'd3) &&
|
||||||
|
((wide.arsize != 3'd3) || ((wide.arlen <= 8'd7) && (wide.araddr[2:0] == 3'd0))));
|
||||||
|
endproperty
|
||||||
|
assert property (p_wide_read_geometry);
|
||||||
|
|
||||||
|
property p_wide_write_geometry;
|
||||||
|
@(posedge clk_i) disable iff (!rst_n_i) wide.awvalid |->
|
||||||
|
((wide.awsize <= 3'd3) &&
|
||||||
|
((wide.awsize != 3'd3) || ((wide.awlen <= 8'd7) && (wide.awaddr[2:0] == 3'd0))));
|
||||||
|
endproperty
|
||||||
|
assert property (p_wide_write_geometry);
|
||||||
|
`endif
|
||||||
|
endmodule
|
||||||
@@ -606,7 +606,7 @@ module axi4_interconnect #(
|
|||||||
|
|
||||||
`ifndef SYNTHESIS
|
`ifndef SYNTHESIS
|
||||||
initial begin
|
initial begin
|
||||||
if (NumMasters != 7 || ((NumTargets != 9) && (NumTargets != 10))) begin
|
if (((NumMasters != 7) && (NumMasters != 8)) || ((NumTargets != 9) && (NumTargets != 10))) begin
|
||||||
$fatal(1, "axi4_interconnect: invalid topology dimensions");
|
$fatal(1, "axi4_interconnect: invalid topology dimensions");
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||||
|
// SPDX-License-Identifier: MulanPSL-2.0
|
||||||
|
|
||||||
|
// Serializes the three HP compatibility ports onto one legacy AXI4 master.
|
||||||
|
module hp_axi4_mux3 (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_n_i,
|
||||||
|
axi4_if.slave icache,
|
||||||
|
axi4_if.slave dcache,
|
||||||
|
axi4_if.slave mmio,
|
||||||
|
axi4_if.master axi4
|
||||||
|
);
|
||||||
|
typedef enum logic {
|
||||||
|
Idle,
|
||||||
|
Active
|
||||||
|
} state_e;
|
||||||
|
|
||||||
|
state_e s_state_d, s_state_q;
|
||||||
|
logic [1:0] s_owner_d, s_owner_q;
|
||||||
|
logic s_write_d, s_write_q;
|
||||||
|
logic [1:0] s_selected;
|
||||||
|
logic s_selected_write;
|
||||||
|
logic s_addr_accept;
|
||||||
|
logic s_terminal;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_selected = 2'd0;
|
||||||
|
s_selected_write = 1'b0;
|
||||||
|
if (mmio.arvalid || mmio.awvalid) begin
|
||||||
|
s_selected = 2'd2;
|
||||||
|
s_selected_write = mmio.awvalid && !mmio.arvalid;
|
||||||
|
end else if (dcache.arvalid || dcache.awvalid) begin
|
||||||
|
s_selected = 2'd1;
|
||||||
|
s_selected_write = dcache.awvalid && !dcache.arvalid;
|
||||||
|
end else begin
|
||||||
|
s_selected = 2'd0;
|
||||||
|
s_selected_write = icache.awvalid && !icache.arvalid;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign axi4.awid = (s_state_q == Idle) ?
|
||||||
|
((s_selected == 2'd2) ? mmio.awid :
|
||||||
|
(s_selected == 2'd1) ? dcache.awid : icache.awid) : '0;
|
||||||
|
assign axi4.awaddr = (s_selected == 2'd2) ? mmio.awaddr :
|
||||||
|
(s_selected == 2'd1) ? dcache.awaddr : icache.awaddr;
|
||||||
|
assign axi4.awlen = (s_selected == 2'd2) ? mmio.awlen :
|
||||||
|
(s_selected == 2'd1) ? dcache.awlen : icache.awlen;
|
||||||
|
assign axi4.awsize = (s_selected == 2'd2) ? mmio.awsize :
|
||||||
|
(s_selected == 2'd1) ? dcache.awsize : icache.awsize;
|
||||||
|
assign axi4.awburst = (s_selected == 2'd2) ? mmio.awburst :
|
||||||
|
(s_selected == 2'd1) ? dcache.awburst : icache.awburst;
|
||||||
|
assign axi4.awlock = (s_selected == 2'd2) ? mmio.awlock :
|
||||||
|
(s_selected == 2'd1) ? dcache.awlock : icache.awlock;
|
||||||
|
assign axi4.awcache = (s_selected == 2'd2) ? mmio.awcache :
|
||||||
|
(s_selected == 2'd1) ? dcache.awcache : icache.awcache;
|
||||||
|
assign axi4.awprot = (s_selected == 2'd2) ? mmio.awprot :
|
||||||
|
(s_selected == 2'd1) ? dcache.awprot : icache.awprot;
|
||||||
|
assign axi4.awqos = (s_selected == 2'd2) ? mmio.awqos :
|
||||||
|
(s_selected == 2'd1) ? dcache.awqos : icache.awqos;
|
||||||
|
assign axi4.awregion = (s_selected == 2'd2) ? mmio.awregion :
|
||||||
|
(s_selected == 2'd1) ? dcache.awregion : icache.awregion;
|
||||||
|
assign axi4.awuser = '0;
|
||||||
|
assign axi4.awvalid = (s_state_q == Idle) && s_selected_write &&
|
||||||
|
((s_selected == 2'd2) ? mmio.awvalid :
|
||||||
|
(s_selected == 2'd1) ? dcache.awvalid : icache.awvalid);
|
||||||
|
|
||||||
|
assign mmio.awready = (s_state_q == Idle) && (s_selected == 2'd2) &&
|
||||||
|
s_selected_write && axi4.awready;
|
||||||
|
assign dcache.awready = (s_state_q == Idle) && (s_selected == 2'd1) &&
|
||||||
|
s_selected_write && axi4.awready;
|
||||||
|
assign icache.awready = (s_state_q == Idle) && (s_selected == 2'd0) &&
|
||||||
|
s_selected_write && axi4.awready;
|
||||||
|
|
||||||
|
assign axi4.arid = (s_selected == 2'd2) ? mmio.arid :
|
||||||
|
(s_selected == 2'd1) ? dcache.arid : icache.arid;
|
||||||
|
assign axi4.araddr = (s_selected == 2'd2) ? mmio.araddr :
|
||||||
|
(s_selected == 2'd1) ? dcache.araddr : icache.araddr;
|
||||||
|
assign axi4.arlen = (s_selected == 2'd2) ? mmio.arlen :
|
||||||
|
(s_selected == 2'd1) ? dcache.arlen : icache.arlen;
|
||||||
|
assign axi4.arsize = (s_selected == 2'd2) ? mmio.arsize :
|
||||||
|
(s_selected == 2'd1) ? dcache.arsize : icache.arsize;
|
||||||
|
assign axi4.arburst = (s_selected == 2'd2) ? mmio.arburst :
|
||||||
|
(s_selected == 2'd1) ? dcache.arburst : icache.arburst;
|
||||||
|
assign axi4.arlock = (s_selected == 2'd2) ? mmio.arlock :
|
||||||
|
(s_selected == 2'd1) ? dcache.arlock : icache.arlock;
|
||||||
|
assign axi4.arcache = (s_selected == 2'd2) ? mmio.arcache :
|
||||||
|
(s_selected == 2'd1) ? dcache.arcache : icache.arcache;
|
||||||
|
assign axi4.arprot = (s_selected == 2'd2) ? mmio.arprot :
|
||||||
|
(s_selected == 2'd1) ? dcache.arprot : icache.arprot;
|
||||||
|
assign axi4.arqos = (s_selected == 2'd2) ? mmio.arqos :
|
||||||
|
(s_selected == 2'd1) ? dcache.arqos : icache.arqos;
|
||||||
|
assign axi4.arregion = (s_selected == 2'd2) ? mmio.arregion :
|
||||||
|
(s_selected == 2'd1) ? dcache.arregion : icache.arregion;
|
||||||
|
assign axi4.aruser = '0;
|
||||||
|
assign axi4.arvalid = (s_state_q == Idle) && !s_selected_write &&
|
||||||
|
((s_selected == 2'd2) ? mmio.arvalid :
|
||||||
|
(s_selected == 2'd1) ? dcache.arvalid : icache.arvalid);
|
||||||
|
|
||||||
|
assign mmio.arready = (s_state_q == Idle) && (s_selected == 2'd2) &&
|
||||||
|
!s_selected_write && axi4.arready;
|
||||||
|
assign dcache.arready = (s_state_q == Idle) && (s_selected == 2'd1) &&
|
||||||
|
!s_selected_write && axi4.arready;
|
||||||
|
assign icache.arready = (s_state_q == Idle) && (s_selected == 2'd0) &&
|
||||||
|
!s_selected_write && axi4.arready;
|
||||||
|
|
||||||
|
assign axi4.wdata = (s_owner_q == 2'd2) ? mmio.wdata :
|
||||||
|
(s_owner_q == 2'd1) ? dcache.wdata : icache.wdata;
|
||||||
|
assign axi4.wstrb = (s_owner_q == 2'd2) ? mmio.wstrb :
|
||||||
|
(s_owner_q == 2'd1) ? dcache.wstrb : icache.wstrb;
|
||||||
|
assign axi4.wlast = (s_owner_q == 2'd2) ? mmio.wlast :
|
||||||
|
(s_owner_q == 2'd1) ? dcache.wlast : icache.wlast;
|
||||||
|
assign axi4.wuser = '0;
|
||||||
|
assign axi4.wvalid = (s_state_q == Active) && s_write_q &&
|
||||||
|
((s_owner_q == 2'd2) ? mmio.wvalid :
|
||||||
|
(s_owner_q == 2'd1) ? dcache.wvalid : icache.wvalid);
|
||||||
|
assign mmio.wready = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd2) && axi4.wready;
|
||||||
|
assign dcache.wready = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd1) && axi4.wready;
|
||||||
|
assign icache.wready = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd0) && axi4.wready;
|
||||||
|
|
||||||
|
assign mmio.bid = axi4.bid;
|
||||||
|
assign dcache.bid = axi4.bid;
|
||||||
|
assign icache.bid = axi4.bid;
|
||||||
|
assign mmio.bresp = axi4.bresp;
|
||||||
|
assign dcache.bresp = axi4.bresp;
|
||||||
|
assign icache.bresp = axi4.bresp;
|
||||||
|
assign mmio.buser = '0;
|
||||||
|
assign dcache.buser = '0;
|
||||||
|
assign icache.buser = '0;
|
||||||
|
assign mmio.bvalid = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd2) && axi4.bvalid;
|
||||||
|
assign dcache.bvalid = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd1) && axi4.bvalid;
|
||||||
|
assign icache.bvalid = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd0) && axi4.bvalid;
|
||||||
|
assign axi4.bready = ((s_state_q == Active) && s_write_q) ?
|
||||||
|
((s_owner_q == 2'd2) ? mmio.bready :
|
||||||
|
(s_owner_q == 2'd1) ? dcache.bready : icache.bready) : 1'b0;
|
||||||
|
|
||||||
|
assign mmio.rid = axi4.rid;
|
||||||
|
assign dcache.rid = axi4.rid;
|
||||||
|
assign icache.rid = axi4.rid;
|
||||||
|
assign mmio.rdata = axi4.rdata;
|
||||||
|
assign dcache.rdata = axi4.rdata;
|
||||||
|
assign icache.rdata = axi4.rdata;
|
||||||
|
assign mmio.rresp = axi4.rresp;
|
||||||
|
assign dcache.rresp = axi4.rresp;
|
||||||
|
assign icache.rresp = axi4.rresp;
|
||||||
|
assign mmio.rlast = axi4.rlast;
|
||||||
|
assign dcache.rlast = axi4.rlast;
|
||||||
|
assign icache.rlast = axi4.rlast;
|
||||||
|
assign mmio.ruser = '0;
|
||||||
|
assign dcache.ruser = '0;
|
||||||
|
assign icache.ruser = '0;
|
||||||
|
assign mmio.rvalid = (s_state_q == Active) && !s_write_q && (s_owner_q == 2'd2) && axi4.rvalid;
|
||||||
|
assign dcache.rvalid = (s_state_q == Active) && !s_write_q && (s_owner_q == 2'd1) && axi4.rvalid;
|
||||||
|
assign icache.rvalid = (s_state_q == Active) && !s_write_q && (s_owner_q == 2'd0) && axi4.rvalid;
|
||||||
|
assign axi4.rready = ((s_state_q == Active) && !s_write_q) ?
|
||||||
|
((s_owner_q == 2'd2) ? mmio.rready :
|
||||||
|
(s_owner_q == 2'd1) ? dcache.rready : icache.rready) : 1'b0;
|
||||||
|
|
||||||
|
assign s_addr_accept = (axi4.awvalid && axi4.awready) || (axi4.arvalid && axi4.arready);
|
||||||
|
assign s_terminal = (s_write_q && axi4.bvalid && axi4.bready) ||
|
||||||
|
(!s_write_q && axi4.rvalid && axi4.rready && axi4.rlast);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
s_state_d = s_state_q;
|
||||||
|
s_owner_d = s_owner_q;
|
||||||
|
s_write_d = s_write_q;
|
||||||
|
if ((s_state_q == Idle) && s_addr_accept) begin
|
||||||
|
s_state_d = Active;
|
||||||
|
s_owner_d = s_selected;
|
||||||
|
s_write_d = axi4.awvalid && axi4.awready;
|
||||||
|
end
|
||||||
|
if ((s_state_q == Active) && s_terminal) s_state_d = Idle;
|
||||||
|
end
|
||||||
|
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_state_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_state_d),
|
||||||
|
.dat_o (s_state_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(2)
|
||||||
|
) u_owner_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_owner_d),
|
||||||
|
.dat_o (s_owner_q)
|
||||||
|
);
|
||||||
|
dffr #(
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_write_dffr (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.dat_i (s_write_d),
|
||||||
|
.dat_o (s_write_q)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||||
|
// SPDX-License-Identifier: MulanPSL-2.0
|
||||||
|
|
||||||
|
`include "axi4_define.svh"
|
||||||
|
|
||||||
|
module hp_core_wrapper (
|
||||||
|
// verilog_format: off -- preserve generated-core boundary alignment
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_n_i,
|
||||||
|
input logic core_reset_i,
|
||||||
|
input logic [63:0] time_i,
|
||||||
|
input logic timer_irq_i,
|
||||||
|
input logic software_irq_i,
|
||||||
|
input logic machine_external_irq_i,
|
||||||
|
input logic supervisor_external_irq_i,
|
||||||
|
input logic jtag_tck_i,
|
||||||
|
input logic jtag_tms_i,
|
||||||
|
input logic jtag_tdi_i,
|
||||||
|
input logic jtag_trst_n_i,
|
||||||
|
output logic jtag_tdo_o,
|
||||||
|
output logic debug_reset_req_o,
|
||||||
|
axi4_if.master icache_axi4,
|
||||||
|
axi4_if.master dcache_axi4,
|
||||||
|
axi4_if.master mmio_axi4
|
||||||
|
// verilog_format: on
|
||||||
|
);
|
||||||
|
logic s_unused_debug_stoptime;
|
||||||
|
|
||||||
|
assign icache_axi4.awid = '0;
|
||||||
|
assign icache_axi4.awaddr = '0;
|
||||||
|
assign icache_axi4.awlen = '0;
|
||||||
|
assign icache_axi4.awsize = '0;
|
||||||
|
assign icache_axi4.awburst = '0;
|
||||||
|
assign icache_axi4.awlock = '0;
|
||||||
|
assign icache_axi4.awcache = '0;
|
||||||
|
assign icache_axi4.awprot = '0;
|
||||||
|
assign icache_axi4.awqos = '0;
|
||||||
|
assign icache_axi4.awregion = '0;
|
||||||
|
assign icache_axi4.awuser = '0;
|
||||||
|
assign icache_axi4.awvalid = 1'b0;
|
||||||
|
assign icache_axi4.wdata = '0;
|
||||||
|
assign icache_axi4.wstrb = '0;
|
||||||
|
assign icache_axi4.wlast = 1'b0;
|
||||||
|
assign icache_axi4.wuser = '0;
|
||||||
|
assign icache_axi4.wvalid = 1'b0;
|
||||||
|
assign icache_axi4.bready = 1'b1;
|
||||||
|
|
||||||
|
// verilog_format: off -- generated VexiiRiscv ports are upstream ABI
|
||||||
|
vexii_riscv_hp_generated u_vexii_riscv_hp_generated (
|
||||||
|
.EmbeddedRiscvJtag_logic_jtag_tms (jtag_tms_i),
|
||||||
|
.EmbeddedRiscvJtag_logic_jtag_tdi (jtag_tdi_i),
|
||||||
|
.EmbeddedRiscvJtag_logic_jtag_tdo (jtag_tdo_o),
|
||||||
|
.EmbeddedRiscvJtag_logic_jtag_tck (jtag_tck_i),
|
||||||
|
.EmbeddedRiscvJtag_logic_ndmreset (debug_reset_req_o),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_valid (dcache_axi4.awvalid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_ready (dcache_axi4.awready),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_payload_addr (dcache_axi4.awaddr),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_payload_id (dcache_axi4.awid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_payload_len (dcache_axi4.awlen),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_payload_size (dcache_axi4.awsize),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_payload_burst (dcache_axi4.awburst),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_payload_cache (dcache_axi4.awcache),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_aw_payload_prot (dcache_axi4.awprot),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_w_valid (dcache_axi4.wvalid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_w_ready (dcache_axi4.wready),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_w_payload_data (dcache_axi4.wdata),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_w_payload_strb (dcache_axi4.wstrb),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_w_payload_last (dcache_axi4.wlast),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_b_valid (dcache_axi4.bvalid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_b_ready (dcache_axi4.bready),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_b_payload_id (dcache_axi4.bid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_b_payload_resp (dcache_axi4.bresp),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_valid (dcache_axi4.arvalid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_ready (dcache_axi4.arready),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_payload_addr (dcache_axi4.araddr),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_payload_id (dcache_axi4.arid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_payload_len (dcache_axi4.arlen),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_payload_size (dcache_axi4.arsize),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_payload_burst (dcache_axi4.arburst),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_payload_cache (dcache_axi4.arcache),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_ar_payload_prot (dcache_axi4.arprot),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_r_valid (dcache_axi4.rvalid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_r_ready (dcache_axi4.rready),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_r_payload_data (dcache_axi4.rdata),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_r_payload_id (dcache_axi4.rid),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_r_payload_resp (dcache_axi4.rresp),
|
||||||
|
.LsuL1Axi4Plugin_logic_axi_r_payload_last (dcache_axi4.rlast),
|
||||||
|
.PrivilegedPlugin_logic_rdtime (time_i),
|
||||||
|
.PrivilegedPlugin_logic_harts_0_int_m_timer (timer_irq_i),
|
||||||
|
.PrivilegedPlugin_logic_harts_0_int_m_software (software_irq_i),
|
||||||
|
.PrivilegedPlugin_logic_harts_0_int_m_external (machine_external_irq_i),
|
||||||
|
.PrivilegedPlugin_logic_harts_0_int_s_external (supervisor_external_irq_i),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_valid (icache_axi4.arvalid),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_ready (icache_axi4.arready),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_payload_addr (icache_axi4.araddr),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_payload_id (icache_axi4.arid[0]),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_payload_len (icache_axi4.arlen),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_payload_size (icache_axi4.arsize),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_payload_burst (icache_axi4.arburst),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_payload_cache (icache_axi4.arcache),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_ar_payload_prot (icache_axi4.arprot),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_r_valid (icache_axi4.rvalid),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_r_ready (icache_axi4.rready),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_r_payload_data (icache_axi4.rdata),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_r_payload_id (icache_axi4.rid[0]),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_r_payload_resp (icache_axi4.rresp),
|
||||||
|
.FetchL1Axi4Plugin_logic_axi_r_payload_last (icache_axi4.rlast),
|
||||||
|
.PrivilegedPlugin_logic_harts_0_debug_stoptime (s_unused_debug_stoptime),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_aw_valid (mmio_axi4.awvalid),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_aw_ready (mmio_axi4.awready),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_aw_payload_addr (mmio_axi4.awaddr),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_aw_payload_size (mmio_axi4.awsize),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_aw_payload_cache (mmio_axi4.awcache),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_aw_payload_prot (mmio_axi4.awprot),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_w_valid (mmio_axi4.wvalid),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_w_ready (mmio_axi4.wready),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_w_payload_data (mmio_axi4.wdata),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_w_payload_strb (mmio_axi4.wstrb),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_w_payload_last (mmio_axi4.wlast),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_b_valid (mmio_axi4.bvalid),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_b_ready (mmio_axi4.bready),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_b_payload_resp (mmio_axi4.bresp),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_ar_valid (mmio_axi4.arvalid),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_ar_ready (mmio_axi4.arready),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_ar_payload_addr (mmio_axi4.araddr),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_ar_payload_size (mmio_axi4.arsize),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_ar_payload_cache (mmio_axi4.arcache),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_ar_payload_prot (mmio_axi4.arprot),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_r_valid (mmio_axi4.rvalid),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_r_ready (mmio_axi4.rready),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_r_payload_data (mmio_axi4.rdata),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_r_payload_resp (mmio_axi4.rresp),
|
||||||
|
.LsuCachelessAxi4Plugin_logic_axi_r_payload_last (mmio_axi4.rlast),
|
||||||
|
.clk (clk_i),
|
||||||
|
.reset (!rst_n_i || core_reset_i),
|
||||||
|
.EmbeddedRiscvJtag_logic_debug_reset (!jtag_trst_n_i)
|
||||||
|
);
|
||||||
|
// verilog_format: on
|
||||||
|
|
||||||
|
assign icache_axi4.arid[2:1] = '0;
|
||||||
|
assign icache_axi4.arlock = 1'b0;
|
||||||
|
assign icache_axi4.arqos = '0;
|
||||||
|
assign icache_axi4.arregion = '0;
|
||||||
|
assign icache_axi4.aruser = '0;
|
||||||
|
assign dcache_axi4.awlock = 1'b0;
|
||||||
|
assign dcache_axi4.awqos = '0;
|
||||||
|
assign dcache_axi4.awregion = '0;
|
||||||
|
assign dcache_axi4.awuser = '0;
|
||||||
|
assign dcache_axi4.wuser = '0;
|
||||||
|
assign dcache_axi4.arlock = 1'b0;
|
||||||
|
assign dcache_axi4.arqos = '0;
|
||||||
|
assign dcache_axi4.arregion = '0;
|
||||||
|
assign dcache_axi4.aruser = '0;
|
||||||
|
assign mmio_axi4.awid = '0;
|
||||||
|
assign mmio_axi4.awlen = '0;
|
||||||
|
assign mmio_axi4.awburst = `AXI4_BURST_TYPE_INCR;
|
||||||
|
assign mmio_axi4.awlock = 1'b0;
|
||||||
|
assign mmio_axi4.awqos = '0;
|
||||||
|
assign mmio_axi4.awregion = '0;
|
||||||
|
assign mmio_axi4.awuser = '0;
|
||||||
|
assign mmio_axi4.wuser = '0;
|
||||||
|
assign mmio_axi4.arid = '0;
|
||||||
|
assign mmio_axi4.arlen = '0;
|
||||||
|
assign mmio_axi4.arburst = `AXI4_BURST_TYPE_INCR;
|
||||||
|
assign mmio_axi4.arlock = 1'b0;
|
||||||
|
assign mmio_axi4.arqos = '0;
|
||||||
|
assign mmio_axi4.arregion = '0;
|
||||||
|
assign mmio_axi4.aruser = '0;
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||||
|
// SPDX-License-Identifier: MulanPSL-2.0
|
||||||
|
|
||||||
|
module hp_subsystem (
|
||||||
|
// verilog_format: off -- preserve HP integration boundary alignment
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_n_i,
|
||||||
|
input logic core_reset_i,
|
||||||
|
input logic [63:0] time_i,
|
||||||
|
input logic timer_irq_i,
|
||||||
|
input logic software_irq_i,
|
||||||
|
input logic machine_external_irq_i,
|
||||||
|
input logic supervisor_external_irq_i,
|
||||||
|
input logic jtag_tck_i,
|
||||||
|
input logic jtag_tms_i,
|
||||||
|
input logic jtag_tdi_i,
|
||||||
|
input logic jtag_trst_n_i,
|
||||||
|
output logic jtag_tdo_o,
|
||||||
|
output logic debug_reset_req_o,
|
||||||
|
axi4_if.master axi4
|
||||||
|
// verilog_format: on
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(64),
|
||||||
|
.ID_WIDTH (3),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) u_icache_wide_axi4_if (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(64),
|
||||||
|
.ID_WIDTH (3),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) u_dcache_wide_axi4_if (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(64),
|
||||||
|
.ID_WIDTH (3),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) u_mmio_wide_axi4_if (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(32),
|
||||||
|
.ID_WIDTH (1),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) u_icache_narrow_axi4_if (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(32),
|
||||||
|
.ID_WIDTH (1),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) u_dcache_narrow_axi4_if (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(32),
|
||||||
|
.ID_WIDTH (1),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) u_mmio_narrow_axi4_if (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(32),
|
||||||
|
.ID_WIDTH (1),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) u_hp_mux_axi4_if (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
|
||||||
|
hp_core_wrapper u_hp_core_wrapper (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i (rst_n_i),
|
||||||
|
.core_reset_i (core_reset_i),
|
||||||
|
.time_i (time_i),
|
||||||
|
.timer_irq_i (timer_irq_i),
|
||||||
|
.software_irq_i (software_irq_i),
|
||||||
|
.machine_external_irq_i (machine_external_irq_i),
|
||||||
|
.supervisor_external_irq_i(supervisor_external_irq_i),
|
||||||
|
.jtag_tck_i (jtag_tck_i),
|
||||||
|
.jtag_tms_i (jtag_tms_i),
|
||||||
|
.jtag_tdi_i (jtag_tdi_i),
|
||||||
|
.jtag_trst_n_i (jtag_trst_n_i),
|
||||||
|
.jtag_tdo_o (jtag_tdo_o),
|
||||||
|
.debug_reset_req_o (debug_reset_req_o),
|
||||||
|
.icache_axi4 (u_icache_wide_axi4_if),
|
||||||
|
.dcache_axi4 (u_dcache_wide_axi4_if),
|
||||||
|
.mmio_axi4 (u_mmio_wide_axi4_if)
|
||||||
|
);
|
||||||
|
|
||||||
|
axi4_downsizer_64to32 u_icache_downsizer (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.wide (u_icache_wide_axi4_if),
|
||||||
|
.narrow (u_icache_narrow_axi4_if)
|
||||||
|
);
|
||||||
|
axi4_downsizer_64to32 u_dcache_downsizer (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.wide (u_dcache_wide_axi4_if),
|
||||||
|
.narrow (u_dcache_narrow_axi4_if)
|
||||||
|
);
|
||||||
|
axi4_downsizer_64to32 u_mmio_downsizer (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.wide (u_mmio_wide_axi4_if),
|
||||||
|
.narrow (u_mmio_narrow_axi4_if)
|
||||||
|
);
|
||||||
|
|
||||||
|
hp_axi4_mux3 u_hp_axi4_mux3 (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.icache (u_icache_narrow_axi4_if),
|
||||||
|
.dcache (u_dcache_narrow_axi4_if),
|
||||||
|
.mmio (u_mmio_narrow_axi4_if),
|
||||||
|
.axi4 (u_hp_mux_axi4_if)
|
||||||
|
);
|
||||||
|
|
||||||
|
axi4_regslice #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(32),
|
||||||
|
.ID_WIDTH (1),
|
||||||
|
.USER_WIDTH(1),
|
||||||
|
.BYPASS (1'b0)
|
||||||
|
) u_hp_axi4_regslice (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.flush_i(core_reset_i),
|
||||||
|
.slv (u_hp_mux_axi4_if),
|
||||||
|
.mst (axi4)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
+134
-40
@@ -25,6 +25,8 @@ module retrosoc (
|
|||||||
gpio_if.soc_pad gpio,
|
gpio_if.soc_pad gpio,
|
||||||
input logic uart_rx_i,
|
input logic uart_rx_i,
|
||||||
output logic uart_tx_o,
|
output logic uart_tx_o,
|
||||||
|
input logic uart1_rx_i,
|
||||||
|
output logic uart1_tx_o,
|
||||||
xpi_if.dut xpi,
|
xpi_if.dut xpi,
|
||||||
sdram_if.dut sdram,
|
sdram_if.dut sdram,
|
||||||
sdio_if.dut sdio1,
|
sdio_if.dut sdio1,
|
||||||
@@ -58,10 +60,13 @@ module retrosoc (
|
|||||||
u_spisd_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
|
u_spisd_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
|
||||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||||
u_opipsram_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
|
u_opipsram_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
|
||||||
|
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||||
|
u_hp_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
|
||||||
user_gpio_if u_user_gpio_if ();
|
user_gpio_if u_user_gpio_if ();
|
||||||
// ip interface
|
// ip interface
|
||||||
gpio_if u_gpio_if ();
|
gpio_if u_gpio_if ();
|
||||||
uart_if u_uart0_if ();
|
uart_if u_uart0_if ();
|
||||||
|
uart_if u_uart1_if ();
|
||||||
psram_if u_psram_if ();
|
psram_if u_psram_if ();
|
||||||
spi_if u_spisd_if ();
|
spi_if u_spisd_if ();
|
||||||
i2c_if u_i2c0_if ();
|
i2c_if u_i2c0_if ();
|
||||||
@@ -103,6 +108,15 @@ module retrosoc (
|
|||||||
logic [ 63:0] s_perf_opipsram_wait;
|
logic [ 63:0] s_perf_opipsram_wait;
|
||||||
logic [ `SOC_IRQ_VECTOR_WIDTH-1:0] s_user_irq;
|
logic [ `SOC_IRQ_VECTOR_WIDTH-1:0] s_user_irq;
|
||||||
logic s_rtc_wake;
|
logic s_rtc_wake;
|
||||||
|
logic s_hp_jtag_tdo;
|
||||||
|
logic s_hp_debug_reset_req;
|
||||||
|
logic s_lp_jtag_tdo;
|
||||||
|
logic s_debug_hp_sel_jtag;
|
||||||
|
logic [ 63:0] s_hp_time;
|
||||||
|
logic s_hp_timer_irq;
|
||||||
|
logic s_hp_software_irq;
|
||||||
|
logic s_hp_machine_external_irq;
|
||||||
|
logic s_hp_supervisor_external_irq;
|
||||||
|
|
||||||
`ifdef HAVE_SRAM_IF
|
`ifdef HAVE_SRAM_IF
|
||||||
localparam bit SramPresent = 1'b1;
|
localparam bit SramPresent = 1'b1;
|
||||||
@@ -131,8 +145,15 @@ module retrosoc (
|
|||||||
assign u_sysctrl_if.perf_psram_wait_i = s_perf_psram_wait + s_perf_opipsram_wait;
|
assign u_sysctrl_if.perf_psram_wait_i = s_perf_psram_wait + s_perf_opipsram_wait;
|
||||||
assign u_sysctrl_if.perf_flash_wait_i = s_perf_flash_wait;
|
assign u_sysctrl_if.perf_flash_wait_i = s_perf_flash_wait;
|
||||||
assign u_sysctrl_if.rtc_wake_i = s_rtc_wake;
|
assign u_sysctrl_if.rtc_wake_i = s_rtc_wake;
|
||||||
assign u_uart0_if.rx_i = uart_rx_i;
|
`ifdef HAVE_HP
|
||||||
assign uart_tx_o = u_uart0_if.tx_o;
|
assign u_sysctrl_if.hp_present_i = 1'b1;
|
||||||
|
`else
|
||||||
|
assign u_sysctrl_if.hp_present_i = 1'b0;
|
||||||
|
`endif
|
||||||
|
assign u_uart0_if.rx_i = uart_rx_i;
|
||||||
|
assign uart_tx_o = u_uart0_if.tx_o;
|
||||||
|
assign u_uart1_if.rx_i = uart1_rx_i;
|
||||||
|
assign uart1_tx_o = u_uart1_if.tx_o;
|
||||||
|
|
||||||
gpio_pad_bridge u_gpio_pad_bridge (
|
gpio_pad_bridge u_gpio_pad_bridge (
|
||||||
.inner(u_gpio_if),
|
.inner(u_gpio_if),
|
||||||
@@ -151,13 +172,25 @@ core_wrapper u_core_wrapper (
|
|||||||
`include "soc_mgmt_core_wrapper_fabric.svh"
|
`include "soc_mgmt_core_wrapper_fabric.svh"
|
||||||
.irq_i (s_irq),
|
.irq_i (s_irq),
|
||||||
.jtag_tck_i (jtag_tck_i),
|
.jtag_tck_i (jtag_tck_i),
|
||||||
.jtag_tms_i (jtag_tms_i),
|
.jtag_tms_i (s_debug_hp_sel_jtag ? 1'b1 : jtag_tms_i),
|
||||||
.jtag_tdi_i (jtag_tdi_i),
|
.jtag_tdi_i (s_debug_hp_sel_jtag ? 1'b0 : jtag_tdi_i),
|
||||||
.jtag_trst_n_i (jtag_trst_n_i),
|
.jtag_trst_n_i (jtag_trst_n_i),
|
||||||
.jtag_tdo_o (jtag_tdo_o),
|
.jtag_tdo_o (s_lp_jtag_tdo),
|
||||||
.debug_halted_o(s_mgmt_debug_halted)
|
.debug_halted_o(s_mgmt_debug_halted)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
cdc_sync #(
|
||||||
|
.STAGE (2),
|
||||||
|
.DATA_WIDTH(1)
|
||||||
|
) u_debug_select_sync (
|
||||||
|
.clk_i (jtag_tck_i),
|
||||||
|
.rst_n_i(jtag_trst_n_i),
|
||||||
|
.dat_i (u_sysctrl_if.debug_hp_select_o),
|
||||||
|
.dat_o (s_debug_hp_sel_jtag)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign jtag_tdo_o = s_debug_hp_sel_jtag ? s_hp_jtag_tdo : s_lp_jtag_tdo;
|
||||||
|
|
||||||
assign s_user_irq = u_sysctrl_if.user_bus_enable_o ? (s_irq & `SOC_USER_IRQ_MASK) : '0;
|
assign s_user_irq = u_sysctrl_if.user_bus_enable_o ? (s_irq & `SOC_USER_IRQ_MASK) : '0;
|
||||||
user_core_top u_user_core_top (
|
user_core_top u_user_core_top (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
@@ -168,6 +201,60 @@ core_wrapper u_core_wrapper (
|
|||||||
.core_reset_i(u_sysctrl_if.core_reset_o)
|
.core_reset_i(u_sysctrl_if.core_reset_o)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
`ifdef HAVE_HP
|
||||||
|
hp_subsystem u_hp_subsystem (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i (rst_n_i),
|
||||||
|
.core_reset_i (!u_sysctrl_if.hp_release_o || s_hp_debug_reset_req),
|
||||||
|
.time_i (s_hp_time),
|
||||||
|
.timer_irq_i (s_hp_timer_irq),
|
||||||
|
.software_irq_i (s_hp_software_irq),
|
||||||
|
.machine_external_irq_i (s_hp_machine_external_irq),
|
||||||
|
.supervisor_external_irq_i(s_hp_supervisor_external_irq),
|
||||||
|
.jtag_tck_i (jtag_tck_i),
|
||||||
|
.jtag_tms_i (s_debug_hp_sel_jtag ? jtag_tms_i : 1'b1),
|
||||||
|
.jtag_tdi_i (s_debug_hp_sel_jtag ? jtag_tdi_i : 1'b0),
|
||||||
|
.jtag_trst_n_i (jtag_trst_n_i),
|
||||||
|
.jtag_tdo_o (s_hp_jtag_tdo),
|
||||||
|
.debug_reset_req_o (s_hp_debug_reset_req),
|
||||||
|
.axi4 (u_hp_axi4_if)
|
||||||
|
);
|
||||||
|
`else
|
||||||
|
assign u_hp_axi4_if.awid = '0;
|
||||||
|
assign u_hp_axi4_if.awaddr = '0;
|
||||||
|
assign u_hp_axi4_if.awlen = '0;
|
||||||
|
assign u_hp_axi4_if.awsize = '0;
|
||||||
|
assign u_hp_axi4_if.awburst = '0;
|
||||||
|
assign u_hp_axi4_if.awlock = '0;
|
||||||
|
assign u_hp_axi4_if.awcache = '0;
|
||||||
|
assign u_hp_axi4_if.awprot = '0;
|
||||||
|
assign u_hp_axi4_if.awqos = '0;
|
||||||
|
assign u_hp_axi4_if.awregion = '0;
|
||||||
|
assign u_hp_axi4_if.awuser = '0;
|
||||||
|
assign u_hp_axi4_if.awvalid = 1'b0;
|
||||||
|
assign u_hp_axi4_if.wdata = '0;
|
||||||
|
assign u_hp_axi4_if.wstrb = '0;
|
||||||
|
assign u_hp_axi4_if.wlast = 1'b0;
|
||||||
|
assign u_hp_axi4_if.wuser = '0;
|
||||||
|
assign u_hp_axi4_if.wvalid = 1'b0;
|
||||||
|
assign u_hp_axi4_if.bready = 1'b1;
|
||||||
|
assign u_hp_axi4_if.arid = '0;
|
||||||
|
assign u_hp_axi4_if.araddr = '0;
|
||||||
|
assign u_hp_axi4_if.arlen = '0;
|
||||||
|
assign u_hp_axi4_if.arsize = '0;
|
||||||
|
assign u_hp_axi4_if.arburst = '0;
|
||||||
|
assign u_hp_axi4_if.arlock = '0;
|
||||||
|
assign u_hp_axi4_if.arcache = '0;
|
||||||
|
assign u_hp_axi4_if.arprot = '0;
|
||||||
|
assign u_hp_axi4_if.arqos = '0;
|
||||||
|
assign u_hp_axi4_if.arregion = '0;
|
||||||
|
assign u_hp_axi4_if.aruser = '0;
|
||||||
|
assign u_hp_axi4_if.arvalid = 1'b0;
|
||||||
|
assign u_hp_axi4_if.rready = 1'b1;
|
||||||
|
assign s_hp_jtag_tdo = 1'b0;
|
||||||
|
assign s_hp_debug_reset_req = 1'b0;
|
||||||
|
`endif
|
||||||
|
|
||||||
onchip_ram #(
|
onchip_ram #(
|
||||||
.Present (SramPresent),
|
.Present (SramPresent),
|
||||||
.CapacityKiB(`SOC_ADDR_SRAM_SIZE >> 10)
|
.CapacityKiB(`SOC_ADDR_SRAM_SIZE >> 10)
|
||||||
@@ -187,6 +274,7 @@ core_wrapper u_core_wrapper (
|
|||||||
.user_bus_enable_i (u_sysctrl_if.user_bus_enable_o),
|
.user_bus_enable_i (u_sysctrl_if.user_bus_enable_o),
|
||||||
.user_bus_idle_o (u_sysctrl_if.user_bus_idle_i),
|
.user_bus_idle_o (u_sysctrl_if.user_bus_idle_i),
|
||||||
`include "soc_bus_fabric.svh"
|
`include "soc_bus_fabric.svh"
|
||||||
|
.hp_axi4 (u_hp_axi4_if),
|
||||||
.sdram_axi4 (u_sdram_axi4_if),
|
.sdram_axi4 (u_sdram_axi4_if),
|
||||||
.psram_axi4 (u_psram_axi4_if),
|
.psram_axi4 (u_psram_axi4_if),
|
||||||
.xpi_axi4 (u_xpi_axi4_if),
|
.xpi_axi4 (u_xpi_axi4_if),
|
||||||
@@ -216,42 +304,48 @@ core_wrapper u_core_wrapper (
|
|||||||
);
|
);
|
||||||
|
|
||||||
apb4_periph u_apb4_periph (
|
apb4_periph u_apb4_periph (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
.rst_n_i (rst_n_i),
|
.rst_n_i (rst_n_i),
|
||||||
.clk_aud_i (clk_aud_i),
|
.clk_aud_i (clk_aud_i),
|
||||||
.rst_aud_n_i (rst_aud_n_i),
|
.rst_aud_n_i (rst_aud_n_i),
|
||||||
.clk_ulpi_i (clk_ulpi_i),
|
.clk_ulpi_i (clk_ulpi_i),
|
||||||
.debug_halted_i (s_mgmt_debug_halted),
|
.debug_halted_i (s_mgmt_debug_halted),
|
||||||
.timebase_tick_i (timebase_tick_i),
|
.timebase_tick_i (timebase_tick_i),
|
||||||
`include "apb4_periph_fabric.svh"
|
`include "apb4_periph_fabric.svh"
|
||||||
.psram_axi4 (u_psram_axi4_if),
|
.psram_axi4 (u_psram_axi4_if),
|
||||||
.xpi_axi4 (u_xpi_axi4_if),
|
.xpi_axi4 (u_xpi_axi4_if),
|
||||||
.spisd_axi4 (u_spisd_axi4_if),
|
.spisd_axi4 (u_spisd_axi4_if),
|
||||||
.opipsram_axi4 (u_opipsram_axi4_if),
|
.opipsram_axi4 (u_opipsram_axi4_if),
|
||||||
.gpio (u_gpio_if),
|
.gpio (u_gpio_if),
|
||||||
.user_gpio (u_user_gpio_if),
|
.user_gpio (u_user_gpio_if),
|
||||||
.uart (u_uart0_if),
|
.uart (u_uart0_if),
|
||||||
.psram (u_psram_if),
|
.uart1 (u_uart1_if),
|
||||||
.spisd (u_spisd_if),
|
.psram (u_psram_if),
|
||||||
.i2c0 (u_i2c0_if),
|
.spisd (u_spisd_if),
|
||||||
.i2s (u_i2s_if),
|
.i2c0 (u_i2c0_if),
|
||||||
.ws2812 (u_ws2812_if),
|
.i2s (u_i2s_if),
|
||||||
.xpi (xpi),
|
.ws2812 (u_ws2812_if),
|
||||||
.sysctrl (u_sysctrl_if),
|
.xpi (xpi),
|
||||||
.pll_ctrl (pll_ctrl),
|
.sysctrl (u_sysctrl_if),
|
||||||
.sdram_cfg (u_sdram_cfg_if),
|
.pll_ctrl (pll_ctrl),
|
||||||
.sram_cfg (u_sram_cfg_if),
|
.sdram_cfg (u_sdram_cfg_if),
|
||||||
.dvp (u_dvp_if),
|
.sram_cfg (u_sram_cfg_if),
|
||||||
.sdio0 (u_sdio0_if),
|
.dvp (u_dvp_if),
|
||||||
.sdio1 (sdio1),
|
.sdio0 (u_sdio0_if),
|
||||||
.usb2 (usb2),
|
.sdio1 (sdio1),
|
||||||
.opipsram (u_opipsram_if),
|
.usb2 (usb2),
|
||||||
.i2c1 (u_i2c1_if),
|
.opipsram (u_opipsram_if),
|
||||||
.fault_valid_i (s_bus_fault_valid),
|
.i2c1 (u_i2c1_if),
|
||||||
.fault_addr_i (s_bus_fault_addr),
|
.fault_valid_i (s_bus_fault_valid),
|
||||||
.fault_wstrb_i (s_bus_fault_wstrb),
|
.fault_addr_i (s_bus_fault_addr),
|
||||||
.fault_reserved_i(s_bus_fault_reserved),
|
.fault_wstrb_i (s_bus_fault_wstrb),
|
||||||
.irq_o (s_apb4_periph_irq)
|
.fault_reserved_i (s_bus_fault_reserved),
|
||||||
|
.hp_time_o (s_hp_time),
|
||||||
|
.hp_timer_irq_o (s_hp_timer_irq),
|
||||||
|
.hp_software_irq_o (s_hp_software_irq),
|
||||||
|
.hp_machine_external_irq_o (s_hp_machine_external_irq),
|
||||||
|
.hp_supervisor_external_irq_o(s_hp_supervisor_external_irq),
|
||||||
|
.irq_o (s_apb4_periph_irq)
|
||||||
);
|
);
|
||||||
|
|
||||||
axi4_sdram u_axi4_sdram (
|
axi4_sdram u_axi4_sdram (
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ module retrosoc_asic (
|
|||||||
logic s_jtag_tdo;
|
logic s_jtag_tdo;
|
||||||
logic s_uart0_rx;
|
logic s_uart0_rx;
|
||||||
logic s_uart0_tx;
|
logic s_uart0_tx;
|
||||||
|
logic s_uart1_rx;
|
||||||
|
logic s_uart1_tx;
|
||||||
logic s_usb2_ulpi_clk;
|
logic s_usb2_ulpi_clk;
|
||||||
(* keep = "true" *)logic s_test_done;
|
(* keep = "true" *)logic s_test_done;
|
||||||
(* keep = "true" *)logic s_test_pass;
|
(* keep = "true" *)logic s_test_pass;
|
||||||
@@ -123,6 +125,8 @@ rcu #(
|
|||||||
.gpio (u_gpio_if),
|
.gpio (u_gpio_if),
|
||||||
.uart_rx_i (s_uart0_rx),
|
.uart_rx_i (s_uart0_rx),
|
||||||
.uart_tx_o (s_uart0_tx),
|
.uart_tx_o (s_uart0_tx),
|
||||||
|
.uart1_rx_i (s_uart1_rx),
|
||||||
|
.uart1_tx_o (s_uart1_tx),
|
||||||
.xpi (u_xpi_if),
|
.xpi (u_xpi_if),
|
||||||
.sdram (u_sdram_if),
|
.sdram (u_sdram_if),
|
||||||
.sdio1 (u_sdio1_if),
|
.sdio1 (u_sdio1_if),
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ module retrosoc_core (
|
|||||||
logic s_jtag_tdo;
|
logic s_jtag_tdo;
|
||||||
logic s_uart0_rx;
|
logic s_uart0_rx;
|
||||||
logic s_uart0_tx;
|
logic s_uart0_tx;
|
||||||
|
logic s_uart1_rx;
|
||||||
|
logic s_uart1_tx;
|
||||||
logic s_usb2_ulpi_clk;
|
logic s_usb2_ulpi_clk;
|
||||||
(* keep = "true" *)logic s_test_done;
|
(* keep = "true" *)logic s_test_done;
|
||||||
(* keep = "true" *)logic s_test_pass;
|
(* keep = "true" *)logic s_test_pass;
|
||||||
@@ -82,6 +84,8 @@ rcu #(
|
|||||||
.gpio (u_gpio_if),
|
.gpio (u_gpio_if),
|
||||||
.uart_rx_i (s_uart0_rx),
|
.uart_rx_i (s_uart0_rx),
|
||||||
.uart_tx_o (s_uart0_tx),
|
.uart_tx_o (s_uart0_tx),
|
||||||
|
.uart1_rx_i (s_uart1_rx),
|
||||||
|
.uart1_tx_o (s_uart1_tx),
|
||||||
.xpi (u_xpi_if),
|
.xpi (u_xpi_if),
|
||||||
.sdram (u_sdram_if),
|
.sdram (u_sdram_if),
|
||||||
.sdio1 (u_sdio1_if),
|
.sdio1 (u_sdio1_if),
|
||||||
|
|||||||
@@ -142,6 +142,8 @@
|
|||||||
"apb4_clint.sv",
|
"apb4_clint.sv",
|
||||||
"apb4_dma.sv",
|
"apb4_dma.sv",
|
||||||
"apb4_gpio.sv",
|
"apb4_gpio.sv",
|
||||||
|
"apb4_hp_mailbox.sv",
|
||||||
|
"apb4_plic.sv",
|
||||||
"apb4_sysctrl.sv",
|
"apb4_sysctrl.sv",
|
||||||
"apb4_timer.sv",
|
"apb4_timer.sv",
|
||||||
"clint_core.sv",
|
"clint_core.sv",
|
||||||
@@ -159,6 +161,7 @@
|
|||||||
"gpio_define.svh",
|
"gpio_define.svh",
|
||||||
"gpio_if.sv",
|
"gpio_if.sv",
|
||||||
"gpio_reg.sv",
|
"gpio_reg.sv",
|
||||||
|
"hp_mailbox_define.svh",
|
||||||
"pll_ctrl_if.sv",
|
"pll_ctrl_if.sv",
|
||||||
"sysctrl_core.sv",
|
"sysctrl_core.sv",
|
||||||
"sysctrl_define.svh",
|
"sysctrl_define.svh",
|
||||||
@@ -277,11 +280,15 @@
|
|||||||
"axi42ribp_burst.sv",
|
"axi42ribp_burst.sv",
|
||||||
"axi4_bus.sv",
|
"axi4_bus.sv",
|
||||||
"axi4_connector.sv",
|
"axi4_connector.sv",
|
||||||
|
"axi4_downsizer_64to32.sv",
|
||||||
"axi4_error_slave.sv",
|
"axi4_error_slave.sv",
|
||||||
"axi4_interconnect.sv",
|
"axi4_interconnect.sv",
|
||||||
"axi4_word_bridge.sv",
|
"axi4_word_bridge.sv",
|
||||||
"core_wrapper.sv",
|
"core_wrapper.sv",
|
||||||
"gpio_pad_bridge.sv",
|
"gpio_pad_bridge.sv",
|
||||||
|
"hp_axi4_mux3.sv",
|
||||||
|
"hp_core_wrapper.sv",
|
||||||
|
"hp_subsystem.sv",
|
||||||
"mgmt_core_wrapper.sv",
|
"mgmt_core_wrapper.sv",
|
||||||
"mgmt_debug_reset.sv",
|
"mgmt_debug_reset.sv",
|
||||||
"mgmt_debug_wrapper.sv",
|
"mgmt_debug_wrapper.sv",
|
||||||
|
|||||||
@@ -25,6 +25,15 @@ SRAM CoreMark quick report into `meta/coremark.json`; it requires one valid
|
|||||||
`COREMARK_RESULT` record and `COREMARK_PASS`. Both reports complement, rather
|
`COREMARK_RESULT` record and `COREMARK_PASS`. Both reports complement, rather
|
||||||
than replace, the common `SIM_TEST_PASS` simulation verdict.
|
than replace, the common `SIM_TEST_PASS` simulation verdict.
|
||||||
|
|
||||||
|
`generate_vexiiriscv.py` verifies the locked VexiiRiscv revision and generates
|
||||||
|
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
|
||||||
|
bundle and its SHA-256/CRC manifest. `check_lp_hp_performance.py` applies the
|
||||||
|
measured 2.5x CoreMark/MHz gate.
|
||||||
|
|
||||||
`run_debug_session.py` is the local Hazard3 debug acceptance driver. It starts
|
`run_debug_session.py` is the local Hazard3 debug acceptance driver. It starts
|
||||||
the Verilator remote-bitbang endpoint, the lock-pinned OpenOCD binary, and
|
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
|
RISC-V GDB, then records their logs and a structured result. Invoke it through
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build the pinned RV32 HP Buildroot, Linux, DTB, and OpenSBI images."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def command(arguments: list[str], cwd: Path) -> None:
|
||||||
|
environment = dict(os.environ)
|
||||||
|
environment.pop("CONFIG", None)
|
||||||
|
environment.pop("MAKEFLAGS", None)
|
||||||
|
environment.pop("MAKEOVERRIDES", None)
|
||||||
|
environment.pop("MFLAGS", None)
|
||||||
|
subprocess.run(arguments, cwd=cwd, check=True, env=environment)
|
||||||
|
|
||||||
|
|
||||||
|
def sha256(path: Path) -> str:
|
||||||
|
digest = hashlib.sha256()
|
||||||
|
with path.open("rb") as source:
|
||||||
|
for chunk in iter(lambda: source.read(1024 * 1024), b""):
|
||||||
|
digest.update(chunk)
|
||||||
|
return digest.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def require_source(path: Path, name: str) -> Path:
|
||||||
|
resolved = path.resolve()
|
||||||
|
if not (resolved / ".git").exists():
|
||||||
|
raise FileNotFoundError(f"missing locked {name} source: {resolved}; run setup-hp-linux")
|
||||||
|
return resolved
|
||||||
|
|
||||||
|
|
||||||
|
def source_revision(path: Path) -> str:
|
||||||
|
return subprocess.check_output(
|
||||||
|
["git", "-C", str(path), "rev-parse", "HEAD"], text=True
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def find_toolchain(buildroot_output: Path) -> str:
|
||||||
|
matches = sorted((buildroot_output / "host/bin").glob("riscv32*-linux-*-gcc"))
|
||||||
|
if len(matches) != 1:
|
||||||
|
raise RuntimeError(f"expected one RV32 Linux GCC in {buildroot_output / 'host/bin'}")
|
||||||
|
return str(matches[0])[: -len("gcc")]
|
||||||
|
|
||||||
|
|
||||||
|
def build(args: argparse.Namespace) -> None:
|
||||||
|
root = args.root.resolve()
|
||||||
|
output = args.output.resolve()
|
||||||
|
output.mkdir(parents=True, exist_ok=True)
|
||||||
|
buildroot = require_source(args.buildroot, "Buildroot")
|
||||||
|
linux = require_source(args.linux, "Linux")
|
||||||
|
opensbi = require_source(args.opensbi, "OpenSBI")
|
||||||
|
external = root / "app/ports/linux"
|
||||||
|
|
||||||
|
buildroot_output = output / "buildroot"
|
||||||
|
command(
|
||||||
|
["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)
|
||||||
|
cross_compile = find_toolchain(buildroot_output)
|
||||||
|
|
||||||
|
linux_output = output / "linux"
|
||||||
|
command(
|
||||||
|
["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}", "tinyconfig"],
|
||||||
|
linux,
|
||||||
|
)
|
||||||
|
command(
|
||||||
|
[
|
||||||
|
str(linux / "scripts/kconfig/merge_config.sh"),
|
||||||
|
"-m",
|
||||||
|
"-O",
|
||||||
|
str(linux_output),
|
||||||
|
str(linux_output / ".config"),
|
||||||
|
str(external / "linux/retrosoc_hp.config"),
|
||||||
|
],
|
||||||
|
linux,
|
||||||
|
)
|
||||||
|
command(
|
||||||
|
["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}", "olddefconfig"],
|
||||||
|
linux,
|
||||||
|
)
|
||||||
|
command(
|
||||||
|
["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}",
|
||||||
|
f"-j{args.jobs}", "Image"],
|
||||||
|
linux,
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
command(
|
||||||
|
[
|
||||||
|
"dtc",
|
||||||
|
"-I",
|
||||||
|
"dts",
|
||||||
|
"-O",
|
||||||
|
"dtb",
|
||||||
|
"-o",
|
||||||
|
str(image_dir / "retrosoc_hp.dtb"),
|
||||||
|
str(external / "linux/retrosoc_hp.dts"),
|
||||||
|
],
|
||||||
|
root,
|
||||||
|
)
|
||||||
|
command(
|
||||||
|
[
|
||||||
|
"fdtput",
|
||||||
|
"-t",
|
||||||
|
"x",
|
||||||
|
str(image_dir / "retrosoc_hp.dtb"),
|
||||||
|
"/chosen",
|
||||||
|
"linux,initrd-end",
|
||||||
|
f"0x{initrd_end:08x}",
|
||||||
|
],
|
||||||
|
root,
|
||||||
|
)
|
||||||
|
|
||||||
|
opensbi_output = output / "opensbi"
|
||||||
|
command(
|
||||||
|
[
|
||||||
|
"make",
|
||||||
|
f"O={opensbi_output}",
|
||||||
|
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_zicsr_zifencei",
|
||||||
|
"FW_TEXT_START=0x38000000",
|
||||||
|
"FW_JUMP=y",
|
||||||
|
"FW_JUMP_ADDR=0x38400000",
|
||||||
|
"FW_JUMP_FDT_ADDR=0x38080000",
|
||||||
|
f"-j{args.jobs}",
|
||||||
|
],
|
||||||
|
opensbi,
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
manifest: dict[str, object] = {
|
||||||
|
"schema_version": 1,
|
||||||
|
"boot_flow": "opensbi-fw_jump",
|
||||||
|
"hart_id": 1,
|
||||||
|
"sources": {
|
||||||
|
"buildroot": source_revision(buildroot),
|
||||||
|
"linux": source_revision(linux),
|
||||||
|
"opensbi": source_revision(opensbi),
|
||||||
|
},
|
||||||
|
"artifacts": {},
|
||||||
|
}
|
||||||
|
artifacts = manifest["artifacts"]
|
||||||
|
assert isinstance(artifacts, dict)
|
||||||
|
for name, (address, maximum) in LAYOUT.items():
|
||||||
|
path = image_dir / name
|
||||||
|
size = path.stat().st_size
|
||||||
|
if size > maximum:
|
||||||
|
raise ValueError(f"{name} is {size} bytes; maximum is {maximum}")
|
||||||
|
artifacts[name] = {
|
||||||
|
"address": f"0x{address:08X}",
|
||||||
|
"maximum_bytes": maximum,
|
||||||
|
"size_bytes": size,
|
||||||
|
"sha256": sha256(path),
|
||||||
|
}
|
||||||
|
(image_dir / "manifest.json").write_text(
|
||||||
|
json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--root", type=Path, required=True)
|
||||||
|
parser.add_argument("--buildroot", type=Path, required=True)
|
||||||
|
parser.add_argument("--linux", type=Path, required=True)
|
||||||
|
parser.add_argument("--opensbi", type=Path, required=True)
|
||||||
|
parser.add_argument("--output", type=Path, required=True)
|
||||||
|
parser.add_argument("--jobs", type=int, default=1)
|
||||||
|
build(parser.parse_args())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build the minimal hart-1 smoke payload used by HP RTL simulation."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def build(args: argparse.Namespace) -> None:
|
||||||
|
output = args.output.resolve()
|
||||||
|
images = output / "images"
|
||||||
|
images.mkdir(parents=True, exist_ok=True)
|
||||||
|
elf = output / "hp_smoke.elf"
|
||||||
|
compiler = f"{args.cross}gcc"
|
||||||
|
objcopy = f"{args.cross}objcopy"
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
compiler,
|
||||||
|
"-march=rv32imafdc_zicsr_zifencei",
|
||||||
|
"-mabi=ilp32d",
|
||||||
|
"-nostdlib",
|
||||||
|
"-nostartfiles",
|
||||||
|
"-Wl,--build-id=none",
|
||||||
|
f"-Wl,-T,{args.linker.resolve()}",
|
||||||
|
"-o",
|
||||||
|
str(elf),
|
||||||
|
str(args.source.resolve()),
|
||||||
|
],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
subprocess.run(
|
||||||
|
[objcopy, "-O", "binary", str(elf), str(images / "fw_jump.bin")],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
(images / "retrosoc_hp.dtb").write_bytes(b"SMOK")
|
||||||
|
(images / "Image").write_bytes(b"SMOK")
|
||||||
|
(images / "rootfs.cpio.gz").write_bytes(b"SMOK")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--source", type=Path, required=True)
|
||||||
|
parser.add_argument("--linker", type=Path, required=True)
|
||||||
|
parser.add_argument("--output", type=Path, required=True)
|
||||||
|
parser.add_argument("--cross", default="riscv32-unknown-elf-")
|
||||||
|
build(parser.parse_args())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Enforce the measured HP-to-LP CoreMark/MHz performance ratio."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from decimal import Decimal, InvalidOperation
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def result(report: dict[str, object], label: str) -> dict[str, object]:
|
||||||
|
if report.get("status") != "passed":
|
||||||
|
raise ValueError(f"{label} CoreMark report did not pass")
|
||||||
|
results = report.get("results")
|
||||||
|
if not isinstance(results, list) or len(results) != 1 or not isinstance(results[0], dict):
|
||||||
|
raise ValueError(f"{label} CoreMark report must contain exactly one result")
|
||||||
|
return results[0]
|
||||||
|
|
||||||
|
|
||||||
|
def compare(
|
||||||
|
lp_report: dict[str, object], hp_report: dict[str, object], threshold: Decimal
|
||||||
|
) -> dict[str, object]:
|
||||||
|
if threshold <= 0:
|
||||||
|
raise ValueError("minimum performance ratio must be positive")
|
||||||
|
lp = result(lp_report, "LP")
|
||||||
|
hp = result(hp_report, "HP")
|
||||||
|
if lp.get("mode") != hp.get("mode"):
|
||||||
|
raise ValueError("LP and HP CoreMark reports must use the same mode")
|
||||||
|
if lp.get("cpu_hz") != hp.get("cpu_hz"):
|
||||||
|
raise ValueError("LP and HP CoreMark reports must use the same fixed frequency")
|
||||||
|
try:
|
||||||
|
lp_score = Decimal(str(lp["coremark_per_mhz"]))
|
||||||
|
hp_score = Decimal(str(hp["coremark_per_mhz"]))
|
||||||
|
ratio = hp_score / lp_score
|
||||||
|
except (InvalidOperation, KeyError, ZeroDivisionError) as error:
|
||||||
|
raise ValueError("invalid CoreMark/MHz values") from error
|
||||||
|
passed = ratio >= threshold
|
||||||
|
return {
|
||||||
|
"schema_version": 1,
|
||||||
|
"status": "passed" if passed else "failed",
|
||||||
|
"frequency_hz": lp["cpu_hz"],
|
||||||
|
"mode": lp["mode"],
|
||||||
|
"lp_coremark_per_mhz": str(lp_score),
|
||||||
|
"hp_coremark_per_mhz": str(hp_score),
|
||||||
|
"minimum_ratio": str(threshold),
|
||||||
|
"measured_ratio": str(ratio.quantize(Decimal("0.001"))),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--lp", type=Path, required=True)
|
||||||
|
parser.add_argument("--hp", type=Path, required=True)
|
||||||
|
parser.add_argument("--minimum-ratio", type=Decimal, default=Decimal("2.5"))
|
||||||
|
parser.add_argument("--output", type=Path, required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
try:
|
||||||
|
report = compare(
|
||||||
|
json.loads(args.lp.read_text(encoding="utf-8")),
|
||||||
|
json.loads(args.hp.read_text(encoding="utf-8")),
|
||||||
|
args.minimum_ratio,
|
||||||
|
)
|
||||||
|
except (OSError, ValueError, json.JSONDecodeError) as error:
|
||||||
|
print(f"performance comparison failed: {error}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
args.output.write_text(
|
||||||
|
json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
if report["status"] != "passed":
|
||||||
|
print(
|
||||||
|
f"HP/LP CoreMark/MHz ratio {report['measured_ratio']} is below "
|
||||||
|
f"{report['minimum_ratio']}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate the locked VexiiRiscv HP core below the selected build variant."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
GENERATOR_CLASS = "vexiiriscv.GenerateRetroSocHp"
|
||||||
|
GENERATED_MODULE = "vexii_riscv_hp_generated"
|
||||||
|
|
||||||
|
|
||||||
|
def run(command: list[str], cwd: Path) -> str:
|
||||||
|
result = subprocess.run(command, cwd=cwd, check=True, capture_output=True, text=True)
|
||||||
|
return result.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def git_revision(source: Path) -> str:
|
||||||
|
return run(["git", "rev-parse", "HEAD"], source)
|
||||||
|
|
||||||
|
|
||||||
|
def git_status(source: Path) -> list[str]:
|
||||||
|
output = run(["git", "status", "--short"], source)
|
||||||
|
return output.splitlines() if output else []
|
||||||
|
|
||||||
|
|
||||||
|
def sha256(path: Path) -> str:
|
||||||
|
digest = hashlib.sha256()
|
||||||
|
with path.open("rb") as source:
|
||||||
|
for chunk in iter(lambda: source.read(1024 * 1024), b""):
|
||||||
|
digest.update(chunk)
|
||||||
|
return digest.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def locked_revision(lock_path: Path) -> str:
|
||||||
|
document: dict[str, Any] = json.loads(lock_path.read_text(encoding="utf-8"))
|
||||||
|
source = document.get("sources", {}).get("vexiiriscv")
|
||||||
|
if not isinstance(source, dict) or not isinstance(source.get("revision"), str):
|
||||||
|
raise ValueError("dependency lock has no vexiiriscv source revision")
|
||||||
|
return source["revision"]
|
||||||
|
|
||||||
|
|
||||||
|
def generate(args: argparse.Namespace) -> None:
|
||||||
|
root = args.root.resolve()
|
||||||
|
source = args.source.resolve()
|
||||||
|
output = args.output.resolve()
|
||||||
|
expected = locked_revision(args.lock.resolve())
|
||||||
|
actual = git_revision(source)
|
||||||
|
if actual != expected:
|
||||||
|
raise ValueError(f"VexiiRiscv revision mismatch: expected {expected}, found {actual}")
|
||||||
|
|
||||||
|
scala_dir = root / "scripts" / "vexiiriscv"
|
||||||
|
output.mkdir(parents=True, exist_ok=True)
|
||||||
|
command = [
|
||||||
|
str(args.sbt),
|
||||||
|
f'set Compile / unmanagedSourceDirectories += file("{scala_dir}")',
|
||||||
|
f"runMain {GENERATOR_CLASS} {output}",
|
||||||
|
]
|
||||||
|
environment = os.environ.copy()
|
||||||
|
java_home = environment.get("HOME")
|
||||||
|
if java_home:
|
||||||
|
inherited = environment.get("JAVA_TOOL_OPTIONS", "").strip()
|
||||||
|
environment["JAVA_TOOL_OPTIONS"] = (
|
||||||
|
f"{inherited} -Duser.home={java_home}".strip()
|
||||||
|
)
|
||||||
|
subprocess.run(command, cwd=source, check=True, env=environment)
|
||||||
|
|
||||||
|
generated = output / "vexii_riscv_hp_generated.v"
|
||||||
|
if not generated.is_file():
|
||||||
|
raise FileNotFoundError(f"VexiiRiscv generator did not create {generated}")
|
||||||
|
|
||||||
|
submodules = run(["git", "submodule", "status", "--recursive"], source).splitlines()
|
||||||
|
manifest = {
|
||||||
|
"schema_version": 1,
|
||||||
|
"module": GENERATED_MODULE,
|
||||||
|
"configuration": "rv32imafdc_max",
|
||||||
|
"vexiiriscv_revision": actual,
|
||||||
|
"source_status": git_status(source),
|
||||||
|
"submodules": submodules,
|
||||||
|
"generator": str((scala_dir / "GenerateRetroSocHp.scala").relative_to(root)),
|
||||||
|
"files": {generated.name: sha256(generated)},
|
||||||
|
}
|
||||||
|
args.manifest.resolve().parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
args.manifest.resolve().write_text(
|
||||||
|
json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
(output / "vexiiriscv.fl").write_text(str(generated) + "\n", encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--root", type=Path, required=True)
|
||||||
|
parser.add_argument("--source", type=Path, required=True)
|
||||||
|
parser.add_argument("--output", type=Path, required=True)
|
||||||
|
parser.add_argument("--manifest", type=Path, required=True)
|
||||||
|
parser.add_argument("--lock", type=Path, required=True)
|
||||||
|
parser.add_argument("--sbt", type=Path, required=True)
|
||||||
|
generate(parser.parse_args())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Executable
+127
@@ -0,0 +1,127 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Package LP firmware and the fixed HP Linux image set into one flash image."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import struct
|
||||||
|
import zlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
FLASH_SIZE = 16 * 1024 * 1024
|
||||||
|
BUNDLE_OFFSET = 1 * 1024 * 1024
|
||||||
|
PAYLOAD_ALIGNMENT = 4096
|
||||||
|
MAGIC = 0x50485352
|
||||||
|
VERSION = 1
|
||||||
|
REQUIRED = 1
|
||||||
|
HEADER = struct.Struct("<8I")
|
||||||
|
ENTRY = struct.Struct("<6I")
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
HEADER_SIZE = HEADER.size + (ENTRY.size * len(ARTIFACTS))
|
||||||
|
|
||||||
|
|
||||||
|
def align_up(value: int, alignment: int) -> int:
|
||||||
|
return (value + alignment - 1) & ~(alignment - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def sha256(data: bytes) -> str:
|
||||||
|
return hashlib.sha256(data).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def package(args: argparse.Namespace) -> None:
|
||||||
|
firmware = args.firmware.read_bytes()
|
||||||
|
if len(firmware) > BUNDLE_OFFSET:
|
||||||
|
raise ValueError(
|
||||||
|
f"LP firmware is {len(firmware)} bytes; bundle starts at {BUNDLE_OFFSET}"
|
||||||
|
)
|
||||||
|
|
||||||
|
payload_offset = align_up(BUNDLE_OFFSET + HEADER_SIZE, PAYLOAD_ALIGNMENT)
|
||||||
|
entries: list[bytes] = []
|
||||||
|
payloads: list[tuple[int, bytes]] = []
|
||||||
|
artifact_manifest: dict[str, object] = {}
|
||||||
|
cursor = payload_offset
|
||||||
|
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")
|
||||||
|
crc32 = zlib.crc32(data) & 0xFFFFFFFF
|
||||||
|
entries.append(ENTRY.pack(kind, cursor, load_address, len(data), crc32, REQUIRED))
|
||||||
|
payloads.append((cursor, data))
|
||||||
|
artifact_manifest[name] = {
|
||||||
|
"crc32": f"0x{crc32:08X}",
|
||||||
|
"flash_offset": f"0x{cursor:08X}",
|
||||||
|
"load_address": f"0x{load_address:08X}",
|
||||||
|
"sha256": sha256(data),
|
||||||
|
"size_bytes": len(data),
|
||||||
|
}
|
||||||
|
cursor = align_up(cursor + len(data), PAYLOAD_ALIGNMENT)
|
||||||
|
|
||||||
|
if cursor > FLASH_SIZE:
|
||||||
|
raise ValueError(f"HP boot image needs {cursor} bytes; flash capacity is {FLASH_SIZE}")
|
||||||
|
total_size = cursor - BUNDLE_OFFSET
|
||||||
|
header = HEADER.pack(
|
||||||
|
MAGIC,
|
||||||
|
VERSION,
|
||||||
|
HEADER_SIZE,
|
||||||
|
len(entries),
|
||||||
|
total_size,
|
||||||
|
0,
|
||||||
|
REQUIRED,
|
||||||
|
0,
|
||||||
|
) + b"".join(entries)
|
||||||
|
header_crc32 = zlib.crc32(header) & 0xFFFFFFFF
|
||||||
|
header = HEADER.pack(
|
||||||
|
MAGIC,
|
||||||
|
VERSION,
|
||||||
|
HEADER_SIZE,
|
||||||
|
len(entries),
|
||||||
|
total_size,
|
||||||
|
header_crc32,
|
||||||
|
REQUIRED,
|
||||||
|
0,
|
||||||
|
) + b"".join(entries)
|
||||||
|
|
||||||
|
image = bytearray(b"\xFF" * cursor)
|
||||||
|
image[: len(firmware)] = firmware
|
||||||
|
image[BUNDLE_OFFSET : BUNDLE_OFFSET + len(header)] = header
|
||||||
|
for offset, data in payloads:
|
||||||
|
image[offset : offset + len(data)] = data
|
||||||
|
|
||||||
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
args.output.write_bytes(image)
|
||||||
|
manifest = {
|
||||||
|
"schema_version": 1,
|
||||||
|
"format": "retrosoc-hp-boot-bundle-v1",
|
||||||
|
"bundle_offset": f"0x{BUNDLE_OFFSET:08X}",
|
||||||
|
"flash_capacity_bytes": FLASH_SIZE,
|
||||||
|
"header_crc32": f"0x{header_crc32:08X}",
|
||||||
|
"image_sha256": sha256(image),
|
||||||
|
"image_size_bytes": len(image),
|
||||||
|
"lp_firmware_size_bytes": len(firmware),
|
||||||
|
"artifacts": artifact_manifest,
|
||||||
|
}
|
||||||
|
args.manifest.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
args.manifest.write_text(
|
||||||
|
json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--firmware", type=Path, required=True)
|
||||||
|
parser.add_argument("--images", type=Path, required=True)
|
||||||
|
parser.add_argument("--output", type=Path, required=True)
|
||||||
|
parser.add_argument("--manifest", type=Path, required=True)
|
||||||
|
package(parser.parse_args())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Install the pinned HP Linux, OpenSBI, and Buildroot source trees."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dependency_lock import source
|
||||||
|
from setup_helpers import ensure_git_repo, run
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def repair_incomplete_checkout(
|
||||||
|
destination: Path, url: str, revision: str
|
||||||
|
) -> None:
|
||||||
|
if not (destination / ".git").is_dir():
|
||||||
|
return
|
||||||
|
result = subprocess.run(
|
||||||
|
["git", "-C", str(destination), "rev-parse", "--verify", "HEAD"],
|
||||||
|
check=False,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
if result.returncode == 0:
|
||||||
|
return
|
||||||
|
run(("git", "remote", "set-url", "origin", url), cwd=destination)
|
||||||
|
run(("git", "fetch", "--depth", "1", "origin", revision), cwd=destination)
|
||||||
|
run(("git", "checkout", "--detach", "FETCH_HEAD"), cwd=destination)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--update", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
# The stable Linux mirror is large enough to expose HTTP/2 proxy framing failures.
|
||||||
|
os.environ.setdefault("GIT_CONFIG_COUNT", "1")
|
||||||
|
os.environ.setdefault("GIT_CONFIG_KEY_0", "http.version")
|
||||||
|
os.environ.setdefault("GIT_CONFIG_VALUE_0", "HTTP/1.1")
|
||||||
|
for name in ("opensbi_hp", "linux_hp", "buildroot_hp"):
|
||||||
|
dependency = source(name)
|
||||||
|
destination = ROOT / dependency["destination"]
|
||||||
|
repair_incomplete_checkout(
|
||||||
|
destination, dependency["url"], dependency["revision"]
|
||||||
|
)
|
||||||
|
ensure_git_repo(
|
||||||
|
dependency["url"],
|
||||||
|
destination,
|
||||||
|
dependency["revision"],
|
||||||
|
recursive=dependency.get("recursive", False),
|
||||||
|
update=args.update,
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package vexiiriscv
|
||||||
|
|
||||||
|
import spinal.core._
|
||||||
|
import spinal.lib.bus.misc.SizeMapping
|
||||||
|
import spinal.lib.bus.tilelink.M2sTransfers
|
||||||
|
import spinal.lib.system.tag.PmaRegionImpl
|
||||||
|
import vexiiriscv.misc.EmbeddedRiscvJtag
|
||||||
|
|
||||||
|
import java.nio.file.{Files, Paths}
|
||||||
|
|
||||||
|
/** Generates the fixed retroSoC RV32 Linux application core. */
|
||||||
|
object GenerateRetroSocHp extends App {
|
||||||
|
require(args.length == 1, "usage: GenerateRetroSocHp <output-directory>")
|
||||||
|
|
||||||
|
val output = Paths.get(args(0)).toAbsolutePath.normalize
|
||||||
|
Files.createDirectories(output)
|
||||||
|
|
||||||
|
val param = new ParamSimple()
|
||||||
|
param.xlen = 32
|
||||||
|
param.physicalWidth = 32
|
||||||
|
param.resetVector = 0x38000000L
|
||||||
|
param.asidWidth = 9
|
||||||
|
param.addISA("m", "a", "f", "d", "c", "s", "u", "zicntr", "zihpm")
|
||||||
|
param.fixIsaParams()
|
||||||
|
|
||||||
|
param.decoders = 2
|
||||||
|
param.lanes = 2
|
||||||
|
param.withBtb = true
|
||||||
|
param.withGShare = true
|
||||||
|
param.withRas = true
|
||||||
|
param.withLateAlu = true
|
||||||
|
param.withAlignerBuffer = true
|
||||||
|
param.withDispatcherBuffer = true
|
||||||
|
param.allowBypassFrom = 0
|
||||||
|
param.storeRs2Late = true
|
||||||
|
param.divRadix = 4
|
||||||
|
param.divArea = false
|
||||||
|
|
||||||
|
param.fetchL1Enable = true
|
||||||
|
param.fetchL1Sets = 64
|
||||||
|
param.fetchL1Ways = 4
|
||||||
|
param.fetchMemDataWidthMin = 64
|
||||||
|
param.fetchL1RefillCount = 2
|
||||||
|
param.fetchL1Prefetch = "nl"
|
||||||
|
param.fetchBus = FetchBusEnum.axi4
|
||||||
|
|
||||||
|
param.lsuL1Enable = true
|
||||||
|
param.lsuL1Sets = 64
|
||||||
|
param.lsuL1Ways = 4
|
||||||
|
param.lsuMemDataWidthMin = 64
|
||||||
|
param.lsuL1RefillCount = 8
|
||||||
|
param.lsuL1WritebackCount = 8
|
||||||
|
param.lsuStoreBufferSlots = 4
|
||||||
|
param.lsuStoreBufferOps = 32
|
||||||
|
param.lsuSoftwarePrefetch = true
|
||||||
|
param.lsuHardwarePrefetch = "rpt"
|
||||||
|
param.withLsuBypass = true
|
||||||
|
param.lsuBus = LsuBusEnum.axi4
|
||||||
|
param.lsuL1Bus = LsuL1BusEnum.axi4
|
||||||
|
|
||||||
|
param.pmpParam.pmpSize = 16
|
||||||
|
param.pmpParam.granularity = 4096
|
||||||
|
param.additionalPerformanceCounters = 8
|
||||||
|
param.privParam.withRdTime = true
|
||||||
|
param.privParam.withDebug = true
|
||||||
|
param.privParam.debugTriggers = 4
|
||||||
|
param.embeddedJtagTap = true
|
||||||
|
|
||||||
|
val config = SpinalConfig(
|
||||||
|
targetDirectory = output.toString,
|
||||||
|
inlineRom = true
|
||||||
|
)
|
||||||
|
config.generateVerilog {
|
||||||
|
val plugins = param.plugins(hartId = 1)
|
||||||
|
plugins.foreach {
|
||||||
|
case plugin: EmbeddedRiscvJtag =>
|
||||||
|
plugin.debugCd = ClockDomain.current.copy(
|
||||||
|
reset = Bool().setName("EmbeddedRiscvJtag_logic_debug_reset")
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
ParamSimple.setPma(
|
||||||
|
plugins,
|
||||||
|
Seq(
|
||||||
|
new PmaRegionImpl(
|
||||||
|
mapping = SizeMapping(0x00000000L, 0x01000000L),
|
||||||
|
isMain = false,
|
||||||
|
isExecutable = true,
|
||||||
|
transfers = M2sTransfers.all
|
||||||
|
),
|
||||||
|
new PmaRegionImpl(
|
||||||
|
mapping = SizeMapping(0x02000000L, 0x2E000000L),
|
||||||
|
isMain = false,
|
||||||
|
isExecutable = false,
|
||||||
|
transfers = M2sTransfers.all
|
||||||
|
),
|
||||||
|
new PmaRegionImpl(
|
||||||
|
mapping = SizeMapping(0x30000000L, 0x00020000L),
|
||||||
|
isMain = true,
|
||||||
|
isExecutable = true,
|
||||||
|
transfers = M2sTransfers.all
|
||||||
|
),
|
||||||
|
new PmaRegionImpl(
|
||||||
|
mapping = SizeMapping(0x38000000L, 0x04000000L),
|
||||||
|
isMain = true,
|
||||||
|
isExecutable = true,
|
||||||
|
transfers = M2sTransfers.all
|
||||||
|
),
|
||||||
|
new PmaRegionImpl(
|
||||||
|
mapping = SizeMapping(0x40000000L, 0x02000000L),
|
||||||
|
isMain = true,
|
||||||
|
isExecutable = true,
|
||||||
|
transfers = M2sTransfers.all
|
||||||
|
),
|
||||||
|
new PmaRegionImpl(
|
||||||
|
mapping = SizeMapping(0x48000000L, 0x08000000L),
|
||||||
|
isMain = true,
|
||||||
|
isExecutable = true,
|
||||||
|
transfers = M2sTransfers.all
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
VexiiRiscv(plugins).setDefinitionName("vexii_riscv_hp_generated")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,10 @@ tooling.
|
|||||||
- `test_user_ip_register_parity.py` keeps the integrated slot 1 timer and slot
|
- `test_user_ip_register_parity.py` keeps the integrated slot 1 timer and slot
|
||||||
2 GPIO register offsets synchronized with their application-owned C
|
2 GPIO register offsets synchronized with their application-owned C
|
||||||
definitions and checks their extension-manifest slot assignments.
|
definitions and checks their extension-manifest slot assignments.
|
||||||
|
- `test_hp_boot_bundle.py` checks the HP flash ABI, CRCs, payload placement,
|
||||||
|
and handwritten mailbox RTL/C offset parity. `test_hp_platform.py`,
|
||||||
|
`test_hp_mailbox.py`, `test_plic.py`, and the AXI tests cover the remaining
|
||||||
|
HP integration contracts.
|
||||||
|
|
||||||
Add a host C test when changing deterministic runtime or media logic; add a
|
Add a host C test when changing deterministic runtime or media logic; add a
|
||||||
Python test when changing scripts or build policy. Run:
|
Python test when changing scripts or build policy. Run:
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
`include "axi4_define.svh"
|
||||||
|
|
||||||
|
module axi4_downsizer_64to32_tb;
|
||||||
|
logic clk_i = 1'b0;
|
||||||
|
logic rst_n_i = 1'b0;
|
||||||
|
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(64),
|
||||||
|
.ID_WIDTH (3),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) wide (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
axi4_if #(
|
||||||
|
.ADDR_WIDTH(32),
|
||||||
|
.DATA_WIDTH(32),
|
||||||
|
.ID_WIDTH (1),
|
||||||
|
.USER_WIDTH(1)
|
||||||
|
) narrow (
|
||||||
|
.aclk (clk_i),
|
||||||
|
.aresetn(rst_n_i)
|
||||||
|
);
|
||||||
|
|
||||||
|
always #5 clk_i = ~clk_i;
|
||||||
|
|
||||||
|
axi4_downsizer_64to32 u_dut (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_n_i(rst_n_i),
|
||||||
|
.wide (wide),
|
||||||
|
.narrow (narrow)
|
||||||
|
);
|
||||||
|
|
||||||
|
task automatic init_bus;
|
||||||
|
begin
|
||||||
|
wide.awid = '0;
|
||||||
|
wide.awaddr = '0;
|
||||||
|
wide.awlen = '0;
|
||||||
|
wide.awsize = `AXI4_BURST_SIZE_8BYTES;
|
||||||
|
wide.awburst = `AXI4_BURST_TYPE_INCR;
|
||||||
|
wide.awlock = `AXI4_LOCK_NORM;
|
||||||
|
wide.awcache = `AXI4_CACHE_NO_BUF;
|
||||||
|
wide.awprot = `AXI4_PROT_DATA;
|
||||||
|
wide.awqos = `AXI4_QOS_NORMAL;
|
||||||
|
wide.awregion = `AXI4_REGION_NORMAL;
|
||||||
|
wide.awuser = '0;
|
||||||
|
wide.awvalid = 1'b0;
|
||||||
|
wide.wdata = '0;
|
||||||
|
wide.wstrb = '0;
|
||||||
|
wide.wlast = 1'b0;
|
||||||
|
wide.wuser = '0;
|
||||||
|
wide.wvalid = 1'b0;
|
||||||
|
wide.bready = 1'b0;
|
||||||
|
wide.arid = '0;
|
||||||
|
wide.araddr = '0;
|
||||||
|
wide.arlen = '0;
|
||||||
|
wide.arsize = `AXI4_BURST_SIZE_8BYTES;
|
||||||
|
wide.arburst = `AXI4_BURST_TYPE_INCR;
|
||||||
|
wide.arlock = `AXI4_LOCK_NORM;
|
||||||
|
wide.arcache = `AXI4_CACHE_NO_BUF;
|
||||||
|
wide.arprot = `AXI4_PROT_DATA;
|
||||||
|
wide.arqos = `AXI4_QOS_NORMAL;
|
||||||
|
wide.arregion = `AXI4_REGION_NORMAL;
|
||||||
|
wide.aruser = '0;
|
||||||
|
wide.arvalid = 1'b0;
|
||||||
|
wide.rready = 1'b0;
|
||||||
|
narrow.awready = 1'b0;
|
||||||
|
narrow.wready = 1'b0;
|
||||||
|
narrow.bid = '0;
|
||||||
|
narrow.bresp = `AXI4_RESP_OKAY;
|
||||||
|
narrow.buser = '0;
|
||||||
|
narrow.bvalid = 1'b0;
|
||||||
|
narrow.arready = 1'b0;
|
||||||
|
narrow.rid = '0;
|
||||||
|
narrow.rdata = '0;
|
||||||
|
narrow.rresp = `AXI4_RESP_OKAY;
|
||||||
|
narrow.rlast = 1'b0;
|
||||||
|
narrow.ruser = '0;
|
||||||
|
narrow.rvalid = 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic accept_read(input logic [31:0] address, input logic [7:0] length,
|
||||||
|
input logic [2:0] size, input logic [2:0] id,
|
||||||
|
input logic [7:0] expected_length);
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.araddr = address;
|
||||||
|
wide.arlen = length;
|
||||||
|
wide.arsize = size;
|
||||||
|
wide.arid = id;
|
||||||
|
wide.arvalid = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (wide.arready) $fatal(1, "read address ignored narrow backpressure");
|
||||||
|
narrow.arready = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (!narrow.arvalid || narrow.araddr != address || narrow.arlen != expected_length ||
|
||||||
|
narrow.arsize != ((size == 3'd3) ? 3'd2 : size)) begin
|
||||||
|
$fatal(1, "read address conversion mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.arvalid = 1'b0;
|
||||||
|
narrow.arready = 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic accept_write(input logic [31:0] address, input logic [7:0] length,
|
||||||
|
input logic [2:0] size, input logic [2:0] id,
|
||||||
|
input logic [7:0] expected_length);
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.awaddr = address;
|
||||||
|
wide.awlen = length;
|
||||||
|
wide.awsize = size;
|
||||||
|
wide.awid = id;
|
||||||
|
wide.awvalid = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (wide.awready) $fatal(1, "write address ignored narrow backpressure");
|
||||||
|
narrow.awready = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (!narrow.awvalid || narrow.awaddr != address || narrow.awlen != expected_length ||
|
||||||
|
narrow.awsize != ((size == 3'd3) ? 3'd2 : size)) begin
|
||||||
|
$fatal(1, "write address conversion mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.awvalid = 1'b0;
|
||||||
|
narrow.awready = 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic return_write_response(input logic [2:0] expected_id, input logic [1:0] response);
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
narrow.bresp = response;
|
||||||
|
narrow.bvalid = 1'b1;
|
||||||
|
wide.bready = 1'b0;
|
||||||
|
#1;
|
||||||
|
if (!narrow.bready) $fatal(1, "narrow write response was not accepted into buffer");
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
narrow.bvalid = 1'b0;
|
||||||
|
#1;
|
||||||
|
if (!wide.bvalid || wide.bid != expected_id || wide.bresp != response) begin
|
||||||
|
$fatal(1, "buffered write response mismatch");
|
||||||
|
end
|
||||||
|
repeat (2) @(posedge clk_i);
|
||||||
|
if (!wide.bvalid || wide.bid != expected_id || wide.bresp != response) begin
|
||||||
|
$fatal(1, "write response changed under backpressure");
|
||||||
|
end
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.bready = 1'b1;
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.bready = 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
init_bus();
|
||||||
|
repeat (4) @(posedge clk_i);
|
||||||
|
rst_n_i = 1'b1;
|
||||||
|
|
||||||
|
accept_read(32'h0000_0040, 8'd0, 3'd3, 3'd5, 8'd1);
|
||||||
|
@(negedge clk_i);
|
||||||
|
narrow.rdata = 32'h1122_3344;
|
||||||
|
narrow.rresp = `AXI4_RESP_SLAVE_ERROR;
|
||||||
|
narrow.rlast = 1'b0;
|
||||||
|
narrow.rvalid = 1'b1;
|
||||||
|
wide.rready = 1'b0;
|
||||||
|
#1;
|
||||||
|
if (!narrow.rready || wide.rvalid) $fatal(1, "lower read beat was not buffered");
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
narrow.rdata = 32'h5566_7788;
|
||||||
|
narrow.rresp = `AXI4_RESP_OKAY;
|
||||||
|
narrow.rlast = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (!wide.rvalid || narrow.rready || wide.rid != 3'd5 ||
|
||||||
|
wide.rdata != 64'h5566_7788_1122_3344 || wide.rresp != `AXI4_RESP_SLAVE_ERROR ||
|
||||||
|
!wide.rlast) begin
|
||||||
|
$fatal(1, "64-bit read assembly or backpressure mismatch");
|
||||||
|
end
|
||||||
|
repeat (2) @(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.rready = 1'b1;
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.rready = 1'b0;
|
||||||
|
narrow.rvalid = 1'b0;
|
||||||
|
|
||||||
|
accept_read(32'h0000_0000, 8'd1, 3'd2, 3'd3, 8'd1);
|
||||||
|
@(negedge clk_i);
|
||||||
|
narrow.rdata = 32'hA5A5_0000;
|
||||||
|
narrow.rresp = `AXI4_RESP_OKAY;
|
||||||
|
narrow.rlast = 1'b0;
|
||||||
|
narrow.rvalid = 1'b1;
|
||||||
|
wide.rready = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (wide.rdata != 64'h0000_0000_A5A5_0000 || wide.rid != 3'd3) begin
|
||||||
|
$fatal(1, "lower 32-bit read lane mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
narrow.rdata = 32'hA5A5_0001;
|
||||||
|
narrow.rlast = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (wide.rdata != 64'hA5A5_0001_0000_0000 || !wide.rlast) begin
|
||||||
|
$fatal(1, "upper 32-bit read lane mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.rready = 1'b0;
|
||||||
|
narrow.rvalid = 1'b0;
|
||||||
|
|
||||||
|
accept_write(32'h0000_0080, 8'd0, 3'd3, 3'd6, 8'd1);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.wdata = 64'h1122_3344_5566_7788;
|
||||||
|
wide.wstrb = 8'hF3;
|
||||||
|
wide.wlast = 1'b1;
|
||||||
|
wide.wvalid = 1'b1;
|
||||||
|
narrow.wready = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (narrow.wdata != 32'h5566_7788 || narrow.wstrb != 4'h3 || narrow.wlast || wide.wready) begin
|
||||||
|
$fatal(1, "lower 64-bit write split mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
#1;
|
||||||
|
if (narrow.wdata != 32'h1122_3344 || narrow.wstrb != 4'hF || !narrow.wlast ||
|
||||||
|
!wide.wready) begin
|
||||||
|
$fatal(1, "upper 64-bit write split mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.wvalid = 1'b0;
|
||||||
|
narrow.wready = 1'b0;
|
||||||
|
return_write_response(3'd6, `AXI4_RESP_DECODE_ERROR);
|
||||||
|
|
||||||
|
accept_write(32'h0000_0004, 8'd1, 3'd2, 3'd2, 8'd1);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.wdata = 64'hCAFE_0000_DEAD_0000;
|
||||||
|
wide.wstrb = 8'hF0;
|
||||||
|
wide.wlast = 1'b0;
|
||||||
|
wide.wvalid = 1'b1;
|
||||||
|
narrow.wready = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (narrow.wdata != 32'hCAFE_0000 || narrow.wstrb != 4'hF || !wide.wready) begin
|
||||||
|
$fatal(1, "upper 32-bit write lane mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.wdata = 64'hDEAD_0000_CAFE_0001;
|
||||||
|
wide.wstrb = 8'h0F;
|
||||||
|
wide.wlast = 1'b1;
|
||||||
|
#1;
|
||||||
|
if (narrow.wdata != 32'hCAFE_0001 || narrow.wstrb != 4'hF || !wide.wready) begin
|
||||||
|
$fatal(1, "lower 32-bit write lane mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
wide.wvalid = 1'b0;
|
||||||
|
narrow.wready = 1'b0;
|
||||||
|
return_write_response(3'd2, `AXI4_RESP_OKAY);
|
||||||
|
|
||||||
|
$display("AXI4 64-to-32 downsizer test passed");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
`include "rib_defs.svh"
|
`include "rib_defs.svh"
|
||||||
|
|
||||||
module axi4_interconnect_tb;
|
module axi4_interconnect_tb;
|
||||||
localparam int NumMasters = 7;
|
localparam int NumMasters = 8;
|
||||||
localparam int NumTargets = 9;
|
localparam int NumTargets = 9;
|
||||||
|
|
||||||
logic clk_i = 1'b0;
|
logic clk_i = 1'b0;
|
||||||
@@ -288,6 +288,50 @@ module axi4_interconnect_tb;
|
|||||||
end
|
end
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
|
task automatic issue_hp_accesses;
|
||||||
|
integer beat;
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
masters[7].araddr = 32'h3800_0000;
|
||||||
|
masters[7].arlen = 8'd15;
|
||||||
|
masters[7].arvalid = 1'b1;
|
||||||
|
do @(posedge clk_i); while (!masters[7].arready);
|
||||||
|
@(negedge clk_i);
|
||||||
|
masters[7].arvalid = 1'b0;
|
||||||
|
masters[7].rready = 1'b1;
|
||||||
|
beat = 0;
|
||||||
|
while (beat < 16) begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
if (masters[7].rvalid) begin
|
||||||
|
if ((masters[7].rresp != `AXI4_RESP_OKAY) ||
|
||||||
|
(masters[7].rlast != (beat == 15)) || fault_valid_o) begin
|
||||||
|
$fatal(1, "HP SDRAM burst was rejected or misclassified");
|
||||||
|
end
|
||||||
|
beat = beat + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@(negedge clk_i);
|
||||||
|
masters[7].rready = 1'b0;
|
||||||
|
masters[7].araddr = 32'hA000_7000;
|
||||||
|
masters[7].arlen = 8'd0;
|
||||||
|
masters[7].arvalid = 1'b1;
|
||||||
|
do @(posedge clk_i); while (!masters[7].arready);
|
||||||
|
@(negedge clk_i);
|
||||||
|
masters[7].arvalid = 1'b0;
|
||||||
|
masters[7].rready = 1'b1;
|
||||||
|
while (!masters[7].rvalid) @(negedge clk_i);
|
||||||
|
#1;
|
||||||
|
if ((masters[7].rresp != `AXI4_RESP_DECODE_ERROR) || !fault_valid_o ||
|
||||||
|
(fault_master_o != 3'd7) || (fault_addr_o != 32'hA000_7000) ||
|
||||||
|
(fault_code_o != `RIB_RESP_DECERR)) begin
|
||||||
|
$fatal(1, "HP decode fault attribution mismatch");
|
||||||
|
end
|
||||||
|
@(posedge clk_i);
|
||||||
|
@(negedge clk_i);
|
||||||
|
masters[7].rready = 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
`INIT_MASTER(0)
|
`INIT_MASTER(0)
|
||||||
`INIT_MASTER(1)
|
`INIT_MASTER(1)
|
||||||
@@ -295,6 +339,8 @@ module axi4_interconnect_tb;
|
|||||||
`INIT_MASTER(3)
|
`INIT_MASTER(3)
|
||||||
`INIT_MASTER(4)
|
`INIT_MASTER(4)
|
||||||
`INIT_MASTER(5)
|
`INIT_MASTER(5)
|
||||||
|
`INIT_MASTER(6)
|
||||||
|
`INIT_MASTER(7)
|
||||||
repeat (4) @(posedge clk_i);
|
repeat (4) @(posedge clk_i);
|
||||||
rst_n_i = 1'b1;
|
rst_n_i = 1'b1;
|
||||||
|
|
||||||
@@ -303,6 +349,7 @@ module axi4_interconnect_tb;
|
|||||||
issue_mgmt_error_read(32'h3000_0000, 8'd16, `AXI4_RESP_SLAVE_ERROR, `RIB_RESP_BURSTERR);
|
issue_mgmt_error_read(32'h3000_0000, 8'd16, `AXI4_RESP_SLAVE_ERROR, `RIB_RESP_BURSTERR);
|
||||||
issue_denied_user_write(32'h1000_B000);
|
issue_denied_user_write(32'h1000_B000);
|
||||||
issue_contending_sdio_faults();
|
issue_contending_sdio_faults();
|
||||||
|
issue_hp_accesses();
|
||||||
|
|
||||||
$display("AXI4 interconnect fault classification test passed");
|
$display("AXI4 interconnect fault classification test passed");
|
||||||
$finish;
|
$finish;
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module hp_mailbox_tb;
|
||||||
|
logic clk_i = 1'b0;
|
||||||
|
logic rst_n_i = 1'b0;
|
||||||
|
logic lp_irq_o;
|
||||||
|
logic hp_irq_o;
|
||||||
|
logic [31:0] value;
|
||||||
|
apb4_if apb4 (
|
||||||
|
.pclk (clk_i),
|
||||||
|
.presetn(rst_n_i)
|
||||||
|
);
|
||||||
|
|
||||||
|
always #5 clk_i = ~clk_i;
|
||||||
|
|
||||||
|
apb4_hp_mailbox u_dut (
|
||||||
|
.clk_i,
|
||||||
|
.rst_n_i,
|
||||||
|
.apb4,
|
||||||
|
.lp_irq_o,
|
||||||
|
.hp_irq_o
|
||||||
|
);
|
||||||
|
|
||||||
|
task automatic apb_write(input logic [31:0] address, input logic [31:0] data);
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
apb4.paddr = address;
|
||||||
|
apb4.pwdata = data;
|
||||||
|
apb4.pstrb = 4'hf;
|
||||||
|
apb4.pwrite = 1'b1;
|
||||||
|
apb4.psel = 1'b1;
|
||||||
|
apb4.penable = 1'b1;
|
||||||
|
while (!apb4.pready) @(negedge clk_i);
|
||||||
|
apb4.psel = 1'b0;
|
||||||
|
apb4.penable = 1'b0;
|
||||||
|
apb4.pwrite = 1'b0;
|
||||||
|
apb4.pstrb = '0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic apb_read(input logic [31:0] address, output logic [31:0] data);
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
apb4.paddr = address;
|
||||||
|
apb4.pstrb = '0;
|
||||||
|
apb4.pwrite = 1'b0;
|
||||||
|
apb4.psel = 1'b1;
|
||||||
|
apb4.penable = 1'b1;
|
||||||
|
while (!apb4.pready) @(negedge clk_i);
|
||||||
|
data = apb4.prdata;
|
||||||
|
apb4.psel = 1'b0;
|
||||||
|
apb4.penable = 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
apb4.psel = 1'b0;
|
||||||
|
apb4.penable = 1'b0;
|
||||||
|
apb4.pwrite = 1'b0;
|
||||||
|
apb4.paddr = '0;
|
||||||
|
apb4.pwdata = '0;
|
||||||
|
apb4.pstrb = '0;
|
||||||
|
repeat (4) @(posedge clk_i);
|
||||||
|
rst_n_i = 1'b1;
|
||||||
|
|
||||||
|
apb_read(32'h0, value);
|
||||||
|
if (value != 32'h0001_0000) $fatal(1, "mailbox version mismatch");
|
||||||
|
apb_write(32'h44, 32'h1);
|
||||||
|
apb_write(32'h10, 32'h1);
|
||||||
|
apb_write(32'h18, 32'h1234);
|
||||||
|
apb_write(32'h1c, 32'h1);
|
||||||
|
if (!hp_irq_o) $fatal(1, "LP-to-HP doorbell did not assert");
|
||||||
|
apb_read(32'h18, value);
|
||||||
|
if (value != 32'h1234) $fatal(1, "LP sequence did not persist");
|
||||||
|
apb_write(32'h40, 32'h1);
|
||||||
|
if (hp_irq_o) $fatal(1, "HP interrupt did not clear");
|
||||||
|
|
||||||
|
apb_write(32'h34, 32'h1);
|
||||||
|
apb_write(32'h20, 32'h1);
|
||||||
|
apb_write(32'h2c, 32'h1);
|
||||||
|
if (!lp_irq_o) $fatal(1, "HP-to-LP doorbell did not assert");
|
||||||
|
apb_write(32'h30, 32'h1);
|
||||||
|
if (lp_irq_o) $fatal(1, "LP interrupt did not clear");
|
||||||
|
|
||||||
|
$display("HP mailbox register and doorbell test passed");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module plic_tb;
|
||||||
|
logic clk_i = 1'b0;
|
||||||
|
logic rst_n_i = 1'b0;
|
||||||
|
logic [31:0] source_i = '0;
|
||||||
|
logic [ 1:0] context_irq_o;
|
||||||
|
logic [31:0] value;
|
||||||
|
apb4_if apb4 (
|
||||||
|
.pclk (clk_i),
|
||||||
|
.presetn(rst_n_i)
|
||||||
|
);
|
||||||
|
|
||||||
|
always #5 clk_i = ~clk_i;
|
||||||
|
|
||||||
|
apb4_plic u_dut (
|
||||||
|
.clk_i,
|
||||||
|
.rst_n_i,
|
||||||
|
.source_i,
|
||||||
|
.apb4,
|
||||||
|
.context_irq_o
|
||||||
|
);
|
||||||
|
|
||||||
|
task automatic apb_write(input logic [31:0] address, input logic [31:0] data);
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
apb4.paddr = address;
|
||||||
|
apb4.pwdata = data;
|
||||||
|
apb4.pstrb = 4'hf;
|
||||||
|
apb4.pwrite = 1'b1;
|
||||||
|
apb4.psel = 1'b1;
|
||||||
|
apb4.penable = 1'b1;
|
||||||
|
while (!apb4.pready) @(negedge clk_i);
|
||||||
|
if (apb4.pslverr) $fatal(1, "PLIC write failed at %h", address);
|
||||||
|
apb4.psel = 1'b0;
|
||||||
|
apb4.penable = 1'b0;
|
||||||
|
apb4.pwrite = 1'b0;
|
||||||
|
apb4.pstrb = '0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task automatic apb_read(input logic [31:0] address, output logic [31:0] data);
|
||||||
|
begin
|
||||||
|
@(negedge clk_i);
|
||||||
|
apb4.paddr = address;
|
||||||
|
apb4.pstrb = '0;
|
||||||
|
apb4.pwrite = 1'b0;
|
||||||
|
apb4.psel = 1'b1;
|
||||||
|
apb4.penable = 1'b1;
|
||||||
|
while (!apb4.pready) @(negedge clk_i);
|
||||||
|
if (apb4.pslverr) $fatal(1, "PLIC read failed at %h", address);
|
||||||
|
data = apb4.prdata;
|
||||||
|
apb4.psel = 1'b0;
|
||||||
|
apb4.penable = 1'b0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
apb4.psel = 1'b0;
|
||||||
|
apb4.penable = 1'b0;
|
||||||
|
apb4.pwrite = 1'b0;
|
||||||
|
apb4.paddr = '0;
|
||||||
|
apb4.pwdata = '0;
|
||||||
|
apb4.pstrb = '0;
|
||||||
|
repeat (4) @(posedge clk_i);
|
||||||
|
rst_n_i = 1'b1;
|
||||||
|
|
||||||
|
apb_write(32'h0000_0004, 32'd3);
|
||||||
|
apb_write(32'h0000_0008, 32'd5);
|
||||||
|
apb_write(32'h0000_2080, 32'h0000_0006);
|
||||||
|
apb_write(32'h0020_1000, 32'd0);
|
||||||
|
source_i[1] = 1'b1;
|
||||||
|
source_i[2] = 1'b1;
|
||||||
|
repeat (2) @(posedge clk_i);
|
||||||
|
if (!context_irq_o[1]) $fatal(1, "supervisor context IRQ did not assert");
|
||||||
|
apb_read(32'h0020_1004, value);
|
||||||
|
if (value != 32'd2) $fatal(1, "highest-priority source was not claimed");
|
||||||
|
source_i[2] = 1'b0;
|
||||||
|
apb_write(32'h0020_1004, 32'd2);
|
||||||
|
repeat (2) @(posedge clk_i);
|
||||||
|
apb_read(32'h0020_1004, value);
|
||||||
|
if (value != 32'd1) $fatal(1, "remaining source was not claimed");
|
||||||
|
source_i[1] = 1'b0;
|
||||||
|
apb_write(32'h0020_1004, 32'd1);
|
||||||
|
repeat (2) @(posedge clk_i);
|
||||||
|
if (context_irq_o[1]) $fatal(1, "supervisor context IRQ did not clear");
|
||||||
|
|
||||||
|
$display("PLIC priority, claim, and completion test passed");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
@@ -120,14 +120,27 @@ module pll_ctrl_tb;
|
|||||||
endtask
|
endtask
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
apb4.psel = 1'b0;
|
apb4.psel = 1'b0;
|
||||||
apb4.paddr = '0;
|
apb4.paddr = '0;
|
||||||
apb4.pwdata = '0;
|
apb4.pwdata = '0;
|
||||||
apb4.pstrb = '0;
|
apb4.pstrb = '0;
|
||||||
sysctrl.user_bus_idle_i = 1'b1;
|
sysctrl.user_bus_idle_i = 1'b1;
|
||||||
sysctrl.fault_access_i = 1'b0;
|
sysctrl.fault_access_i = 1'b0;
|
||||||
sysctrl.fault_master_i = '0;
|
sysctrl.fault_master_i = '0;
|
||||||
sysctrl.rtc_wake_i = 1'b0;
|
sysctrl.fault_code_i = '0;
|
||||||
|
sysctrl.perf_mgmt_wait_i = '0;
|
||||||
|
sysctrl.perf_user_wait_i = '0;
|
||||||
|
sysctrl.perf_dma_wait_i = '0;
|
||||||
|
sysctrl.perf_sdio0_wait_i = '0;
|
||||||
|
sysctrl.perf_sdio1_wait_i = '0;
|
||||||
|
sysctrl.perf_usb2_wait_i = '0;
|
||||||
|
sysctrl.perf_apb4_periph_wait_i = '0;
|
||||||
|
sysctrl.perf_apb4_system_wait_i = '0;
|
||||||
|
sysctrl.perf_sdram_wait_i = '0;
|
||||||
|
sysctrl.perf_psram_wait_i = '0;
|
||||||
|
sysctrl.perf_flash_wait_i = '0;
|
||||||
|
sysctrl.rtc_wake_i = 1'b0;
|
||||||
|
sysctrl.hp_present_i = 1'b0;
|
||||||
#100;
|
#100;
|
||||||
rst_n_i = 1'b1;
|
rst_n_i = 1'b1;
|
||||||
repeat (2) begin
|
repeat (2) begin
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ module soc_irq_topology_tb;
|
|||||||
17: expect_irq(32'd1 << 21);
|
17: expect_irq(32'd1 << 21);
|
||||||
18: expect_irq(32'd1 << 23);
|
18: expect_irq(32'd1 << 23);
|
||||||
19: expect_irq(32'd1 << 24);
|
19: expect_irq(32'd1 << 24);
|
||||||
|
20: expect_irq(32'd1 << 25);
|
||||||
|
21: expect_irq(32'd1 << 26);
|
||||||
default: expect_irq(32'd1 << (bit_index + 7));
|
default: expect_irq(32'd1 << (bit_index + 7));
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
@@ -64,7 +66,7 @@ module soc_irq_topology_tb;
|
|||||||
$fatal(1, "SDIO core IRQ bits are not low when sources are low: IRQ10=%b IRQ21=%b",
|
$fatal(1, "SDIO core IRQ bits are not low when sources are low: IRQ10=%b IRQ21=%b",
|
||||||
s_irq[10], s_irq[21]);
|
s_irq[10], s_irq[21]);
|
||||||
end
|
end
|
||||||
if ((s_irq[31:25] !== '0) || (s_irq[19:18] !== '0)) begin
|
if ((s_irq[31:27] !== '0) || (s_irq[19:18] !== '0)) begin
|
||||||
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq);
|
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+28
-1
@@ -93,6 +93,7 @@ module sysctrl_tb;
|
|||||||
sysctrl.perf_psram_wait_i = 64'd17;
|
sysctrl.perf_psram_wait_i = 64'd17;
|
||||||
sysctrl.perf_flash_wait_i = 64'd18;
|
sysctrl.perf_flash_wait_i = 64'd18;
|
||||||
sysctrl.rtc_wake_i = 1'b0;
|
sysctrl.rtc_wake_i = 1'b0;
|
||||||
|
sysctrl.hp_present_i = 1'b0;
|
||||||
pll_ctrl.req_ready_i = 1'b1;
|
pll_ctrl.req_ready_i = 1'b1;
|
||||||
pll_ctrl.rsp_active_sel_i = '0;
|
pll_ctrl.rsp_active_sel_i = '0;
|
||||||
pll_ctrl.rsp_active_valid_i = 1'b0;
|
pll_ctrl.rsp_active_valid_i = 1'b0;
|
||||||
@@ -216,7 +217,33 @@ module sysctrl_tb;
|
|||||||
$fatal(1, "RTC wake sticky status W1C failed");
|
$fatal(1, "RTC wake sticky status W1C failed");
|
||||||
end
|
end
|
||||||
|
|
||||||
$display("SystemCtrl register, lifecycle, fault, performance, and RTC wake test passed");
|
read_register(32'h1000_B0A8, read_data);
|
||||||
|
if (read_data !== 32'h0000_0000) $fatal(1, "absent HP status was not zero");
|
||||||
|
write_register(32'h1000_B0A4, 32'h0000_0001);
|
||||||
|
write_register(32'h1000_B0AC, 32'h0000_0001);
|
||||||
|
if (sysctrl.hp_release_o || sysctrl.debug_hp_select_o) begin
|
||||||
|
$fatal(1, "absent HP accepted lifecycle control");
|
||||||
|
end
|
||||||
|
|
||||||
|
sysctrl.hp_present_i = 1'b1;
|
||||||
|
read_register(32'h1000_B0A8, read_data);
|
||||||
|
if (read_data !== 32'h0000_0005) $fatal(1, "present HP reset status mismatch");
|
||||||
|
write_register(32'h1000_B0AC, 32'h0000_0001);
|
||||||
|
if (!sysctrl.debug_hp_select_o) $fatal(1, "HP debug selection was not accepted in reset");
|
||||||
|
write_register(32'h1000_B0A4, 32'h0000_0001);
|
||||||
|
read_register(32'h1000_B0A8, read_data);
|
||||||
|
if ((read_data !== 32'h0000_0003) || !sysctrl.hp_release_o) begin
|
||||||
|
$fatal(1, "HP release status mismatch");
|
||||||
|
end
|
||||||
|
write_register(32'h1000_B0AC, 32'h0000_0000);
|
||||||
|
if (!sysctrl.debug_hp_select_o) $fatal(1, "running HP allowed JTAG selection change");
|
||||||
|
write_register(32'h1000_B0A4, 32'h0000_0000);
|
||||||
|
write_register(32'h1000_B0AC, 32'h0000_0000);
|
||||||
|
if (sysctrl.hp_release_o || sysctrl.debug_hp_select_o) begin
|
||||||
|
$fatal(1, "HP reset/debug return did not complete");
|
||||||
|
end
|
||||||
|
|
||||||
|
$display("SystemCtrl register, lifecycle, fault, performance, RTC wake, and HP test passed");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
@@ -12,6 +12,49 @@ from pathlib import Path
|
|||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_axi4_downsizer_preserves_bursts_lanes_and_backpressure(
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
verilator = shutil.which("verilator")
|
||||||
|
if verilator is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
output = tmp_path / "axi4_downsizer_64to32_tb"
|
||||||
|
ccache_tmp = tmp_path / "ccache"
|
||||||
|
ccache_tmp.mkdir()
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
verilator,
|
||||||
|
"--binary",
|
||||||
|
"--timing",
|
||||||
|
"-Wno-fatal",
|
||||||
|
"--top-module",
|
||||||
|
"axi4_downsizer_64to32_tb",
|
||||||
|
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||||
|
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||||
|
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||||
|
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||||
|
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_addr_gen.sv"),
|
||||||
|
str(ROOT / "rtl/mini/top/axi4_downsizer_64to32.sv"),
|
||||||
|
str(ROOT / "tests/rtl/axi4_downsizer_64to32_tb.sv"),
|
||||||
|
"-Mdir",
|
||||||
|
str(tmp_path / "obj"),
|
||||||
|
"-o",
|
||||||
|
str(output),
|
||||||
|
],
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
env={
|
||||||
|
**os.environ,
|
||||||
|
"CCACHE_DIR": str(ccache_tmp),
|
||||||
|
"CCACHE_TEMPDIR": str(ccache_tmp),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
result = subprocess.run([output], check=True, text=True, capture_output=True)
|
||||||
|
assert "AXI4 64-to-32 downsizer test passed" in result.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_axi4_word_bridge_supports_bursts_backpressure_and_errors(tmp_path: Path) -> None:
|
def test_axi4_word_bridge_supports_bursts_backpressure_and_errors(tmp_path: Path) -> None:
|
||||||
verilator = shutil.which("verilator")
|
verilator = shutil.which("verilator")
|
||||||
if verilator is None:
|
if verilator is None:
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
"""HP flash bundle and handwritten mailbox ABI tests."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import importlib.util
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import zlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
PACKAGER = ROOT / "scripts/package_hp_boot.py"
|
||||||
|
MAILBOX_RTL = ROOT / "rtl/ip/peripheral/hp_mailbox_define.svh"
|
||||||
|
MAILBOX_C = ROOT / "crt/src/hal/hp_mailbox.c"
|
||||||
|
|
||||||
|
|
||||||
|
def load_packager():
|
||||||
|
spec = importlib.util.spec_from_file_location("package_hp_boot", PACKAGER)
|
||||||
|
assert spec is not None and spec.loader is not None
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
def test_hp_boot_bundle_layout_crc_and_payloads(tmp_path: Path) -> None:
|
||||||
|
module = load_packager()
|
||||||
|
firmware = tmp_path / "lp.bin"
|
||||||
|
firmware.write_bytes(b"LP" * 32)
|
||||||
|
images = tmp_path / "images"
|
||||||
|
images.mkdir()
|
||||||
|
expected: dict[str, bytes] = {}
|
||||||
|
for index, (_, name, _, _) in enumerate(module.ARTIFACTS, start=1):
|
||||||
|
expected[name] = bytes([index]) * (31 + index)
|
||||||
|
(images / name).write_bytes(expected[name])
|
||||||
|
|
||||||
|
output = tmp_path / "boot.bin"
|
||||||
|
manifest = tmp_path / "boot.json"
|
||||||
|
module.package(
|
||||||
|
argparse.Namespace(
|
||||||
|
firmware=firmware,
|
||||||
|
images=images,
|
||||||
|
output=output,
|
||||||
|
manifest=manifest,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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 = (
|
||||||
|
header_values
|
||||||
|
)
|
||||||
|
assert magic == module.MAGIC
|
||||||
|
assert version == module.VERSION
|
||||||
|
assert header_size == module.HEADER_SIZE == 128
|
||||||
|
assert entry_count == len(module.ARTIFACTS) == 4
|
||||||
|
assert total_size == len(image) - module.BUNDLE_OFFSET
|
||||||
|
assert flags == module.REQUIRED
|
||||||
|
assert reserved == 0
|
||||||
|
|
||||||
|
header = bytearray(image[module.BUNDLE_OFFSET : module.BUNDLE_OFFSET + header_size])
|
||||||
|
struct.pack_into("<I", header, 20, 0)
|
||||||
|
assert zlib.crc32(header) & 0xFFFFFFFF == header_crc
|
||||||
|
for index, (_, name, load_address, _) in enumerate(module.ARTIFACTS):
|
||||||
|
entry_offset = module.BUNDLE_OFFSET + module.HEADER.size + index * module.ENTRY.size
|
||||||
|
kind, flash_offset, entry_address, size, crc32, entry_flags = module.ENTRY.unpack_from(
|
||||||
|
image, entry_offset
|
||||||
|
)
|
||||||
|
assert kind == index + 1
|
||||||
|
assert entry_address == load_address
|
||||||
|
assert image[flash_offset : flash_offset + size] == expected[name]
|
||||||
|
assert zlib.crc32(expected[name]) & 0xFFFFFFFF == crc32
|
||||||
|
assert entry_flags == module.REQUIRED
|
||||||
|
|
||||||
|
|
||||||
|
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(
|
||||||
|
r"^#define\s+RS_HP_MAILBOX_(\w+)_OFFSET\s+UINT32_C\(0x([0-9A-Fa-f]+)\)$"
|
||||||
|
)
|
||||||
|
rtl = {
|
||||||
|
match.group(1): int(match.group(2), 16)
|
||||||
|
for line in MAILBOX_RTL.read_text(encoding="utf-8").splitlines()
|
||||||
|
if (match := rtl_pattern.match(line)) is not None
|
||||||
|
}
|
||||||
|
c = {
|
||||||
|
match.group(1): int(match.group(2), 16)
|
||||||
|
for line in MAILBOX_C.read_text(encoding="utf-8").splitlines()
|
||||||
|
if (match := c_pattern.match(line)) is not None
|
||||||
|
}
|
||||||
|
assert c == {
|
||||||
|
name: rtl[name]
|
||||||
|
for name in (
|
||||||
|
"IP_VERSION",
|
||||||
|
"CAPABILITY",
|
||||||
|
"LP_COMMAND",
|
||||||
|
"LP_ARG0",
|
||||||
|
"LP_SEQUENCE",
|
||||||
|
"LP_DOORBELL",
|
||||||
|
"HP_EVENT",
|
||||||
|
"HP_ARG0",
|
||||||
|
"HP_SEQUENCE",
|
||||||
|
"LP_INTR_STATE",
|
||||||
|
"LP_INTR_ENABLE",
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
"""HP mailbox RTL regression test."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_hp_mailbox_registers_and_doorbells(tmp_path: Path) -> None:
|
||||||
|
iverilog = shutil.which("iverilog")
|
||||||
|
vvp = shutil.which("vvp")
|
||||||
|
if iverilog is None or vvp is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
common = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||||
|
peripheral = ROOT / "rtl/ip/peripheral"
|
||||||
|
filelist = tmp_path / "hp_mailbox.fl"
|
||||||
|
filelist.write_text(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"+define+SV_ASSRT_DISABLE",
|
||||||
|
f"+incdir+{common}",
|
||||||
|
f"+incdir+{common / 'interface'}",
|
||||||
|
f"+incdir+{common / 'utils'}",
|
||||||
|
f"+incdir+{peripheral}",
|
||||||
|
str(common / "interface/apb4_if.sv"),
|
||||||
|
str(common / "utils/register.sv"),
|
||||||
|
str(peripheral / "apb4_hp_mailbox.sv"),
|
||||||
|
str(ROOT / "tests/rtl/hp_mailbox_tb.sv"),
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
converted = tmp_path / "hp_mailbox_tb.v"
|
||||||
|
subprocess.run(
|
||||||
|
[sys.executable, str(ROOT / "rtl/mini/script/convt_sv2v.py"), "-f", str(filelist),
|
||||||
|
"--output", str(converted)],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
simulation = tmp_path / "hp_mailbox_tb"
|
||||||
|
subprocess.run(
|
||||||
|
[iverilog, "-g2012", "-s", "hp_mailbox_tb", "-o", str(simulation), str(converted)],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
|
||||||
|
assert "HP mailbox register and doorbell test passed" in result.stdout
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
"""HP platform configuration and generated-source boundary tests."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_hp_profile_and_locked_generator_contract() -> None:
|
||||||
|
lock = json.loads((ROOT / "dependencies/dependencies.lock.json").read_text(encoding="utf-8"))
|
||||||
|
vexii = lock["sources"]["vexiiriscv"]
|
||||||
|
assert vexii["revision"] == "ef7da4134ff11ec6a681d0632123b232b853b046"
|
||||||
|
assert vexii["recursive"] is True
|
||||||
|
assert vexii["destination"].startswith(".cache/")
|
||||||
|
|
||||||
|
profile = (ROOT / "configs/ci/ihp130-hp.mk").read_text(encoding="utf-8")
|
||||||
|
assert "HAVE_HP" in profile and "YES" in profile
|
||||||
|
assert "rv32imafdc_max" in profile
|
||||||
|
assert "APP" in profile and "hp_boot" in profile
|
||||||
|
assert "LINK_TYPE" in profile and "ld2_all_sram" in profile
|
||||||
|
|
||||||
|
generator = (ROOT / "scripts/vexiiriscv/GenerateRetroSocHp.scala").read_text(
|
||||||
|
encoding="utf-8"
|
||||||
|
)
|
||||||
|
for requirement in (
|
||||||
|
'param.addISA("m", "a", "f", "d", "c", "s", "u", "zicntr", "zihpm")',
|
||||||
|
"param.decoders = 2",
|
||||||
|
"param.lanes = 2",
|
||||||
|
"param.fetchL1Ways = 4",
|
||||||
|
"param.lsuL1Ways = 4",
|
||||||
|
"param.resetVector = 0x38000000L",
|
||||||
|
"param.plugins(hartId = 1)",
|
||||||
|
):
|
||||||
|
assert requirement in generator
|
||||||
|
|
||||||
|
|
||||||
|
def test_makefile_uses_path_resolved_sbt() -> None:
|
||||||
|
makefile = (ROOT / "Makefile").read_text(encoding="utf-8")
|
||||||
|
assert "SBT ?= sbt" in makefile
|
||||||
|
assert "/nfs/home/miaoyuchi/sbt/bin/sbt" not in makefile
|
||||||
|
|
||||||
|
|
||||||
|
def test_hp_address_and_sysctrl_contract() -> None:
|
||||||
|
document = json.loads(
|
||||||
|
(ROOT / "rtl/mini/address_map/memory_map.json").read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
regions = {region["symbol"]: region for region in document["regions"]}
|
||||||
|
assert regions["HP_ACLINT"]["base"] == "0x02000000"
|
||||||
|
assert regions["HP_PLIC"]["base"] == "0x0C000000"
|
||||||
|
assert regions["APB4_UART1"]["base"] == "0x10018000"
|
||||||
|
assert regions["APB4_HP_MAILBOX"]["base"] == "0x10019000"
|
||||||
|
|
||||||
|
registers = {register["symbol"]: register["offset"] for register in document["sysctrl_registers"]}
|
||||||
|
assert registers["HP_CTRL"] == "0xA4"
|
||||||
|
assert registers["HP_STATUS"] == "0xA8"
|
||||||
|
assert registers["DEBUG_SELECT"] == "0xAC"
|
||||||
|
|
||||||
|
|
||||||
|
def test_generated_vexii_rtl_is_not_tracked() -> None:
|
||||||
|
tracked = subprocess.run(
|
||||||
|
["git", "ls-files", "*vexii_riscv_hp_generated*"],
|
||||||
|
cwd=ROOT,
|
||||||
|
check=True,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
).stdout
|
||||||
|
assert tracked == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_hp_smoke_payload_uses_hart1_platform_abi() -> None:
|
||||||
|
source = (ROOT / "app/ports/linux/smoke/start.S").read_text(encoding="utf-8")
|
||||||
|
assert "0x10018000" in source
|
||||||
|
assert "0x10019000" in source
|
||||||
|
assert "0x4c4e5801" in source.lower()
|
||||||
|
assert "HP_SMOKE_READY" in source
|
||||||
|
|
||||||
|
|
||||||
|
def test_linux_build_uses_external_opensbi_platform_and_actual_initrd_end() -> None:
|
||||||
|
build = (ROOT / "scripts/build_hp_linux.py").read_text(encoding="utf-8")
|
||||||
|
assert '"tinyconfig"' in build
|
||||||
|
assert 'environment.pop("MAKEOVERRIDES", None)' in build
|
||||||
|
assert '"PLATFORM=retrosoc_hp"' in build
|
||||||
|
assert 'f"PLATFORM_DIR={external / \'opensbi\'}"' in build
|
||||||
|
assert '"fdtput"' in build
|
||||||
|
assert '"linux,initrd-end"' in build
|
||||||
|
|
||||||
|
platform = (
|
||||||
|
ROOT / "app/ports/linux/opensbi/retrosoc_hp/platform.c"
|
||||||
|
).read_text(encoding="utf-8")
|
||||||
|
assert "s_hart_index_to_id[] = {1U}" in platform
|
||||||
|
assert "RETROSOC_HP_UART_BASE" in platform
|
||||||
|
assert "aclint_mtimer_cold_init" in platform
|
||||||
|
|
||||||
|
|
||||||
|
def test_hp_linux_device_tree_compiles_and_can_patch_initrd_end(tmp_path: Path) -> None:
|
||||||
|
dtc = shutil.which("dtc")
|
||||||
|
fdtput = shutil.which("fdtput")
|
||||||
|
fdtget = shutil.which("fdtget")
|
||||||
|
if dtc is None or fdtput is None or fdtget is None:
|
||||||
|
return
|
||||||
|
dtb = tmp_path / "retrosoc_hp.dtb"
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
dtc,
|
||||||
|
"-I",
|
||||||
|
"dts",
|
||||||
|
"-O",
|
||||||
|
"dtb",
|
||||||
|
"-o",
|
||||||
|
str(dtb),
|
||||||
|
str(ROOT / "app/ports/linux/linux/retrosoc_hp.dts"),
|
||||||
|
],
|
||||||
|
check=True,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
subprocess.run(
|
||||||
|
[fdtput, "-t", "x", str(dtb), "/chosen", "linux,initrd-end", "0x39123456"],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
initrd_end = subprocess.check_output(
|
||||||
|
[fdtget, "-t", "x", str(dtb), "/chosen", "linux,initrd-end"], text=True
|
||||||
|
).strip()
|
||||||
|
hart_id = subprocess.check_output(
|
||||||
|
[fdtget, "-t", "x", str(dtb), "/cpus/cpu@1", "reg"], text=True
|
||||||
|
).strip()
|
||||||
|
assert initrd_end == "39123456"
|
||||||
|
assert hart_id == "1"
|
||||||
@@ -44,10 +44,10 @@ def test_chip_config_places_every_signal_and_power_pad_once(tmp_path: Path) -> N
|
|||||||
sides = {name: config[f"PAD_{name.upper()}"] for name in module.SIDE_ORDER}
|
sides = {name: config[f"PAD_{name.upper()}"] for name in module.SIDE_ORDER}
|
||||||
placed = [instance for side in module.SIDE_ORDER for instance in sides[side]]
|
placed = [instance for side in module.SIDE_ORDER for instance in sides[side]]
|
||||||
|
|
||||||
assert len(placed) == 189
|
assert len(placed) == 191
|
||||||
assert len(placed) == len(set(placed))
|
assert len(placed) == len(set(placed))
|
||||||
assert {side: len(instances) for side, instances in sides.items()} == {
|
assert {side: len(instances) for side, instances in sides.items()} == {
|
||||||
"south": 30,
|
"south": 32,
|
||||||
"east": 52,
|
"east": 52,
|
||||||
"north": 48,
|
"north": 48,
|
||||||
"west": 59,
|
"west": 59,
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from scripts.check_lp_hp_performance import compare as compare_lp_hp
|
||||||
from scripts.parse_coremark_log import parse_log as parse_coremark_log
|
from scripts.parse_coremark_log import parse_log as parse_coremark_log
|
||||||
from scripts.parse_performance_log import parse_log
|
from scripts.parse_performance_log import parse_log
|
||||||
|
|
||||||
@@ -91,3 +94,21 @@ def test_parse_coremark_rejects_failure_or_non_sram_result() -> None:
|
|||||||
assert "SRAM" in str(error)
|
assert "SRAM" in str(error)
|
||||||
else:
|
else:
|
||||||
raise AssertionError("non-SRAM CoreMark result was accepted")
|
raise AssertionError("non-SRAM CoreMark result was accepted")
|
||||||
|
|
||||||
|
|
||||||
|
def test_lp_hp_coremark_ratio_gate() -> None:
|
||||||
|
lp = parse_coremark_log(
|
||||||
|
"COREMARK_RESULT mode=quick qualified=0 memory=sram iterations=4 cycles=2000 "
|
||||||
|
"cpu_hz=72000000\nCOREMARK_PASS\n"
|
||||||
|
)
|
||||||
|
hp = parse_coremark_log(
|
||||||
|
"COREMARK_RESULT mode=quick qualified=0 memory=sram iterations=12 cycles=2000 "
|
||||||
|
"cpu_hz=72000000\nCOREMARK_PASS\n"
|
||||||
|
)
|
||||||
|
report = compare_lp_hp(lp, hp, Decimal("2.5"))
|
||||||
|
assert report["status"] == "passed"
|
||||||
|
assert report["measured_ratio"] == "3.000"
|
||||||
|
|
||||||
|
hp["results"][0]["coremark_per_mhz"] = "4000.000"
|
||||||
|
report = compare_lp_hp(lp, hp, Decimal("2.5"))
|
||||||
|
assert report["status"] == "failed"
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
"""HP PLIC RTL regression test."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_plic_priority_claim_and_completion(tmp_path: Path) -> None:
|
||||||
|
iverilog = shutil.which("iverilog")
|
||||||
|
vvp = shutil.which("vvp")
|
||||||
|
if iverilog is None or vvp is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
common = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||||
|
peripheral = ROOT / "rtl/ip/peripheral"
|
||||||
|
filelist = tmp_path / "plic.fl"
|
||||||
|
filelist.write_text(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"+define+SV_ASSRT_DISABLE",
|
||||||
|
f"+incdir+{common}",
|
||||||
|
f"+incdir+{common / 'interface'}",
|
||||||
|
f"+incdir+{common / 'utils'}",
|
||||||
|
str(common / "interface/apb4_if.sv"),
|
||||||
|
str(common / "utils/register.sv"),
|
||||||
|
str(peripheral / "apb4_plic.sv"),
|
||||||
|
str(ROOT / "tests/rtl/plic_tb.sv"),
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
converted = tmp_path / "plic_tb.v"
|
||||||
|
subprocess.run(
|
||||||
|
[sys.executable, str(ROOT / "rtl/mini/script/convt_sv2v.py"), "-f", str(filelist),
|
||||||
|
"--output", str(converted)],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
simulation = tmp_path / "plic_tb"
|
||||||
|
subprocess.run(
|
||||||
|
[iverilog, "-g2012", "-s", "plic_tb", "-o", str(simulation), str(converted)],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
|
||||||
|
assert "PLIC priority, claim, and completion test passed" in result.stdout
|
||||||
@@ -75,7 +75,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
|||||||
irq_sva = (tmp_path / "rtl/soc_irq_sva.svh").read_text(encoding="utf-8")
|
irq_sva = (tmp_path / "rtl/soc_irq_sva.svh").read_text(encoding="utf-8")
|
||||||
filelist = (tmp_path / "soc_topology.fl").read_text(encoding="utf-8")
|
filelist = (tmp_path / "soc_topology.fl").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert interfaces.count("apb4_if u_") == 20
|
assert interfaces.count("apb4_if u_") == 24
|
||||||
assert "nmi_if" not in interfaces
|
assert "nmi_if" not in interfaces
|
||||||
assert "soc_nmi" not in interfaces
|
assert "soc_nmi" not in interfaces
|
||||||
assert "assign s_psel_comb[17] = `SOC_ADDR_IS_APB4_I2C1(s_decode_addr);" in routes
|
assert "assign s_psel_comb[17] = `SOC_ADDR_IS_APB4_I2C1(s_decode_addr);" in routes
|
||||||
@@ -86,6 +86,10 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
|||||||
assert "assign s_psel_comb[18] = `SOC_ADDR_IS_APB4_SDIO1(s_decode_addr);" in routes
|
assert "assign s_psel_comb[18] = `SOC_ADDR_IS_APB4_SDIO1(s_decode_addr);" in routes
|
||||||
assert "assign s_psel_comb[19] = `SOC_ADDR_IS_APB4_CRYPTO(s_decode_addr);" in routes
|
assert "assign s_psel_comb[19] = `SOC_ADDR_IS_APB4_CRYPTO(s_decode_addr);" in routes
|
||||||
assert "assign s_psel_comb[20] = `SOC_ADDR_IS_APB4_USB2(s_decode_addr);" in routes
|
assert "assign s_psel_comb[20] = `SOC_ADDR_IS_APB4_USB2(s_decode_addr);" in routes
|
||||||
|
assert "assign s_psel_comb[22] = `SOC_ADDR_IS_APB4_UART1(s_decode_addr);" in routes
|
||||||
|
assert "assign s_psel_comb[23] = `SOC_ADDR_IS_APB4_HP_MAILBOX(s_decode_addr);" in routes
|
||||||
|
assert "assign s_psel_comb[24] = `SOC_ADDR_IS_HP_ACLINT(s_decode_addr);" in routes
|
||||||
|
assert "assign s_psel_comb[25] = `SOC_ADDR_IS_HP_PLIC(s_decode_addr);" in routes
|
||||||
assert gpio.count("// GPIO") == 64
|
assert gpio.count("// GPIO") == 64
|
||||||
assert "u_uart1_if" not in gpio
|
assert "u_uart1_if" not in gpio
|
||||||
assert "assign u_uart0_if.cts_n_i = u_gpio_if.di_i[0];" in gpio
|
assert "assign u_uart0_if.cts_n_i = u_gpio_if.di_i[0];" in gpio
|
||||||
@@ -132,7 +136,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
|||||||
assert ".usb2_axi4(u_usb2_axi4_if)" in apb_periph_fabric
|
assert ".usb2_axi4(u_usb2_axi4_if)" in apb_periph_fabric
|
||||||
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
|
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
|
||||||
assert "`define SOC_USER_IRQ_MASK 32'h004EFBFC" in irq_config
|
assert "`define SOC_USER_IRQ_MASK 32'h004EFBFC" in irq_config
|
||||||
assert "`define SOC_IRQ_APB4_PERIPH_WIDTH 20" in irq_config
|
assert "`define SOC_IRQ_APB4_PERIPH_WIDTH 22" in irq_config
|
||||||
assert "`define SOC_IRQ_APB4_SYSTEM_WIDTH 5" in irq_config
|
assert "`define SOC_IRQ_APB4_SYSTEM_WIDTH 5" in irq_config
|
||||||
assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq
|
assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq
|
||||||
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
|
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
|
||||||
@@ -206,6 +210,8 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
|||||||
("sdio1", "apb4_periph", 17, 21, "sdio1.irq_o"),
|
("sdio1", "apb4_periph", 17, 21, "sdio1.irq_o"),
|
||||||
("crypto", "apb4_periph", 18, 23, "s_crypto_irq"),
|
("crypto", "apb4_periph", 18, 23, "s_crypto_irq"),
|
||||||
("usb2", "apb4_periph", 19, 24, "s_usb2_irq"),
|
("usb2", "apb4_periph", 19, 24, "s_usb2_irq"),
|
||||||
|
("hp_mailbox_lp", "apb4_periph", 20, 25, "s_mailbox_lp_irq"),
|
||||||
|
("uart1", "apb4_periph", 21, 26, "uart1.irq_o"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loaded 100 of 101 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user