feat: refactor NMI interface and remove unused variables

- Removed CORE and IP variables from common.tcl and synth.tcl scripts.
- Updated yosys.mk to exclude CORE and IP from environment variables.
- Modified bus_fault_tb to enhance NMI interface with management and user NMI signals.
- Added user access denial handling in bus_fault_tb.
- Updated pll_ctrl_tb and sysctrl_fault_tb to reflect changes in NMI interface.
- Adjusted test_gpio_user_mux.py to remove IP_MDD definition.
- Enhanced memory map tests to include user extensions and ensure proper generation.
- Updated test_script_tools.py to reflect changes in core management and user extensions.
- Refined topology tests to ensure user APB target is always added.
- Adjusted tech cell configuration tests to use simplified profile paths.
- Improved user extensions tests for scalar bindings and slot validation.
This commit is contained in:
maksyuki committed 2026-07-26 09:03:33 +08:00
1 parent 3f98ad646c
commit 7a604ec86b
111 files changed
+3729 -2012

No files matched your search

+1 -1
View File
@@ -18,5 +18,5 @@ jobs:
with:
suite: nightly
pdk: IHP130
profile: configs/ci/hazard3-rv32im-ihp130.mk
profile: configs/ci/ihp130.mk
retention_days: 90
+1 -1
View File
@@ -20,5 +20,5 @@ jobs:
with:
suite: pr
pdk: GF180
profile: configs/ci/hazard3-rv32im-gf180.mk
profile: configs/ci/gf180.mk
retention_days: 30
+1 -1
View File
@@ -20,5 +20,5 @@ jobs:
with:
suite: pr
pdk: IHP130
profile: configs/ci/hazard3-rv32im-ihp130.mk
profile: configs/ci/ihp130.mk
retention_days: 30
+1 -1
View File
@@ -20,5 +20,5 @@ jobs:
with:
suite: pr
pdk: SKY130
profile: configs/ci/hazard3-rv32im-sky130.mk
profile: configs/ci/sky130.mk
retention_days: 30
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
with:
suite: smoke
pdk: IHP130
profile: configs/ci/hazard3-rv32im-ihp130.mk
profile: configs/ci/ihp130.mk
retention_days: 14
timeout_minutes: 60
toolset: verilator sv2v iverilog yosys sby bitwuzla riscv_gnu
+2 -2
View File
@@ -47,10 +47,10 @@ jobs:
run: python3 -m pip install --requirement requirements/build.txt
- name: Set up locked source dependencies
run: make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk setup
run: make CONFIG=configs/ci/ihp130.mk setup
- name: Build checksummed source package and SBOM
run: make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk package
run: make CONFIG=configs/ci/ihp130.mk package
- name: Upload workflow artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
+12 -13
View File
@@ -18,7 +18,12 @@ CONFIG_PATH :=
PROFILE_NAME := manual
endif
ifneq ($(origin IP),undefined)
$(error IP is no longer configurable; user IP integration is fixed)
endif
SOC ?= MINI
CORE ?= HAZARD3
SIMU ?= VCS
SYNTH ?= NONE
STA ?= NONE
@@ -32,15 +37,12 @@ HAVE_SVA ?= NO
WAVE ?= NO
FORMAL ?= NO
RTL_SIM_CORESEL ?= 0
RTL_SIM_TIMEOUT ?= -1
SIM_FIRMWARE_NAME ?= $(FIRMWARE_NAME)
SIM_SUCCESS_MARKER ?= retroSoC: A Customized ASIC for Retro Stuff
RTL_PATH := $(ROOT_PATH)/rtl/mini
CORE ?= HAZARD3
IP ?= NONE
RTL_TOP ?= retrosoc_tb
# SW
@@ -61,7 +63,7 @@ VERIBLE_FORMAT ?= verible-verilog-format
JOBS ?= $(shell count=$$(nproc 2>/dev/null || printf '1'); \
if [ "$$count" -gt "$(MAX_JOBS)" ]; then printf '%s' '$(MAX_JOBS)'; \
else printf '%s' "$$count"; fi)
CONFIG_KEY_VARS := SOC CORE IP PDK HAVE_PLL HAVE_SRAM_IF HAVE_SRAM_MACRO HAVE_SVA \
CONFIG_KEY_VARS := SOC CORE PDK HAVE_PLL HAVE_SRAM_IF HAVE_SRAM_MACRO HAVE_SVA \
ISA HAVE_CSR APP LINK_TYPE RTL_TOP FIRMWARE_NAME
VARIANT_ID := $(strip $(shell python3 $(ROOT_PATH)/scripts/config_key.py \
--lock $(LOCK_FILE) --profile $(PROFILE_NAME) --timestamp $(BUILD_TIMESTAMP) \
@@ -85,8 +87,7 @@ FLOW_FILELIST_DIR := $(SIM_BUILD_ROOT)/filelists
endif
VALID_SOC := MINI
VALID_CORE := PICORV32 HAZARD3 MDD
VALID_IP := NONE MDD
VALID_CORE := HAZARD3 PICORV32
VALID_SIMU := VCS VERILATOR IVERILOG
VALID_SYNTH := NONE YOSYS
VALID_STA := NONE OPENSTA
@@ -102,7 +103,6 @@ endef
$(call validate_value,SOC,$(VALID_SOC))
$(call validate_value,CORE,$(VALID_CORE))
$(call validate_value,IP,$(VALID_IP))
$(call validate_value,SIMU,$(VALID_SIMU))
$(call validate_value,SYNTH,$(VALID_SYNTH))
$(call validate_value,STA,$(VALID_STA))
@@ -131,9 +131,8 @@ endif
endif
DEF_LIST ?= +define+PDK_$(PDK)
DEF_LIST += +define+CORE_$(CORE)
DEF_LIST += +define+IP_$(IP)
DEF_LIST += +define+SIMU_$(SIMU)
DEF_LIST += +define+CORE_$(CORE)
ifeq ($(HAVE_PLL), YES)
ifneq ($(filter $(PDK),GF180 SKY130),)
@@ -200,7 +199,7 @@ help:
' check-user-extensions validate the canonical user-extension map' \
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
' formal | formal-bus | formal-nmi2apb | formal-sysctrl | formal-pll-rcu | formal-gpio-mdd run SBY protocol proofs' \
' formal | formal-bus | formal-nmi2apb | formal-sysctrl | formal-pll-rcu | formal-gpio-user run SBY protocol proofs' \
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
' tech-cell-test test GF180/SKY130 technology IO and clock wrappers' \
' check-warnings | metrics analyze flow logs and reports' \
@@ -219,14 +218,14 @@ help:
' clean | clean-all clean current flow or all build output' \
' purge-cache remove dependency and compiler caches' \
'' \
'Usage: make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG sim'
'Usage: make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG sim'
config:
@printf '%-18s %s\n' \
ROOT_PATH '$(ROOT_PATH)' CONFIG '$(or $(CONFIG_PATH),<defaults>)' \
BUILD_TIMESTAMP '$(BUILD_TIMESTAMP)' VARIANT_ID '$(VARIANT_ID)' VARIANT_ROOT '$(VARIANT_ROOT)' \
JOBS '$(JOBS)' \
SOC '$(SOC)' CORE '$(CORE)' IP '$(IP)' \
SOC '$(SOC)' CORE '$(CORE)' \
SIMU '$(SIMU)' SYNTH '$(SYNTH)' STA '$(STA)' FORMAL '$(FORMAL)' PDK '$(PDK)' \
HAVE_PLL '$(HAVE_PLL)' HAVE_SRAM_IF '$(HAVE_SRAM_IF)' \
HAVE_SRAM_MACRO '$(HAVE_SRAM_MACRO)' HAVE_SVA '$(HAVE_SVA)' \
@@ -236,7 +235,7 @@ config:
doctor:
@python3 $(ROOT_PATH)/scripts/doctor.py \
--root $(ROOT_PATH) --simu $(SIMU) --synth $(SYNTH) --sta $(STA) \
--pdk $(PDK) --core $(CORE) --ip $(IP) --formal $(FORMAL) --lock $(LOCK_FILE)
--pdk $(PDK) --formal $(FORMAL) --lock $(LOCK_FILE)
setup: setup-mpw setup-core setup-clusterip setup-ip setup-pdk setup-app
+31 -31
View File
@@ -13,7 +13,9 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
## Highlights
- Selectable RV32IM CPU configurations using HAZARD3, PicoRV32, or MDD cores.
- A fixed architecture with a Hazard3 management core by default (PicoRV32 is
an explicit build option) and software-selected
user-core and user-IP extension slots.
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets. GF180, SKY130,
and IHP130 have open-source CI coverage; ICS55 remains a configured cluster target.
- A memory-mapped peripheral subsystem with GPIO, UART, timers, PWM, I2C, I2S, PS2,
@@ -42,20 +44,18 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
## Supported Configurations
The committed profiles are the supported starting points. They select a core, ISA, PDK,
application, linker layout, and optional features as one reproducible configuration.
The committed profiles are the supported starting points. They select an ISA,
PDK, application, linker layout, and optional features as one reproducible
configuration. The user-extension fabric is fixed; `CORE` selects the management
core and defaults to `HAZARD3`.
| Profile | Core / ISA | Application | Coverage |
| Profile | ISA | Application | Coverage |
| --- | --- | --- | --- |
| [`configs/ci/hazard3-rv32im-ihp130.mk`](configs/ci/hazard3-rv32im-ihp130.mk) | HAZARD3 / RV32IM | `bringup` | Pull-request open-source regression: firmware, Verilator, Icarus, Yosys, Icarus netlist simulation, and OpenSTA. |
| [`configs/ci/hazard3-rv32im-gf180.mk`](configs/ci/hazard3-rv32im-gf180.mk) | HAZARD3 / RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
| [`configs/ci/hazard3-rv32im-sky130.mk`](configs/ci/hazard3-rv32im-sky130.mk) | HAZARD3 / RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
| [`configs/ci/hazard3-rv32im-ihp130-shell.mk`](configs/ci/hazard3-rv32im-ihp130-shell.mk) | HAZARD3 / RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
| [`configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk`](configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk) | HAZARD3 / RV32IM + MDD IP | `bringup` | Pull-request firmware and Verilator integration coverage for the user-IP GPIO ownership path. |
| [`configs/ci/hazard3-rv32im-ihp130-ip-mdd-shell.mk`](configs/ci/hazard3-rv32im-ihp130-ip-mdd-shell.mk) | HAZARD3 / RV32IM + MDD IP | `shell` | Pull-request firmware compilation coverage for the user-IP software command. |
| [`configs/ci/mdd-rv32im-ihp130.mk`](configs/ci/mdd-rv32im-ihp130.mk) | MDD / RV32IM | `bringup` | Pull-request firmware and Verilator regression. |
| [`configs/nightly/picorv32-rv32im-ihp130.mk`](configs/nightly/picorv32-rv32im-ihp130.mk) | PicoRV32 / RV32IM | `bringup` | Nightly firmware, Verilator, and Icarus regression. |
| [`configs/cluster/hazard3-ics55.mk`](configs/cluster/hazard3-ics55.mk) | HAZARD3 / RV32IM | `bringup` | Cluster-only configuration; requires the site PDK and licensed-tool environment. |
| [`configs/ci/ihp130.mk`](configs/ci/ihp130.mk) | RV32IM | `bringup` | Pull-request open-source regression: firmware, Verilator, Icarus, Yosys, Icarus netlist simulation, and OpenSTA. |
| [`configs/ci/gf180.mk`](configs/ci/gf180.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
| [`configs/ci/sky130.mk`](configs/ci/sky130.mk) | RV32IM | `bringup` | Pull-request firmware, RTL simulation, Yosys, and Icarus netlist coverage. |
| [`configs/ci/ihp130-shell.mk`](configs/ci/ihp130-shell.mk) | RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | RV32IM | `bringup` | Cluster-only configuration; requires the site PDK and licensed-tool environment. |
## Prerequisites
@@ -80,20 +80,20 @@ and dependency update procedure.
## Quick Start
Start with the CI-verified HAZARD3/IHP130 `bringup` profile. `setup` retrieves the pinned
Start with the CI-verified IHP130 `bringup` profile. `setup` retrieves the pinned
source dependencies, and `doctor` reports any missing local executables or setup inputs.
```sh
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk setup
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG doctor
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk firmware
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG sim
make CONFIG=configs/ci/ihp130.mk setup
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG doctor
make CONFIG=configs/ci/ihp130.mk firmware
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG sim
```
Select the interactive shell application without editing source files:
```sh
make CONFIG=configs/ci/hazard3-rv32im-ihp130-shell.mk firmware
make CONFIG=configs/ci/ihp130-shell.mk firmware
```
## Common Flows
@@ -107,9 +107,9 @@ Verilator simulations run for 180 seconds by default. Set `SOC_SIM_TIME` explici
an exploratory local run needs a different limit.
```sh
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG RTL_SIM_TIMEOUT=5200000 sim-asm
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG \
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG RTL_SIM_TIMEOUT=5200000 sim-asm
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG \
SIM_FIRMWARE_NAME=retrosoc_asm \
SIM_SUCCESS_MARKER='Mem wr/rd test success' \
RTL_SIM_TIMEOUT=5200000 netsim
@@ -117,13 +117,13 @@ make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG \
| Goal | Command |
| --- | --- |
| Icarus behavioral simulation | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG sim` |
| Verilator behavioral simulation | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=VERILATOR sim` |
| Assembly self-test with Icarus | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG RTL_SIM_TIMEOUT=5200000 sim-asm` |
| Yosys synthesis | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SYNTH=YOSYS synth` |
| Icarus netlist simulation after synthesis | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG netsim` |
| OpenSTA core timing analysis after synthesis | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk STA=OPENSTA sta` |
| Strict Verilator RTL lint | `make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=VERILATOR HAVE_SVA=YES check-rtl-lint` |
| Icarus behavioral simulation | `make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG sim` |
| Verilator behavioral simulation | `make CONFIG=configs/ci/ihp130.mk SIMU=VERILATOR sim` |
| Assembly self-test with Icarus | `make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG RTL_SIM_TIMEOUT=5200000 sim-asm` |
| Yosys synthesis | `make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth` |
| Icarus netlist simulation after synthesis | `make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG netsim` |
| OpenSTA core timing analysis after synthesis | `make CONFIG=configs/ci/ihp130.mk STA=OPENSTA sta` |
| Strict Verilator RTL lint | `make CONFIG=configs/ci/ihp130.mk SIMU=VERILATOR HAVE_SVA=YES check-rtl-lint` |
| IHP130 fast smoke suite | `make regress-smoke` |
| Pull-request regression suite | `make regress-pr` |
| Nightly regression suite | `make regress-nightly` |
@@ -149,8 +149,8 @@ commands must reuse one variant:
```sh
export BUILD_TIMESTAMP=2026-07-21-10-39
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk firmware
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG sim
make CONFIG=configs/ci/ihp130.mk firmware
make CONFIG=configs/ci/ihp130.mk SIMU=IVERILOG sim
```
## Reproducibility And CI
+3 -3
View File
@@ -38,10 +38,10 @@ Build and simulate the supported profiles from the repository root:
```sh
# Bringup firmware and Verilator simulation
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=VERILATOR firmware sim
make CONFIG=configs/ci/ihp130.mk SIMU=VERILATOR firmware sim
# Shell firmware and Verilator simulation
make CONFIG=configs/ci/hazard3-rv32im-ihp130-shell.mk SIMU=VERILATOR firmware sim
make CONFIG=configs/ci/ihp130-shell.mk SIMU=VERILATOR firmware sim
```
For a firmware-only build, omit `SIMU=VERILATOR sim`.
@@ -54,7 +54,7 @@ For a firmware-only build, omit `SIMU=VERILATOR sim`.
3. Add `<name>` to the allowed `APP` values in the top-level `Makefile`; this
keeps profile selection explicit and rejects misspellings.
4. Add a committed configuration profile under `configs/` that selects
`APP := <name>` and the required core, ISA, CSR, and linker options.
`APP := <name>` and the required ISA, CSR, and linker options.
5. Add host tests for deterministic parsing or utility code, and add a
regression command when the application must execute in simulation.
+1 -4
View File
@@ -1,5 +1,2 @@
# User IP is optional and is linked only for MDD configurations.
ifeq ($(IP), MDD)
APP_SRCS += $(ROOT_PATH)/app/network/userip/userip.c
APP_INC_DIRS += $(ROOT_PATH)/app/network/userip
endif
APP_INC_DIRS += $(ROOT_PATH)/app/network/userip
+5 -4
View File
@@ -1,11 +1,12 @@
# Reproducible Build Profiles
This directory contains committed Make configuration profiles. Each profile
selects SoC, CPU/IP, PDK, ISA, CSR support, application, linker layout, and
the supported validation tier.
selects SoC, PDK, ISA, CSR support, application, linker layout, and the
supported validation tier. The user-extension fabric is fixed; the management
core defaults to `HAZARD3` and may be set to `PICORV32` with `CORE`.
`ci/` contains pull-request profiles, `nightly/` adds extended open-source
coverage, and `cluster/` contains configurations requiring site tools or PDKs.
`ci/` contains pull-request profiles and `cluster/` contains configurations
requiring site tools or PDKs. The nightly workflow reuses the IHP130 CI profile.
Start builds from a committed profile rather than setting an unreviewed mix of
variables on the command line.
@@ -1,6 +1,4 @@
SOC := MINI
CORE := HAZARD3
IP := NONE
PDK := GF180
HAVE_PLL := NO
HAVE_SRAM_IF := NO
@@ -1,12 +0,0 @@
SOC := MINI
CORE := HAZARD3
IP := MDD
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
-12
View File
@@ -1,12 +0,0 @@
SOC := MINI
CORE := HAZARD3
IP := NONE
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := YES
APP := shell
LINK_TYPE := ld2_psram
-12
View File
@@ -1,12 +0,0 @@
SOC := MINI
CORE := HAZARD3
IP := NONE
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
@@ -1,6 +1,4 @@
SOC := MINI
CORE := HAZARD3
IP := MDD
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
@@ -1,6 +1,4 @@
SOC := MINI
CORE := MDD
IP := NONE
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
@@ -1,6 +1,4 @@
SOC := MINI
CORE := HAZARD3
IP := NONE
PDK := SKY130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
@@ -1,6 +1,4 @@
SOC := MINI
CORE := HAZARD3
IP := NONE
PDK := ICS55
HAVE_PLL := NO
HAVE_SRAM_IF := NO
-12
View File
@@ -1,12 +0,0 @@
SOC := MINI
CORE := PICORV32
IP := NONE
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
+2 -2
View File
@@ -42,8 +42,8 @@ selected.
Start from a committed configuration profile:
```sh
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk setup
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk firmware
make CONFIG=configs/ci/ihp130.mk setup
make CONFIG=configs/ci/ihp130.mk firmware
```
The resulting firmware and generated headers are isolated under
+16 -14
View File
@@ -5,13 +5,14 @@
#include <stdbool.h>
#include <retrosoc/generated/memory_map.h>
#include <retrosoc/generated/user_extensions.h>
#ifdef CORE_PICORV32
#define HW_CORE "PicoRV32"
#elif CORE_HAZARD3
#define HW_CORE "HAZARD3"
#if defined(RS_SOC_MGMT_CORE_HAZARD3)
#define HW_CORE "Management Hazard3"
#elif defined(RS_SOC_MGMT_CORE_PICORV32)
#define HW_CORE "Management PicoRV32"
#else
#define HW_CORE "none"
#error "Management core selection is missing"
#endif
#define CPU_FREQ 72 // unit: MHz
@@ -158,6 +159,9 @@
#define reg_sysctrl_bus_fault_addr RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_ADDR_OFFSET)
#define reg_sysctrl_bus_fault_count RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_COUNT_OFFSET)
#define reg_sysctrl_pll_status RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PLL_STATUS_OFFSET)
#define reg_sysctrl_user_core_reset RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_USER_CORE_RESET_OFFSET)
#define reg_sysctrl_user_core_status RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_USER_CORE_STATUS_OFFSET)
#define reg_sysctrl_bus_fault_master RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_MASTER_OFFSET)
#define RS_SOC_BUS_FAULT_PENDING UINT32_C(0x00000001)
#define RS_SOC_BUS_FAULT_WRITE UINT32_C(0x00000002)
#define RS_SOC_BUS_FAULT_REASON_MASK UINT32_C(0x0000000C)
@@ -241,13 +245,11 @@
#define reg_tim3_cnt RS_SOC_REG32(RS_SOC_APB_TMR_BASE, UINT32_C(0x08))
#define reg_tim3_cmp RS_SOC_REG32(RS_SOC_APB_TMR_BASE, UINT32_C(0x0C))
#define reg_tim3_stat RS_SOC_REG32(RS_SOC_APB_TMR_BASE, UINT32_C(0x10))
#ifdef IP_MDD
#define reg_user_ip_reg0 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x00))
#define reg_user_ip_reg1 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x04))
#define reg_user_ip_reg2 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x08))
#define reg_user_ip_reg3 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x0C))
#define reg_user_ip_reg4 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x10))
#define reg_user_ip_reg5 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x14))
#define reg_user_ip_reg6 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x18))
#endif
#define reg_user_ip_reg0 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x00))
#define reg_user_ip_reg1 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x04))
#define reg_user_ip_reg2 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x08))
#define reg_user_ip_reg3 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x0C))
#define reg_user_ip_reg4 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x10))
#define reg_user_ip_reg5 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x14))
#define reg_user_ip_reg6 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x18))
#endif
+23
View File
@@ -0,0 +1,23 @@
#ifndef RETROSOC_HAL_USER_CORE_H
#define RETROSOC_HAL_USER_CORE_H
#include <stdbool.h>
#include <stdint.h>
#include <retrosoc/core/status.h>
typedef struct {
uint32_t reset_mask;
uint8_t selected_core;
bool bus_enabled;
bool bus_idle;
bool draining;
bool config_error;
} rs_user_core_status_t;
rs_status_t rs_user_core_get_status(rs_user_core_status_t *status);
rs_status_t rs_user_core_stop(rs_timeout_t timeout);
rs_status_t rs_user_core_start(uint8_t core_id, rs_timeout_t timeout);
rs_status_t rs_user_core_reset(uint8_t core_id, rs_timeout_t timeout);
#endif
+55 -50
View File
@@ -6,9 +6,6 @@
#include <retrosoc/hal/qspi.h>
#include <retrosoc/hal/lcd.h>
#include <retrosoc/hal/dma.h>
#ifdef CSR_ENABLE
#include <retrosoc/arch/riscv/system_base.h>
#endif
// #include "image.h"
// #include "video.h"
@@ -257,57 +254,65 @@ void lcd_fill_video(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend,
lcd_wr_data32(data + j, (total_pixels - i) / 2U);
}
static uint64_t rs_lcd_read_cycle_counter(void) {
uint32_t high_before;
uint32_t low;
uint32_t high_after;
do {
__asm__ volatile("rdcycleh %0" : "=r"(high_before));
__asm__ volatile("rdcycle %0" : "=r"(low));
__asm__ volatile("rdcycleh %0" : "=r"(high_after));
} while (high_before != high_after);
return ((uint64_t)high_after << 32U) | (uint64_t)low;
}
static uint64_t rs_lcd_read_instret_counter(void) {
uint32_t high_before;
uint32_t low;
uint32_t high_after;
do {
__asm__ volatile("rdinstreth %0" : "=r"(high_before));
__asm__ volatile("rdinstret %0" : "=r"(low));
__asm__ volatile("rdinstreth %0" : "=r"(high_after));
} while (high_before != high_after);
return ((uint64_t)high_after << 32U) | (uint64_t)low;
}
static void lcd_frame(uint32_t first, uint32_t pref_cnt) {
#ifdef CORE_PICORV32
static uint32_t cycle_start, cycle_end;
static uint32_t cycleh_start, cycleh_end;
static uint32_t inst_start, inst_end;
static uint32_t insth_start, insth_end;
if (first) {
__asm__ volatile("rdcycle %0" : "=r"(cycle_start));
__asm__ volatile("rdcycleh %0" : "=r"(cycleh_start));
__asm__ volatile("rdinstret %0" : "=r"(inst_start));
__asm__ volatile("rdinstreth %0" : "=r"(insth_start));
} else {
__asm__ volatile("rdcycle %0" : "=r"(cycle_end));
__asm__ volatile("rdcycleh %0" : "=r"(cycleh_end));
__asm__ volatile("rdinstret %0" : "=r"(inst_end));
__asm__ volatile("rdinstreth %0" : "=r"(insth_end));
static uint64_t cycle_start;
static uint64_t instret_start;
static bool measurement_active;
printf("cycles num: %d(high: %d)\n", cycle_end - cycle_start, cycleh_end - cycleh_start);
printf("insts num: %d(high: %d)\n", inst_end - inst_start, insth_end - insth_start);
if (cycle_end > cycle_start) {
const uint32_t elapsed_us = (cycle_end - cycle_start) / CPU_FREQ;
if (elapsed_us != 0U) {
printf("flush rate: %dfps\n", (pref_cnt * 1000000U) / elapsed_us);
}
}
}
#elif CORE_HAZARD3
static uint64_t cycle_start, cycle_end;
static uint64_t inst_start, inst_end;
if (first) {
// cycle_start = __get_rv_cycle();
// inst_start = __get_rv_instret();
} else {
// cycle_end = __get_rv_cycle();
// inst_end = __get_rv_instret();
if (cycle_end > cycle_start) {
const uint64_t elapsed_us = (cycle_end - cycle_start) / CPU_FREQ;
printf("cycles num: %lld\n", cycle_end - cycle_start);
printf("insts num: %lld\n", inst_end - inst_start);
if (elapsed_us != 0U) {
printf("flush rate: %lldfps\n", ((uint64_t)pref_cnt * 1000000U) / elapsed_us);
}
} else {
printf("frame timing is unavailable on this core\n");
}
if (first != 0U) {
cycle_start = rs_lcd_read_cycle_counter();
instret_start = rs_lcd_read_instret_counter();
measurement_active = true;
return;
}
#else
(void)first;
(void)pref_cnt;
#endif
if (!measurement_active) {
printf("lcd frame timing is unavailable\n");
return;
}
const uint64_t cycle_count = rs_lcd_read_cycle_counter() - cycle_start;
const uint64_t instret_count = rs_lcd_read_instret_counter() - instret_start;
const uint64_t elapsed_us = cycle_count / (uint64_t)CPU_FREQ;
measurement_active = false;
printf("cycles num: %llu\n", (unsigned long long)cycle_count);
printf("insts num: %llu\n", (unsigned long long)instret_count);
if (elapsed_us == 0U) {
printf("lcd frame timing is unavailable\n");
return;
}
printf("flush rate: %llufps\n",
(unsigned long long)(((uint64_t)pref_cnt * UINT64_C(1000000)) / elapsed_us));
}
void ip_lcd_test(int argc, char **argv) {
+91
View File
@@ -0,0 +1,91 @@
#include <stddef.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/user_core.h>
#define RS_USER_CORE_STATUS_SEL_MASK UINT32_C(0x0000001F)
#define RS_USER_CORE_STATUS_BUS_ENABLED UINT32_C(0x00000100)
#define RS_USER_CORE_STATUS_BUS_IDLE UINT32_C(0x00000200)
#define RS_USER_CORE_STATUS_DRAINING UINT32_C(0x00000400)
#define RS_USER_CORE_STATUS_CONFIG_ERROR UINT32_C(0x00000800)
static uint32_t rs_user_core_reset_mask_all(void) {
return UINT32_MAX >> (UINT32_C(32) - RS_SOC_USER_CORE_COUNT);
}
rs_status_t rs_user_core_get_status(rs_user_core_status_t *status) {
uint32_t value;
if (status == NULL) {
return RS_EINVAL;
}
value = reg_sysctrl_user_core_status;
status->reset_mask = reg_sysctrl_user_core_reset;
status->selected_core = (uint8_t)(value & RS_USER_CORE_STATUS_SEL_MASK);
status->bus_enabled = (value & RS_USER_CORE_STATUS_BUS_ENABLED) != UINT32_C(0);
status->bus_idle = (value & RS_USER_CORE_STATUS_BUS_IDLE) != UINT32_C(0);
status->draining = (value & RS_USER_CORE_STATUS_DRAINING) != UINT32_C(0);
status->config_error = (value & RS_USER_CORE_STATUS_CONFIG_ERROR) != UINT32_C(0);
return RS_OK;
}
rs_status_t rs_user_core_stop(rs_timeout_t timeout) {
rs_user_core_status_t status;
reg_sysctrl_user_core_reset = rs_user_core_reset_mask_all();
while (timeout-- != 0U) {
if (rs_user_core_get_status(&status) != RS_OK) {
return RS_EIO;
}
if (status.config_error) {
return RS_EIO;
}
if (!status.bus_enabled && status.bus_idle && !status.draining) {
return RS_OK;
}
}
return RS_ETIMEOUT;
}
rs_status_t rs_user_core_start(uint8_t core_id, rs_timeout_t timeout) {
rs_user_core_status_t status;
rs_status_t result;
uint32_t reset_mask;
if ((uint32_t)core_id >= RS_SOC_USER_CORE_COUNT) {
return RS_EINVAL;
}
result = rs_user_core_stop(timeout);
if (result != RS_OK) {
return result;
}
reg_sysctrl_user_core_status = RS_USER_CORE_STATUS_CONFIG_ERROR;
reg_sysctrl_coresel = (uint32_t)core_id;
if (rs_user_core_get_status(&status) != RS_OK) {
return RS_EIO;
}
if (status.config_error || status.selected_core != core_id) {
return RS_EIO;
}
reset_mask = rs_user_core_reset_mask_all() & ~(UINT32_C(1) << core_id);
reg_sysctrl_user_core_reset = reset_mask;
while (timeout-- != 0U) {
if (rs_user_core_get_status(&status) != RS_OK) {
return RS_EIO;
}
if (status.config_error) {
return RS_EIO;
}
if (status.bus_enabled && !status.draining && status.selected_core == core_id) {
return RS_OK;
}
}
return RS_ETIMEOUT;
}
rs_status_t rs_user_core_reset(uint8_t core_id, rs_timeout_t timeout) {
if ((uint32_t)core_id >= RS_SOC_USER_CORE_COUNT) {
return RS_EINVAL;
}
return rs_user_core_stop(timeout);
}
-10
View File
@@ -9,9 +9,7 @@
#include <retrosoc/lib/string.h>
#include <retrosoc/service/shell.h>
#include <retrosoc/service/booter.h>
#if defined(CORE_MDD) || defined(IP_MDD)
#include <user_design_info.h>
#endif
void rs_app_info(void) {
printf("#############################################################\n");
@@ -51,9 +49,6 @@ void rs_app_info(void) {
printf(" version: %s(commit: %s)\n\n", RETROSOC_BRANCH, RETROSOC_COMMIT);
printf("User Processors:\n");
#ifndef CORE_MDD
printf(" CORE: %s\n", HW_CORE);
#else
uint32_t core_size = sizeof(user_core_info) / sizeof(user_core_info[0]);
printf(" %-15s %-12s %-12s %s\n", "[name]", "[isa]", "[maintainer]", "[repo]");
for (uint32_t i = 0; i < core_size; ++i) {
@@ -64,9 +59,7 @@ void rs_app_info(void) {
printf("[%d]: %-15s %-12s %-12s %s\n", i, user_core_info[i].name, user_core_info[i].isa,
user_core_info[i].maintainer, user_core_info[i].repo);
}
#endif
#ifdef IP_MDD
printf("\nUser IPs:\n");
uint32_t ip_size = sizeof(user_ip_info) / sizeof(user_ip_info[0]);
printf(" %-15s %-12s %-12s %s\n", "[name]", "[isa]", "[maintainer]", "[repo]");
@@ -78,7 +71,6 @@ void rs_app_info(void) {
printf("[%d]: %-15s %-12s %-12s %s\n", i, user_ip_info[i].name, user_ip_info[i].isa,
user_ip_info[i].maintainer, user_ip_info[i].repo);
}
#endif
printf("\nSoftware:\n");
printf(" COMPILER: %s\n", COMPILER_NAME);
@@ -128,9 +120,7 @@ void rs_app_info(void) {
printf(" 1 x WDG @%p\n", (void *)&reg_wdg_ctrl);
printf(" 1 x CRC @%p\n", (void *)&reg_crc_ctrl);
printf(" 1 x TIMER3(ADV) @%p\n", (void *)&reg_tim3_ctrl);
#ifdef IP_MDD
printf(" 1 x USER_IP(4KiB) @%p\n", (void *)&reg_user_ip_reg0);
#endif
printf("\n");
printf("#############################################################\n");
printf("#############################################################\n");
-6
View File
@@ -11,9 +11,7 @@
#include <core_portme.h>
// #include <lvgl.h>
// #include <lv_port_disp.h>
#ifdef IP_MDD
#include <userip.h>
#endif
static char sh_argv_buf[RS_SHELL_MAX_ARGC][RS_SHELL_MAX_COMMAND_LENGTH + 1U];
static char *sh_argv[RS_SHELL_MAX_ARGC + 1U];
@@ -689,7 +687,6 @@ static void rs_shell_app_coremark_cmd(int argc, char **argv) {
core_main();
}
#ifdef IP_MDD
static void rs_shell_app_userip_cmd(int argc, char **argv) {
if (argc != 1 && argc != 2) {
printf("[userip] cmd param error\n");
@@ -713,7 +710,6 @@ static void rs_shell_app_userip_cmd(int argc, char **argv) {
}
// userip: list all info/current id
}
#endif
void rs_shell_launch(void) {
char type_res[RS_SHELL_MAX_COMMAND_LENGTH + 1U];
@@ -728,9 +724,7 @@ void rs_shell_launch(void) {
(void)rs_shell_register("help", "help info", false, rs_shell_help);
(void)rs_shell_register("history", "print history list", false, rs_shell_history_list);
(void)rs_shell_register("coremark", "coremark test", false, rs_shell_app_coremark_cmd);
#ifdef IP_MDD
(void)rs_shell_register("userip", "run user ip program", false, rs_shell_app_userip_cmd);
#endif
if (fs_init_state == RS_OK) {
(void)rs_shell_register("ls", "list directory contents", false, rs_shell_fat32_ls_cmd);
(void)rs_shell_register("lsr", "list directory contents recursively", false,
+13 -14
View File
@@ -4,13 +4,12 @@
| Tier | Profile | Automated coverage |
| --- | --- | --- |
| Smoke | `configs/ci/hazard3-rv32im-ihp130.mk` | strict Verilator RTL lint, firmware, Verilator SVA compilation, Icarus assembly self-test |
| Pull request | `configs/ci/hazard3-rv32im-ihp130.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
| Pull request | `configs/ci/hazard3-rv32im-gf180.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
| Pull request | `configs/ci/hazard3-rv32im-sky130.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
| Pull request | `configs/ci/mdd-rv32im-ihp130.mk` | firmware and Verilator |
| Nightly | `configs/nightly/picorv32-rv32im-ihp130.mk` | firmware, Verilator, and Icarus |
| Cluster | `configs/cluster/hazard3-ics55.mk` | configuration only; run with site PDK/tool access |
| Smoke | `configs/ci/ihp130.mk` | strict Verilator RTL lint, firmware, Verilator SVA compilation, Icarus assembly self-test |
| Pull request | `configs/ci/ihp130.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
| Pull request | `configs/ci/gf180.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
| Pull request | `configs/ci/sky130.mk` | strict Verilator RTL lint, firmware, Verilator, Icarus, Yosys, netlist Icarus, OpenSTA |
| Nightly | `configs/ci/ihp130.mk` | repeated full IHP130 regression |
| Cluster | `configs/cluster/ics55.mk` | configuration only; run with site PDK/tool access |
OpenSTA runs a reproducible core-STA baseline for every CI PDK: IHP130 uses
`slow_1p08V_125C`, GF180 uses `ss_125C_4v50`, and SKY130 uses `ss_100C_1v40`.
@@ -106,14 +105,14 @@ marker is present. Icarus regressions use the assembly self-test as `retrosoc_as
## Formal Protocol Proofs
`make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk formal` proves selected
`make CONFIG=configs/ci/ihp130.mk formal` proves selected
protocol invariants with SymbiYosys, Yosys, `sv2v`, and Bitwuzla. The current
targets are `bus`, `nmi2apb`, `sysctrl`, `pll_rcu`, and `gpio_mdd`; each uses
targets are `bus`, `nmi2apb`, `sysctrl`, `pll_rcu`, and `gpio_user`; each uses
the SBY `prove` task for bounded model checking and k-induction, plus a
`cover` task, at depth 20. `sysctrl` checks register side effects, PLL request
handling, and fault reporting. `pll_rcu` checks the clock-switch controller
state machine. `gpio_mdd` checks MDD user-GPIO ownership, lock, handoff, and
mux safety using the `IP_MDD` build definition.
state machine. `gpio_user` checks fixed user-GPIO ownership, lock, handoff,
and mux safety.
`FORMAL_DEPTH` and `FORMAL_TIMEOUT` set the proof bound and per-task
wall-clock limit. Use `make CONFIG=<profile> formal-doctor` before a local
proof to verify that the required tools are available.
@@ -144,9 +143,9 @@ are reported but do not fail. To refresh one baseline after review:
```sh
python3 scripts/analyze_warnings.py baseline \
--root . --profile hazard3-rv32im-ihp130 --tool verilator \
--root . --profile ihp130 --tool verilator \
--log build/<variant>/sim/verilator/verilating.log \
--output quality/warnings/hazard3-rv32im-ihp130/verilator.json
--output quality/warnings/ihp130/verilator.json
```
## Metrics Promotion
@@ -174,7 +173,7 @@ for diagnosis but is initially non-blocking.
`quality.yml` validates C, Makefile, and self-owned RTL formatting as well as Python, YAML, GitHub
Actions, the dependency lock, and script tests. `regression-smoke.yml` provides fast IHP130 feedback;
the three full PDK regression workflows remain required PR coverage and do not repeat the format checks.
`nightly.yml` adds PICORV32. Source dependencies, locked tool archives, and Verilator `ccache` use
`nightly.yml` repeats the fixed IHP130 architecture. Source dependencies, locked tool archives, and Verilator `ccache` use
separate cache keys.
Tags matching `v*` run `release.yml`. The release contains a flattened SystemVerilog export, a source
+1 -1
View File
@@ -55,7 +55,7 @@ Run the smallest relevant validation set in addition to a MISRA review:
make sw-format-check
make sw-policy-check
make sw-host-test
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk firmware
make CONFIG=configs/ci/ihp130.mk firmware
```
Use the affected profile and simulator for hardware-facing changes. See
+4 -4
View File
@@ -13,8 +13,8 @@ named-port binding. Do not edit generated files.
Use the following commands after editing the map:
```sh
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk check-pin-map
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk pin-map
make CONFIG=configs/ci/ihp130.mk check-pin-map
make CONFIG=configs/ci/ihp130.mk pin-map
```
When adding a pad, define its whitelisted pad template, direction, conditional
@@ -28,8 +28,8 @@ only exposes the pad-side subset of `gpio_if`; neither module contains state.
## User IP GPIO ownership
The IP=MDD configuration does not add dedicated user GPIO pads. A user IP can
instead drive any of the 32 native GPIO pads through `user_gpio_if`. Software
The fixed user-IP integration does not add dedicated user GPIO pads. A user IP
can instead drive any of the 32 native GPIO pads through `user_gpio_if`. Software
selects an owner per pin with the native GPIO `USER_SEL` register at offset
`0x30`; clear selects the existing software/alternate GPIO path and set selects
the user IP. `USER_LOCK` at `0x34` is write-one-set and prevents a selected
@@ -6,7 +6,7 @@
"signature": "aee22756a35889cc"
}
],
"profile": "hazard3-rv32im-gf180",
"profile": "gf180",
"schema_version": 1,
"tool": "iverilog"
}
@@ -3016,7 +3016,7 @@
"signature": "ffd1d68a726cc2c7"
}
],
"profile": "hazard3-rv32im-gf180",
"profile": "gf180",
"schema_version": 1,
"tool": "rtl-lint"
}
@@ -31,7 +31,7 @@
"signature": "ef9f314dab2ac31d"
}
],
"profile": "hazard3-rv32im-gf180",
"profile": "gf180",
"schema_version": 1,
"tool": "verilator"
}
@@ -41,7 +41,7 @@
"signature": "ef03dcca25b39dcb"
}
],
"profile": "hazard3-rv32im-gf180",
"profile": "gf180",
"schema_version": 1,
"tool": "yosys"
}
@@ -1,77 +0,0 @@
{
"entries": [
{
"count": 1,
"example": "UNSIGNED:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Comparison is constant due to unsigned arithmetic",
"signature": "010491867f065cec"
},
{
"count": 4,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator EQ expects 32 bits on the LHS, but LHS's SEL generates 8 bits.",
"signature": "3bba21d5150bdc2e"
},
{
"count": 1,
"example": "UNOPTFLAT:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_xpi_if.io_di_i'",
"signature": "411d9ab46fef9d7d"
},
{
"count": 1,
"example": "UNSIGNED:$ROOT/rtl/mini/top/ip_nmi_wrapper.sv:<line>: Comparison is constant due to unsigned arithmetic",
"signature": "7350cffccb478d64"
},
{
"count": 1,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_sram/verilog/RM_IHPSG13_1P_1024x64_c2_bm_bist.v:<line>: Ignoring unsupported: specify block construct",
"signature": "7a759d6e07651fd8"
},
{
"count": 2,
"example": "CMPCONST:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Comparison is constant due to limited range",
"signature": "813090adc9f1e8a8"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case Item, but Case Item's CONST '8'h0' generates 8 bits.",
"signature": "8ad9b6921bd232e7"
},
{
"count": 1,
"example": "UNSIGNED:$ROOT/rtl/mini/top/bus.sv:<line>: Comparison is constant due to unsigned arithmetic",
"signature": "9f53ff454a8648a4"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case Item, but Case Item's CONST '8'h4' generates 8 bits.",
"signature": "be2cb5333a881eca"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case expression, but Case expression's SEL generates 8 bits.",
"signature": "c43a29f4c975e9c1"
},
{
"count": 68,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_stdcell/verilog/sg13g2_stdcell.v:<line>: Ignoring unsupported: specify block construct",
"signature": "c54331448f63ac73"
},
{
"count": 1,
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_read.sv:<line>: Operator ASSIGNDLY expects 8 bits on the Assign RHS, but Assign RHS's REPLICATE generates 9 bits.",
"signature": "c963ef155f9a032c"
},
{
"count": 3,
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Bit extraction of var[7:0] requires 3 bit index, not 4 bits.",
"signature": "ef9f314dab2ac31d"
},
{
"count": 11,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_io/verilog/sg13g2_io.v:<line>: Ignoring unsupported: specify block construct",
"signature": "faa191e2dbf4a242"
}
],
"profile": "hazard3-rv32im-ihp130-ip-mdd",
"schema_version": 1,
"tool": "verilator"
}
@@ -11,7 +11,7 @@
"signature": "c4297f454f443fed"
}
],
"profile": "hazard3-rv32im-ihp130",
"profile": "ihp130",
"schema_version": 1,
"tool": "iverilog"
}
@@ -1,6 +1,6 @@
{
"entries": [],
"profile": "hazard3-rv32im-ihp130",
"profile": "ihp130",
"schema_version": 1,
"tool": "opensta"
}
@@ -81,7 +81,7 @@
"signature": "faa191e2dbf4a242"
}
],
"profile": "hazard3-rv32im-ihp130",
"profile": "ihp130",
"schema_version": 1,
"tool": "verilator"
}
@@ -36,7 +36,7 @@
"signature": "ef03dcca25b39dcb"
}
],
"profile": "hazard3-rv32im-ihp130",
"profile": "ihp130",
"schema_version": 1,
"tool": "yosys"
}
@@ -1,132 +0,0 @@
{
"entries": [
{
"count": 1,
"example": "UNSIGNED:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Comparison is constant due to unsigned arithmetic",
"signature": "010491867f065cec"
},
{
"count": 1,
"example": "PINMISSING:$BUILD/generated/mpw/verilator/core/username4/./serv/serv_synth_wrapper_username4.v:<line>: Instance has missing pin: 'o_ren'",
"signature": "173218df65cf7bcd"
},
{
"count": 1,
"example": "UNOPTFLAT:$BUILD/generated/mpw/verilator/core/username1/./kianV/alu_username1.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_core_wrapper.u_user_core_wrapper.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.datapath_unit_I.alu_I.is_sub'",
"signature": "180cdbb151faa02d"
},
{
"count": 1,
"example": "UNOPTFLAT:$BUILD/generated/mpw/verilator/core/username1/./kianV/kianv_harris_mc_edition_username1.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_core_wrapper.u_user_core_wrapper.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.alu_valid'",
"signature": "25979c35fe4eb73f"
},
{
"count": 1,
"example": "WIDTHEXPAND:$BUILD/generated/mpw/verilator/core/username6/./darkriscv/darkriscv_username6.v:<line>: Operator COND expects 32 bits on the Conditional True, but Conditional True's LT generates 1 bits.",
"signature": "259baf70503bfe0d"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case Item, but Case Item's CONST '8'h8' generates 8 bits.",
"signature": "2f1913ee897eabb8"
},
{
"count": 1,
"example": "WIDTHEXPAND:$BUILD/generated/mpw/verilator/core/username6/./darkriscv/darkriscv_username6.v:<line>: Operator COND expects 32 bits on the Conditional True, but Conditional True's LTS generates 1 bits.",
"signature": "323be25f98c25432"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator EQ expects 32 bits on the LHS, but LHS's SEL generates 8 bits.",
"signature": "3bba21d5150bdc2e"
},
{
"count": 1,
"example": "UNOPTFLAT:$ROOT/rtl/ip/native/storage/xpi.sv:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_xpi_if.io_di_i'",
"signature": "411d9ab46fef9d7d"
},
{
"count": 14,
"example": "WIDTHTRUNC:$BUILD/generated/mpw/verilator/core/username6/./darkriscv/darkriscv_username6.v:<line>: Logical operator COND expects 1 bit on the Conditional Test, but Conditional Test's VARREF 'FLUSH' generates 2 bits.",
"signature": "4a2065ce464b898c"
},
{
"count": 1,
"example": "UNOPTFLAT:$BUILD/generated/mpw/verilator/core/username1/./kianV/kianv_harris_mc_edition_username1.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_core_wrapper.u_user_core_wrapper.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.ALUSrcA'",
"signature": "4edf683bf8ef29d3"
},
{
"count": 1,
"example": "UNOPTFLAT:$BUILD/generated/mpw/verilator/core/username1/./kianV/alu_decoder_username1.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_core_wrapper.u_user_core_wrapper.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.control_unit_I.alu_decoder_I.ALUControl'",
"signature": "5dc2cc2658c8e2c1"
},
{
"count": 1,
"example": "UNSIGNED:$ROOT/rtl/mini/top/ip_nmi_wrapper.sv:<line>: Comparison is constant due to unsigned arithmetic",
"signature": "7350cffccb478d64"
},
{
"count": 1,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_sram/verilog/RM_IHPSG13_1P_1024x64_c2_bm_bist.v:<line>: Ignoring unsupported: specify block construct",
"signature": "7a759d6e07651fd8"
},
{
"count": 2,
"example": "CMPCONST:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Comparison is constant due to limited range",
"signature": "813090adc9f1e8a8"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case Item, but Case Item's CONST '8'h0' generates 8 bits.",
"signature": "8ad9b6921bd232e7"
},
{
"count": 1,
"example": "UNSIGNED:$ROOT/rtl/mini/top/bus.sv:<line>: Comparison is constant due to unsigned arithmetic",
"signature": "9f53ff454a8648a4"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case Item, but Case Item's CONST '8'h4' generates 8 bits.",
"signature": "be2cb5333a881eca"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case expression, but Case expression's SEL generates 8 bits.",
"signature": "c43a29f4c975e9c1"
},
{
"count": 68,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_stdcell/verilog/sg13g2_stdcell.v:<line>: Ignoring unsupported: specify block construct",
"signature": "c54331448f63ac73"
},
{
"count": 1,
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_read.sv:<line>: Operator ASSIGNDLY expects 8 bits on the Assign RHS, but Assign RHS's REPLICATE generates 9 bits.",
"signature": "c963ef155f9a032c"
},
{
"count": 3,
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/storage/spisd_write.sv:<line>: Bit extraction of var[7:0] requires 3 bit index, not 4 bits.",
"signature": "ef9f314dab2ac31d"
},
{
"count": 1,
"example": "UNOPTFLAT:$BUILD/generated/mpw/verilator/core/username1/./kianV/kianv_harris_mc_edition_username1.v:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_retrosoc.u_core_wrapper.u_user_core_wrapper.u_user_core_top.u_user_core_design_username1.u_kianv_harris_mc_edition.ALUSrcB'",
"signature": "f1f9cfed209f63b9"
},
{
"count": 1,
"example": "WIDTHEXPAND:$ROOT/rtl/ip/native/peripheral/sysctrl.sv:<line>: Operator CASE expects 32 bits on the Case Item, but Case Item's CONST '8'hc' generates 8 bits.",
"signature": "f6f2aa6bb2b3f6c4"
},
{
"count": 11,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_io/verilog/sg13g2_io.v:<line>: Ignoring unsupported: specify block construct",
"signature": "faa191e2dbf4a242"
}
],
"profile": "mdd-rv32im-ihp130",
"schema_version": 1,
"tool": "verilator"
}
@@ -1,17 +0,0 @@
{
"entries": [
{
"count": 1,
"example": "warning:Found both default and explicit timescale based delays. Use",
"signature": "aee22756a35889cc"
},
{
"count": 2,
"example": "sorry:ifnone with an edge-sensitive path is not supported.",
"signature": "c4297f454f443fed"
}
],
"profile": "picorv32-rv32im-ihp130",
"schema_version": 1,
"tool": "iverilog"
}
@@ -1,42 +0,0 @@
{
"entries": [
{
"count": 2,
"example": "CMPCONST:$ROOT/rtl/ip/native/spisd_write.sv:<line>: Comparison is constant due to limited range",
"signature": "11b9d285d4747e4f"
},
{
"count": 1,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_sram/verilog/RM_IHPSG13_1P_1024x64_c2_bm_bist.v:<line>: Ignoring unsupported: specify block construct",
"signature": "7a759d6e07651fd8"
},
{
"count": 68,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_stdcell/verilog/sg13g2_stdcell.v:<line>: Ignoring unsupported: specify block construct",
"signature": "c54331448f63ac73"
},
{
"count": 3,
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/spisd_write.sv:<line>: Bit extraction of var[7:0] requires 3 bit index, not 4 bits.",
"signature": "cdd5c3ca84a609c6"
},
{
"count": 1,
"example": "UNOPTFLAT:$ROOT/rtl/ip/native/xpi.sv:<line>: Signal unoptimizable: Circular combinational logic: 'retrosoc_top.u_retrosoc_asic.u_xpi_if.io_di_i'",
"signature": "ee29e23bc895ee17"
},
{
"count": 1,
"example": "WIDTHTRUNC:$ROOT/rtl/ip/native/spisd_read.sv:<line>: Operator ASSIGNDLY expects 8 bits on the Assign RHS, but Assign RHS's REPLICATE generates 9 bits.",
"signature": "f8f8278c6ce4431d"
},
{
"count": 11,
"example": "SPECIFYIGN:$ROOT/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_io/verilog/sg13g2_io.v:<line>: Ignoring unsupported: specify block construct",
"signature": "faa191e2dbf4a242"
}
],
"profile": "picorv32-rv32im-ihp130",
"schema_version": 1,
"tool": "verilator"
}
@@ -6,7 +6,7 @@
"signature": "aee22756a35889cc"
}
],
"profile": "hazard3-rv32im-sky130",
"profile": "sky130",
"schema_version": 1,
"tool": "iverilog"
}
@@ -6,7 +6,7 @@
"signature": "3c380feb1d0cd00a"
}
],
"profile": "hazard3-rv32im-sky130",
"profile": "sky130",
"schema_version": 1,
"tool": "opensta"
}
@@ -3116,7 +3116,7 @@
"signature": "ffd1d68a726cc2c7"
}
],
"profile": "hazard3-rv32im-sky130",
"profile": "sky130",
"schema_version": 1,
"tool": "rtl-lint"
}
@@ -31,7 +31,7 @@
"signature": "ef9f314dab2ac31d"
}
],
"profile": "hazard3-rv32im-sky130",
"profile": "sky130",
"schema_version": 1,
"tool": "verilator"
}
@@ -41,7 +41,7 @@
"signature": "ef03dcca25b39dcb"
}
],
"profile": "hazard3-rv32im-sky130",
"profile": "sky130",
"schema_version": 1,
"tool": "yosys"
}
+1 -13
View File
@@ -115,14 +115,12 @@ module nmi_gpio (
logic [`NMI_GPIO_NUM-1:0] s_gpio_iofcfg_d, s_gpio_iofcfg_q;
logic s_gpio_pinmux_en;
logic [`NMI_GPIO_NUM-1:0] s_gpio_pinmux_d, s_gpio_pinmux_q;
`ifdef IP_MDD
logic s_gpio_user_sel_en;
logic [`NMI_GPIO_NUM-1:0] s_gpio_user_sel_d, s_gpio_user_sel_q;
logic s_gpio_user_lock_en;
logic [`NMI_GPIO_NUM-1:0] s_gpio_user_lock_d, s_gpio_user_lock_q;
logic [`NMI_GPIO_NUM-1:0] s_gpio_user_handoff_d, s_gpio_user_handoff_q;
logic [`NMI_GPIO_NUM-1:0] s_gpio_user_status;
`endif
// irq
logic [`NMI_GPIO_NUM-1:0] s_gpio_di_re, s_gpio_di_fe, s_gpio_irq;
logic [`NMI_GPIO_NUM-1:0] s_irq_rise, s_irq_fall;
@@ -150,7 +148,6 @@ module nmi_gpio (
assign s_gpio_native_oe[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_oe[i] : s_gpio_oe_q[i];
assign s_gpio_native_out[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_out[i] : s_gpio_do_q[i];
end
`ifdef IP_MDD
assign user_gpio.di_i = gpio.di_i;
for (genvar i = 0; i < `NMI_GPIO_NUM; i++) begin : USER_GPIO_MUX_BLOCK
assign gpio.oe_o[i] = s_gpio_user_handoff_q[i]
@@ -158,11 +155,6 @@ module nmi_gpio (
: (s_gpio_user_sel_q[i] ? user_gpio.oe_o[i] : s_gpio_native_oe[i]);
assign gpio.do_o[i] = s_gpio_user_sel_q[i] ? user_gpio.do_o[i] : s_gpio_native_out[i];
end
`else
assign gpio.oe_o = s_gpio_native_oe;
assign gpio.do_o = s_gpio_native_out;
assign user_gpio.di_i = '0;
`endif
assign s_irq_stat = |s_gpio_istat_q;
assign gpio.irq_o = s_irq_stat;
@@ -320,7 +312,6 @@ module nmi_gpio (
s_gpio_pinmux_q
);
`ifdef IP_MDD
assign s_gpio_user_sel_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_GPIO_USER_SEL;
assign s_gpio_user_sel_d = (s_gpio_user_sel_q & s_gpio_user_lock_q) |
(nmi.wdata[`NMI_GPIO_NUM-1:0] & ~s_gpio_user_lock_q);
@@ -350,11 +341,10 @@ module nmi_gpio (
s_gpio_user_handoff_q
);
assign s_gpio_user_status = s_gpio_user_sel_q & ~s_gpio_user_handoff_q;
`endif
// nmi resp
assign s_nmi_ready_d = nmi.valid && (~s_nmi_ready_q);
assign s_nmi_ready_d = nmi.valid && (~s_nmi_ready_q);
dffr #(1) u_nmi_ready_dffr (
clk_i,
rst_n_i,
@@ -378,11 +368,9 @@ module nmi_gpio (
`NMI_GPIO_ISTAT: s_nmi_rdata_d = {{(32 - `NMI_GPIO_NUM) {1'b0}}, s_gpio_istat_q};
`NMI_GPIO_IOFCFG: s_nmi_rdata_d = {{(32 - `NMI_GPIO_NUM) {1'b0}}, s_gpio_iofcfg_q};
`NMI_GPIO_PINMUX: s_nmi_rdata_d = {{(32 - `NMI_GPIO_NUM) {1'b0}}, s_gpio_pinmux_q};
`ifdef IP_MDD
`NMI_GPIO_USER_SEL: s_nmi_rdata_d = {{(32 - `NMI_GPIO_NUM) {1'b0}}, s_gpio_user_sel_q};
`NMI_GPIO_USER_LOCK: s_nmi_rdata_d = {{(32 - `NMI_GPIO_NUM) {1'b0}}, s_gpio_user_lock_q};
`NMI_GPIO_USER_STATUS: s_nmi_rdata_d = {{(32 - `NMI_GPIO_NUM) {1'b0}}, s_gpio_user_status};
`endif
default: s_nmi_rdata_d = s_nmi_rdata_q;
endcase
end
+143 -16
View File
@@ -8,14 +8,27 @@
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "mdd_config.svh"
`include "user_extensions.svh"
`include "mmap_define.svh"
interface sysctrl_if ();
logic [`USER_CORESEL_WIDTH-1:0] core_sel_i;
logic [`USER_CORESEL_WIDTH-1:0] core_sel_o;
logic [ `USER_CORE_COUNT-1:0] core_reset_o;
logic user_bus_enable_o;
logic user_bus_idle_i;
logic fault_access_i;
logic [ 1:0] fault_master_i;
logic [ `USER_IPSEL_WIDTH-1:0] ip_sel_o;
modport dut(input core_sel_i, output ip_sel_o);
modport dut(
input user_bus_idle_i,
input fault_access_i,
input fault_master_i,
output core_sel_o,
output core_reset_o,
output user_bus_enable_o,
output ip_sel_o
);
endinterface
module nmi_sysctrl (
@@ -42,6 +55,12 @@ module nmi_sysctrl (
localparam sysctrl_offset_t SYSCTRL_FAULT_ADDR_OFFSET = sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_ADDR_OFFSET);
localparam sysctrl_offset_t SYSCTRL_FAULT_COUNT_OFFSET = sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_COUNT_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PLL_STATUS_OFFSET = sysctrl_offset_t'(`SOC_SYSCTRL_PLL_STATUS_OFFSET);
localparam sysctrl_offset_t SYSCTRL_USER_CORE_RESET_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_USER_CORE_RESET_OFFSET);
localparam sysctrl_offset_t SYSCTRL_USER_CORE_STATUS_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_USER_CORE_STATUS_OFFSET);
localparam sysctrl_offset_t SYSCTRL_FAULT_MASTER_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_MASTER_OFFSET);
logic s_nmi_wr_hdshk, s_nmi_rd_hdshk;
logic s_nmi_ready_d, s_nmi_ready_q;
@@ -49,7 +68,17 @@ module nmi_sysctrl (
logic [31:0] s_nmi_rdata_d, s_nmi_rdata_q;
logic [`USER_CORESEL_WIDTH-1:0] s_sysctrl_coresel_d, s_sysctrl_coresel_q;
logic s_sysctrl_ipsel_en;
logic s_sysctrl_coresel_en;
logic s_sysctrl_coresel_write_valid;
logic [`USER_CORE_COUNT-1:0] s_user_reset_d, s_user_reset_q;
logic s_user_reset_en;
logic s_user_running_d, s_user_running_q;
logic s_user_draining_d, s_user_draining_q;
logic s_user_config_error_d, s_user_config_error_q;
logic s_user_config_error_clear;
logic s_user_reset_write_legal;
logic [`USER_CORE_COUNT-1:0] s_user_reset_write_data;
logic s_sysctrl_ipsel_en;
logic [`USER_IPSEL_WIDTH-1:0] s_sysctrl_ipsel_d, s_sysctrl_ipsel_q;
logic [2:0] s_pll_cfg_d, s_pll_cfg_q;
logic s_pll_cfg_en;
@@ -66,28 +95,107 @@ module nmi_sysctrl (
logic s_fault_status_clear;
logic s_fault_pending_d, s_fault_pending_q;
logic s_fault_write_d, s_fault_write_q;
logic [1:0] s_fault_reason_d, s_fault_reason_q;
logic [2:0] s_fault_reason_d, s_fault_reason_q;
logic [31:0] s_fault_addr_d, s_fault_addr_q;
logic [31:0] s_fault_count_d, s_fault_count_q;
logic [1:0] s_fault_master_d, s_fault_master_q;
assign s_nmi_wr_hdshk = nmi.valid && (~s_nmi_ready_q) && (|nmi.wstrb);
assign s_nmi_rd_hdshk = nmi.valid && (~s_nmi_ready_q) && (~(|nmi.wstrb));
assign nmi.ready = s_nmi_ready_q;
assign nmi.rdata = s_nmi_rdata_q;
assign s_nmi_wr_hdshk = nmi.valid && (~s_nmi_ready_q) && (|nmi.wstrb);
assign s_nmi_rd_hdshk = nmi.valid && (~s_nmi_ready_q) && (~(|nmi.wstrb));
assign nmi.ready = s_nmi_ready_q;
assign nmi.rdata = s_nmi_rdata_q;
assign sysctrl.ip_sel_o = s_sysctrl_ipsel_q;
assign pll_ctrl.req_sel_o = s_pll_cfg_q;
assign sysctrl.ip_sel_o = s_sysctrl_ipsel_q;
assign sysctrl.core_sel_o = s_sysctrl_coresel_q;
assign sysctrl.core_reset_o = s_user_reset_q;
assign sysctrl.user_bus_enable_o = s_user_running_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.rsp_ready_o = 1'b1;
assign s_sysctrl_coresel_d = sysctrl.core_sel_i;
dffr #(`USER_CORESEL_WIDTH) u_sysctrl_coresel_dffr (
assign s_sysctrl_coresel_write_valid = nmi.wdata[`USER_CORESEL_WIDTH-1:0] < `USER_CORE_COUNT;
assign s_sysctrl_coresel_en = s_nmi_wr_hdshk && nmi.addr[7:0] == SYSCTRL_CORESEL_OFFSET &&
nmi.wstrb[0] && s_sysctrl_coresel_write_valid &&
(&s_user_reset_q) && sysctrl.user_bus_idle_i && ~s_user_running_q;
assign s_sysctrl_coresel_d = nmi.wdata[`USER_CORESEL_WIDTH-1:0];
dffer #(`USER_CORESEL_WIDTH) u_sysctrl_coresel_dffer (
clk_i,
rst_n_i,
s_sysctrl_coresel_en,
s_sysctrl_coresel_d,
s_sysctrl_coresel_q
);
assign s_user_reset_write_data = nmi.wdata[`USER_CORE_COUNT-1:0];
assign s_user_reset_write_legal = (&s_user_reset_write_data) ||
((s_sysctrl_coresel_q < `USER_CORE_COUNT) &&
((~s_user_reset_write_data) ==
({{(`USER_CORE_COUNT - 1){1'b0}}, 1'b1} << s_sysctrl_coresel_q)));
assign s_user_reset_en = s_nmi_wr_hdshk && nmi.addr[7:0] == SYSCTRL_USER_CORE_RESET_OFFSET &&
nmi.wstrb[0];
assign s_user_config_error_clear = s_nmi_wr_hdshk &&
nmi.addr[7:0] == SYSCTRL_USER_CORE_STATUS_OFFSET && nmi.wstrb[1] && nmi.wdata[11];
always_comb begin
s_user_reset_d = s_user_reset_q;
s_user_running_d = s_user_running_q;
s_user_draining_d = s_user_draining_q;
s_user_config_error_d = s_user_config_error_q;
if (s_user_config_error_clear) begin
s_user_config_error_d = 1'b0;
end
if (s_nmi_wr_hdshk && nmi.addr[7:0] == SYSCTRL_CORESEL_OFFSET && ~s_sysctrl_coresel_en) begin
s_user_config_error_d = 1'b1;
end
if (s_user_reset_en) begin
if (~s_user_reset_write_legal) begin
s_user_config_error_d = 1'b1;
end else if (&s_user_reset_write_data) begin
s_user_running_d = 1'b0;
if (sysctrl.user_bus_idle_i) begin
s_user_reset_d = s_user_reset_write_data;
s_user_draining_d = 1'b0;
end else begin
s_user_draining_d = 1'b1;
end
end else if (sysctrl.user_bus_idle_i && (&s_user_reset_q) && ~s_user_running_q) begin
s_user_reset_d = s_user_reset_write_data;
s_user_running_d = 1'b1;
s_user_draining_d = 1'b0;
end else begin
s_user_config_error_d = 1'b1;
end
end
if (s_user_draining_q && sysctrl.user_bus_idle_i) begin
s_user_reset_d = '1;
s_user_draining_d = 1'b0;
end
end
dffrc #(`USER_CORE_COUNT, '1) u_user_reset_dffrc (
clk_i,
rst_n_i,
s_user_reset_d,
s_user_reset_q
);
dffr #(1) u_user_running_dffr (
clk_i,
rst_n_i,
s_user_running_d,
s_user_running_q
);
dffr #(1) u_user_draining_dffr (
clk_i,
rst_n_i,
s_user_draining_d,
s_user_draining_q
);
dffr #(1) u_user_config_error_dffr (
clk_i,
rst_n_i,
s_user_config_error_d,
s_user_config_error_q
);
assign s_sysctrl_ipsel_en = s_nmi_wr_hdshk && nmi.addr[7:0] == SYSCTRL_IPSEL_OFFSET;
assign s_sysctrl_ipsel_d = nmi.wdata[`USER_IPSEL_WIDTH-1:0];
dffer #(`USER_IPSEL_WIDTH) u_sysctrl_ipsel_dffer (
@@ -218,7 +326,7 @@ module nmi_sysctrl (
if (fault_valid_i) begin
s_fault_pending_d = 1'b1;
s_fault_write_d = |fault_wstrb_i;
s_fault_reason_d = fault_reserved_i ? 2'd2 : 2'd1;
s_fault_reason_d = sysctrl.fault_access_i ? 3'd3 : (fault_reserved_i ? 3'd2 : 3'd1);
s_fault_addr_d = fault_addr_i;
if (~(&s_fault_count_q)) begin
s_fault_count_d = s_fault_count_q + 32'd1;
@@ -237,7 +345,7 @@ module nmi_sysctrl (
s_fault_write_d,
s_fault_write_q
);
dffr #(2) u_fault_reason_dffr (
dffr #(3) u_fault_reason_dffr (
clk_i,
rst_n_i,
s_fault_reason_d,
@@ -255,6 +363,14 @@ module nmi_sysctrl (
s_fault_count_d,
s_fault_count_q
);
assign s_fault_master_d = sysctrl.fault_master_i;
dffer #(2) u_fault_master_dffer (
clk_i,
rst_n_i,
fault_valid_i,
s_fault_master_d,
s_fault_master_q
);
assign s_nmi_ready_d = nmi.valid && (~s_nmi_ready_q);
dffr #(1) u_nmi_ready_dffr (
@@ -272,7 +388,7 @@ module nmi_sysctrl (
SYSCTRL_CORESEL_OFFSET: s_nmi_rdata_d = {{(32 - `USER_CORESEL_WIDTH) {1'b0}}, s_sysctrl_coresel_q};
SYSCTRL_IPSEL_OFFSET: s_nmi_rdata_d = {{(32 - `USER_IPSEL_WIDTH) {1'b0}}, s_sysctrl_ipsel_q};
SYSCTRL_PLL_CFG_OFFSET: s_nmi_rdata_d = {29'd0, s_pll_cfg_q};
SYSCTRL_FAULT_STATUS_OFFSET: s_nmi_rdata_d = {28'd0, s_fault_reason_q, s_fault_write_q, s_fault_pending_q};
SYSCTRL_FAULT_STATUS_OFFSET: s_nmi_rdata_d = {27'd0, s_fault_reason_q, s_fault_write_q, s_fault_pending_q};
SYSCTRL_FAULT_ADDR_OFFSET: s_nmi_rdata_d = s_fault_addr_q;
SYSCTRL_FAULT_COUNT_OFFSET: s_nmi_rdata_d = s_fault_count_q;
SYSCTRL_PLL_STATUS_OFFSET: s_nmi_rdata_d = {
@@ -286,6 +402,17 @@ module nmi_sysctrl (
s_pll_active_valid_q,
s_pll_active_sel_q
};
SYSCTRL_USER_CORE_RESET_OFFSET: s_nmi_rdata_d = {{(32 - `USER_CORE_COUNT) {1'b0}}, s_user_reset_q};
SYSCTRL_USER_CORE_STATUS_OFFSET: s_nmi_rdata_d = {
20'd0,
s_user_config_error_q,
s_user_draining_q,
sysctrl.user_bus_idle_i,
s_user_running_q,
{ (8 - `USER_CORESEL_WIDTH) {1'b0} },
s_sysctrl_coresel_q
};
SYSCTRL_FAULT_MASTER_OFFSET: s_nmi_rdata_d = {30'd0, s_fault_master_q};
default: s_nmi_rdata_d = s_nmi_rdata_q;
endcase
// verilog_format: on
+11 -16
View File
@@ -43,7 +43,7 @@ $(MPW_STAMP):
$(MPW_VARIANT_STAMP): $(MPW_STAMP) $(ROOT_PATH)/scripts/generate_mpw.py
python3 $(ROOT_PATH)/scripts/generate_mpw.py --root $(ROOT_PATH) \
--output $(MPW_OUTPUT_DIR) --simu $(SIMU) --core $(CORE) --ip $(IP) \
--output $(MPW_OUTPUT_DIR) --simu $(SIMU) \
--lock-file $(CACHE_ROOT)/locks/mpw.lock
@mkdir -p $(@D)
@touch $@
@@ -52,7 +52,7 @@ gen_mpw_code: $(MPW_VARIANT_STAMP)
$(MEMORY_MAP_STAMP): $(MEMORY_MAP_SOURCE) $(MEMORY_MAP_SCRIPT)
python3 $(MEMORY_MAP_SCRIPT) --map $(MEMORY_MAP_SOURCE) \
--output-dir $(MEMORY_MAP_DIR) --have-sram-if $(HAVE_SRAM_IF) --ip $(IP)
--output-dir $(MEMORY_MAP_DIR) --have-sram-if $(HAVE_SRAM_IF)
@touch $@
memory-map: $(MEMORY_MAP_STAMP)
@@ -71,16 +71,14 @@ check-pin-map:
$(SOC_TOPOLOGY_STAMP): $(SOC_TOPOLOGY_SOURCE) $(SOC_TOPOLOGY_SCRIPT) $(MEMORY_MAP_SOURCE)
python3 $(SOC_TOPOLOGY_SCRIPT) --map $(SOC_TOPOLOGY_SOURCE) \
--memory-map $(MEMORY_MAP_SOURCE) --ip $(IP) --output-dir $(SOC_TOPOLOGY_DIR)
--memory-map $(MEMORY_MAP_SOURCE) --output-dir $(SOC_TOPOLOGY_DIR)
@touch $@
soc-topology: $(SOC_TOPOLOGY_STAMP)
check-soc-topology:
python3 $(SOC_TOPOLOGY_SCRIPT) --map $(SOC_TOPOLOGY_SOURCE) \
--memory-map $(MEMORY_MAP_SOURCE) --ip NONE --check
python3 $(SOC_TOPOLOGY_SCRIPT) --map $(SOC_TOPOLOGY_SOURCE) \
--memory-map $(MEMORY_MAP_SOURCE) --ip MDD --check
--memory-map $(MEMORY_MAP_SOURCE) --check
$(USER_EXTENSIONS_STAMP): $(USER_EXTENSIONS_SOURCE) $(USER_EXTENSIONS_SCRIPT)
python3 $(USER_EXTENSIONS_SCRIPT) --map $(USER_EXTENSIONS_SOURCE) \
@@ -130,18 +128,15 @@ RTL_FLIST := -f $(MEMORY_MAP_FILELIST) -f $(PIN_MAP_FILELIST) -f $(SOC_TOPOLOGY_
RTL_FLIST += -f $(GENERATED_FL_DIR)/clusterip.fl
RTL_FLIST += -f $(GENERATED_FL_DIR)/ip.fl
RTL_FLIST += -f $(GENERATED_FL_DIR)/tech.fl
ifeq ($(CORE), PICORV32)
RTL_FLIST += -f $(GENERATED_FL_DIR)/core_picorv32.fl
else ifeq ($(CORE), HAZARD3)
RTL_FLIST += -f $(GENERATED_FL_DIR)/core_hazard3.fl
else ifeq ($(CORE), MDD)
RTL_FLIST += -f $(MPW_OUTPUT_DIR)/core/core.fl
ifeq ($(CORE),HAZARD3)
MGMT_CORE_FILELIST := core_hazard3.fl
else
MGMT_CORE_FILELIST := core_picorv32.fl
endif
RTL_FLIST += -f $(GENERATED_FL_DIR)/$(MGMT_CORE_FILELIST)
ifeq ($(IP), MDD)
RTL_FLIST += -f $(MPW_OUTPUT_DIR)/ip/ip.fl
endif
RTL_FLIST += -f $(MPW_OUTPUT_DIR)/core/core.fl
RTL_FLIST += -f $(MPW_OUTPUT_DIR)/ip/ip.fl
RTL_FLIST += -f $(GENERATED_FL_DIR)/top.fl
#====================== end ======================
+44 -16
View File
@@ -14,6 +14,7 @@ from typing import Any
MAX_ADDRESS = 1 << 32
VALID_ROUTES = {"native", "apb", "ram", "reserved"}
VALID_KINDS = {"active", "reserved"}
VALID_USER_ACCESS = {"none", "ro", "rw"}
def parse_integer(value: Any, field: str) -> int:
@@ -53,9 +54,13 @@ def read_map(path: Path) -> tuple[int, list[dict[str, Any]]]:
raise ValueError(f"regions[{index}] has invalid route or kind")
if (route == "reserved") != (kind == "reserved"):
raise ValueError(f"regions[{index}] reserved route and kind must agree")
requires_ip = region.get("requires_ip")
if requires_ip is not None and requires_ip != "MDD":
raise ValueError(f"regions[{index}].requires_ip must be MDD when present")
user_access = region.get("user_access")
if user_access not in VALID_USER_ACCESS:
raise ValueError(
f"regions[{index}].user_access must be one of {sorted(VALID_USER_ACCESS)}"
)
if kind == "reserved" and user_access != "none":
raise ValueError(f"regions[{index}] reserved regions must deny user access")
base = parse_integer(region.get("base"), f"regions[{index}].base")
size = parse_integer(region.get("size"), f"regions[{index}].size")
if base < 0 or size <= 0 or base + size > MAX_ADDRESS:
@@ -72,7 +77,7 @@ def read_map(path: Path) -> tuple[int, list[dict[str, Any]]]:
"kind": kind,
"public": region.get("public", False) is True,
"linker": region.get("linker"),
"requires_ip": requires_ip,
"user_access": user_access,
}
)
previous: dict[str, Any] | None = None
@@ -91,8 +96,13 @@ def c_hex32(value: int) -> str:
return f"UINT32_C(0x{value:08X})"
def range_expression(symbol: str) -> str:
return f"((addr) >= `SOC_ADDR_{symbol}_BASE && (addr) <= `SOC_ADDR_{symbol}_END)"
def range_expression(symbol: str, base: int, end: int) -> str:
conditions: list[str] = []
if base != 0:
conditions.append(f"(addr) >= `SOC_ADDR_{symbol}_BASE")
if end != MAX_ADDRESS - 1:
conditions.append(f"(addr) <= `SOC_ADDR_{symbol}_END")
return "(" + " && ".join(conditions or ["1'b1"]) + ")"
def join_or(expressions: list[str]) -> str:
@@ -117,7 +127,8 @@ def render_rtl(cpu_reset: int, regions: list[dict[str, Any]]) -> str:
lines += [
f"`define SOC_ADDR_{symbol}_BASE {hex32(region['base'])}",
f"`define SOC_ADDR_{symbol}_END {hex32(region['end'])}",
f"`define SOC_ADDR_IS_{symbol}(addr) {range_expression(symbol)}",
f"`define SOC_ADDR_IS_{symbol}(addr) "
f"{range_expression(symbol, region['base'], region['end'])}",
]
lines.append("")
for route in ("native", "apb", "ram", "reserved"):
@@ -127,6 +138,21 @@ def render_rtl(cpu_reset: int, regions: list[dict[str, Any]]) -> str:
if region["route"] == route
]
lines.append(f"`define SOC_ADDR_IS_{route.upper()}(addr) ({join_or(selected)})")
user_readable = [
f"`SOC_ADDR_IS_{region['symbol']}(addr)"
for region in regions
if region["user_access"] in {"ro", "rw"}
]
user_writable = [
f"`SOC_ADDR_IS_{region['symbol']}(addr)"
for region in regions
if region["user_access"] == "rw"
]
lines += [
"",
f"`define SOC_USER_ADDR_READABLE(addr) ({join_or(user_readable)})",
f"`define SOC_USER_ADDR_WRITABLE(addr) ({join_or(user_writable)})",
]
lines += [
"",
"`define SOC_SYSCTRL_PLL_CFG_OFFSET 32'h00000008",
@@ -135,6 +161,9 @@ def render_rtl(cpu_reset: int, regions: list[dict[str, Any]]) -> str:
"`define SOC_SYSCTRL_FAULT_ADDR_OFFSET 32'h00000014",
"`define SOC_SYSCTRL_FAULT_COUNT_OFFSET 32'h00000018",
"`define SOC_SYSCTRL_PLL_STATUS_OFFSET 32'h0000001C",
"`define SOC_SYSCTRL_USER_CORE_RESET_OFFSET 32'h00000020",
"`define SOC_SYSCTRL_USER_CORE_STATUS_OFFSET 32'h00000024",
"`define SOC_SYSCTRL_FAULT_MASTER_OFFSET 32'h00000028",
"",
"`endif",
"",
@@ -171,6 +200,9 @@ def render_c(cpu_reset: int, regions: list[dict[str, Any]], have_sram_if: str) -
"#define RS_SOC_SYSCTRL_FAULT_ADDR_OFFSET UINT32_C(0x00000014)",
"#define RS_SOC_SYSCTRL_FAULT_COUNT_OFFSET UINT32_C(0x00000018)",
"#define RS_SOC_SYSCTRL_PLL_STATUS_OFFSET UINT32_C(0x0000001C)",
"#define RS_SOC_SYSCTRL_USER_CORE_RESET_OFFSET UINT32_C(0x00000020)",
"#define RS_SOC_SYSCTRL_USER_CORE_STATUS_OFFSET UINT32_C(0x00000024)",
"#define RS_SOC_SYSCTRL_FAULT_MASTER_OFFSET UINT32_C(0x00000028)",
"",
"#endif",
"",
@@ -211,18 +243,15 @@ def atomic_write(path: Path, content: str) -> None:
raise
def generate(map_path: Path, output_dir: Path, have_sram_if: str, ip: str) -> None:
def generate(map_path: Path, output_dir: Path, have_sram_if: str) -> None:
cpu_reset, regions = read_map(map_path)
enabled_regions = [
region for region in regions if region["requires_ip"] is None or region["requires_ip"] == ip
]
atomic_write(output_dir / "rtl" / "mmap_define.svh", render_rtl(cpu_reset, enabled_regions))
atomic_write(output_dir / "rtl" / "mmap_define.svh", render_rtl(cpu_reset, regions))
atomic_write(output_dir / "memory_map.fl", f"+incdir+{output_dir / 'rtl'}\n")
atomic_write(
output_dir / "include" / "retrosoc" / "generated" / "memory_map.h",
render_c(cpu_reset, enabled_regions, have_sram_if),
render_c(cpu_reset, regions, have_sram_if),
)
atomic_write(output_dir / "linker" / "memory_regions.ld", render_linker(enabled_regions))
atomic_write(output_dir / "linker" / "memory_regions.ld", render_linker(regions))
def main() -> int:
@@ -230,7 +259,6 @@ def main() -> int:
parser.add_argument("--map", required=True, type=Path)
parser.add_argument("--output-dir", type=Path)
parser.add_argument("--have-sram-if", choices=("YES", "NO"), default="NO")
parser.add_argument("--ip", choices=("NONE", "MDD"), default="NONE")
parser.add_argument("--check", action="store_true", help="validate only; write nothing")
arguments = parser.parse_args()
try:
@@ -239,7 +267,7 @@ def main() -> int:
else:
if arguments.output_dir is None:
parser.error("--output-dir is required unless --check is used")
generate(arguments.map, arguments.output_dir, arguments.have_sram_if, arguments.ip)
generate(arguments.map, arguments.output_dir, arguments.have_sram_if)
except (OSError, ValueError, json.JSONDecodeError) as error:
parser.error(str(error))
return 0
+37 -37
View File
@@ -2,42 +2,42 @@
"schema_version": 1,
"cpu_reset": "0x00000000",
"regions": [
{"symbol": "FLASH", "base": "0x00000000", "size": "0x01000000", "route": "native", "kind": "active", "public": true, "linker": "FLASH"},
{"symbol": "NMI_GPIO", "base": "0x10000000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_UART0", "base": "0x10001000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_TIM0", "base": "0x10002000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_TIM1", "base": "0x10003000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_PSRAM", "base": "0x10004000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_SPISD", "base": "0x10005000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_I2C0", "base": "0x10006000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_I2S", "base": "0x10007000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_ONEWIRE", "base": "0x10008000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_XPI", "base": "0x10009000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_DMA", "base": "0x1000A000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_SYSCTRL", "base": "0x1000B000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_CLINT", "base": "0x1000C000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_SDRAM", "base": "0x1000D000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_DVP", "base": "0x1000E000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_SDIO", "base": "0x1000F000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false},
{"symbol": "NMI_OPIPSRAM", "base": "0x10010000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false},
{"symbol": "NMI_I2C1", "base": "0x10011000", "size": "0x00001000", "route": "native", "kind": "active", "public": true},
{"symbol": "NMI_GA", "base": "0x10012000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false},
{"symbol": "NMI_APU", "base": "0x10013000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false},
{"symbol": "APB_ARCHINFO", "base": "0x20000000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_RNG", "base": "0x20001000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_UART1", "base": "0x20002000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_PWM", "base": "0x20003000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_PS2", "base": "0x20004000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_RTC", "base": "0x20005000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_WDG", "base": "0x20006000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_CRC", "base": "0x20007000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_TMR", "base": "0x20008000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true},
{"symbol": "APB_USER_IP", "base": "0x2000F000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "requires_ip": "MDD"},
{"symbol": "SRAM", "base": "0x30000000", "size": "0x00020000", "route": "ram", "kind": "active", "public": true, "linker": "SRAM"},
{"symbol": "SDRAM", "base": "0x38000000", "size": "0x02000000", "route": "native", "kind": "active", "public": true, "linker": "SDRAM"},
{"symbol": "PSRAM", "base": "0x40000000", "size": "0x00800000", "route": "native", "kind": "active", "public": true, "linker": "PSRAM"},
{"symbol": "OPIPSRAM", "base": "0x48000000", "size": "0x08000000", "route": "reserved", "kind": "reserved", "public": false},
{"symbol": "XPI", "base": "0x50000000", "size": "0x10000000", "route": "native", "kind": "active", "public": true},
{"symbol": "SPISD", "base": "0x60000000", "size": "0x40000000", "route": "native", "kind": "active", "public": true}
{"symbol": "FLASH", "base": "0x00000000", "size": "0x01000000", "route": "native", "kind": "active", "public": true, "linker": "FLASH", "user_access": "ro"},
{"symbol": "NMI_GPIO", "base": "0x10000000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_UART0", "base": "0x10001000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_TIM0", "base": "0x10002000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_TIM1", "base": "0x10003000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_PSRAM", "base": "0x10004000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "NMI_SPISD", "base": "0x10005000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_I2C0", "base": "0x10006000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_I2S", "base": "0x10007000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_ONEWIRE", "base": "0x10008000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_XPI", "base": "0x10009000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "NMI_DMA", "base": "0x1000A000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "NMI_SYSCTRL", "base": "0x1000B000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "NMI_CLINT", "base": "0x1000C000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "NMI_SDRAM", "base": "0x1000D000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "NMI_DVP", "base": "0x1000E000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_SDIO", "base": "0x1000F000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
{"symbol": "NMI_OPIPSRAM", "base": "0x10010000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
{"symbol": "NMI_I2C1", "base": "0x10011000", "size": "0x00001000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "NMI_GA", "base": "0x10012000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
{"symbol": "NMI_APU", "base": "0x10013000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
{"symbol": "APB_ARCHINFO", "base": "0x20000000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "ro"},
{"symbol": "APB_RNG", "base": "0x20001000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_UART1", "base": "0x20002000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_PWM", "base": "0x20003000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_PS2", "base": "0x20004000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_RTC", "base": "0x20005000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_WDG", "base": "0x20006000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "APB_CRC", "base": "0x20007000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_TMR", "base": "0x20008000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_USER_IP", "base": "0x2000F000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "SRAM", "base": "0x30000000", "size": "0x00020000", "route": "ram", "kind": "active", "public": true, "linker": "SRAM", "user_access": "rw"},
{"symbol": "SDRAM", "base": "0x38000000", "size": "0x02000000", "route": "native", "kind": "active", "public": true, "linker": "SDRAM", "user_access": "rw"},
{"symbol": "PSRAM", "base": "0x40000000", "size": "0x00800000", "route": "native", "kind": "active", "public": true, "linker": "PSRAM", "user_access": "rw"},
{"symbol": "OPIPSRAM", "base": "0x48000000", "size": "0x08000000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
{"symbol": "XPI", "base": "0x50000000", "size": "0x10000000", "route": "native", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "SPISD", "base": "0x60000000", "size": "0x40000000", "route": "native", "kind": "active", "public": true, "user_access": "rw"}
]
}
+19 -17
View File
@@ -12,26 +12,28 @@
`ifndef SYNTHESIS
module soc_bus_sva (
input logic clk_i,
input logic rst_n_i,
input logic fault_sel_i,
input logic fault_valid_i,
input logic arb_locked_i,
input logic arb_dma_owner_i,
input logic core_valid_i,
input logic dma_valid_i
input logic clk_i,
input logic rst_n_i,
input logic fault_sel_i,
input logic fault_valid_i,
input logic access_denied_i,
input logic arb_locked_i,
input logic [1:0] arb_owner_i,
input logic mgmt_valid_i,
input logic user_valid_i,
input logic dma_valid_i
);
// A decode miss must be reported and terminate the transaction locally.
assert property (@(posedge clk_i) disable iff (!rst_n_i) fault_sel_i |-> fault_valid_i);
// Retain the documented DMA-over-core arbitration policy while idle.
// A sole management request must acquire ownership rather than being dropped.
assert property (@(posedge clk_i) disable iff (!rst_n_i)
!arb_locked_i && dma_valid_i |=> arb_locked_i && arb_dma_owner_i);
!arb_locked_i && mgmt_valid_i && !user_valid_i && !dma_valid_i |=>
arb_locked_i && arb_owner_i == 2'd0);
// A sole core request must acquire ownership rather than being dropped.
assert property (@(posedge clk_i) disable iff (!rst_n_i)
!arb_locked_i && core_valid_i && !dma_valid_i |=> arb_locked_i && !arb_dma_owner_i);
// A denied user request terminates locally and cannot reach a target.
assert property (@(posedge clk_i) disable iff (!rst_n_i) access_denied_i |-> fault_valid_i);
endmodule
@@ -41,8 +43,10 @@ bind bus soc_bus_sva u_soc_bus_sva (
.fault_sel_i (s_fault_sel),
.fault_valid_i (fault_valid_o),
.arb_locked_i (s_mstr_lock_q),
.arb_dma_owner_i(s_mstr_id_q),
.core_valid_i (core_nmi.valid),
.access_denied_i(s_access_denied),
.arb_owner_i (s_mstr_id_q),
.mgmt_valid_i (mgmt_nmi.valid),
.user_valid_i (user_nmi.valid),
.dma_valid_i (dma_nmi.valid)
);
@@ -108,7 +112,6 @@ bind pll_rcu_controller soc_pll_rcu_sva u_soc_pll_rcu_sva (
.select_ext_clk_i(select_ext_clk_o)
);
`ifdef IP_MDD
module soc_gpio_user_handoff_sva #(
parameter int DATA_WIDTH = 1
) (
@@ -147,7 +150,6 @@ bind nmi_gpio soc_gpio_user_handoff_sva #(
.gpio_oe_i (gpio.oe_o),
.gpio_do_i (gpio.do_o)
);
`endif
`include "soc_irq_sva.svh"
`endif
+3 -11
View File
@@ -28,8 +28,6 @@ module retrosoc_tb;
`ifdef HAVE_PLL
reg r_xtal_clk;
`endif
reg [ 4:0] r_core_sel;
wire [ 4:0] s_core_sel;
wire s_uart0_tx;
// for handle x-prop issue
wire s_uart0_rx = 1'b1;
@@ -82,10 +80,9 @@ module retrosoc_tb;
always #(1000 / AUD_CPU_FREQ / 2) r_aud_clk = (r_aud_clk === 1'b0);
// connect inout pad
assign s_ext_clk = r_ext_clk;
assign s_aud_clk = r_aud_clk;
assign s_rst_n = r_rst_n;
assign s_core_sel = r_core_sel;
assign s_ext_clk = r_ext_clk;
assign s_aud_clk = r_aud_clk;
assign s_rst_n = r_rst_n;
retrosoc_asic u_retrosoc_asic (
`include "retrosoc_asic_tb_bindings.svh"
@@ -268,11 +265,6 @@ module retrosoc_tb;
initial begin
$display("========================================================");
`ifdef CORE_MDD
if (!$value$plusargs("core_sel=%d", r_core_sel)) r_core_sel = 5'd0;
$display("core_sel: %0d", r_core_sel);
`endif
`ifdef HAVE_PLL
$display("pll clock control: sysctrl");
`else
+48 -56
View File
@@ -4,30 +4,27 @@
static int signal_received = 0;
void sig_handler(int signo)
{
if (signal_received != 0)
{
void sig_handler(int signo) {
if (signal_received != 0) {
std::cout << "SIGINT received, forcely shutting down." << std::endl;
exit(1);
}
std::cout << "\nSIGINT received, gracefully shutting down... Type Ctrl+C again to stop forcely." << std::endl;
std::cout << "\nSIGINT received, gracefully shutting down... Type Ctrl+C again to stop forcely."
<< std::endl;
signal_received = signo;
}
void env_init()
{
std::cout << rang::fg::magenta << "Emulator compiled at " << __DATE__ << ", " << __TIME__ << rang::fg::reset << std::endl;
if (signal(SIGINT, sig_handler) == SIG_ERR)
{
void env_init() {
std::cout << rang::fg::magenta << "Emulator compiled at " << __DATE__ << ", " << __TIME__
<< rang::fg::reset << std::endl;
if (signal(SIGINT, sig_handler) == SIG_ERR) {
std::cout << "can't catch SIGINT" << std::endl;
}
}
extern "C" void flash_init(const char *img);
Emulator::Emulator(cxxopts::ParseResult &res)
{
Emulator::Emulator(cxxopts::ParseResult &res) {
args.dumpWave = res["dump-wave"].as<bool>();
args.dumpBegin = res["log-begin"].as<unsigned long>();
auto tmp = res["log-end"].as<unsigned long>();
@@ -41,104 +38,101 @@ Emulator::Emulator(cxxopts::ParseResult &res)
args.image = res["image"].as<std::string>();
startTime = chrono::system_clock::now();
if (args.image == "")
{
std::cout << rang::fg::red << "Image file unspecified. Use -i to provide the image of flash" << rang::fg::reset << std::endl;
if (args.image == "") {
std::cout << rang::fg::red << "Image file unspecified. Use -i to provide the image of flash"
<< rang::fg::reset << std::endl;
exit(1);
}
std::cout << rang::fg::green << "Initializing flash with " << args.image << " ..." << rang::fg::reset << std::endl;
std::cout << rang::fg::green << "Initializing flash with " << args.image << " ..."
<< rang::fg::reset << std::endl;
flash_init(args.image.c_str());
dutPtr = new Vretrosoc_top;
dutPtr->core_sel_i = res["core-sel"].as<unsigned long>();;
reset();
if (args.dumpWave)
{
if (args.dumpWave) {
#ifdef DUMP_WAVE_FST
wavePtr = new VerilatedFstC;
#endif
Verilated::traceEverOn(true);
std::cout << rang::fg::yellow << "`dump-wave` enabled, waves will be written to \"soc.wave\"." << rang::fg::reset << std::endl;
std::cout << rang::fg::yellow
<< "`dump-wave` enabled, waves will be written to \"soc.wave\"."
<< rang::fg::reset << std::endl;
dutPtr->trace(wavePtr, 1);
wavePtr->open("soc.wave");
wavePtr->dump(0);
}
}
Emulator::~Emulator()
{
if (wavePtr)
{
Emulator::~Emulator() {
if (wavePtr) {
wavePtr->close();
delete wavePtr;
}
}
void Emulator::wave()
{
void Emulator::wave() {
++cycle;
if (args.dumpWave && args.dumpBegin <= cycle && cycle <= args.dumpEnd)
{
if (args.dumpWave && args.dumpBegin <= cycle && cycle <= args.dumpEnd) {
wavePtr->dump((vluint64_t)cycle);
}
}
void Emulator::reset()
{
std::cout << rang::fg::yellow << "Initializing and resetting DUT ..." << rang::fg::reset << std::endl;
void Emulator::reset() {
std::cout << rang::fg::yellow << "Initializing and resetting DUT ..." << rang::fg::reset
<< std::endl;
dutPtr->rst_n_i = 1;
dutPtr->ext_clk_i = 0;
dutPtr->eval();
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " << static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " <<
// static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
for (int i = 0; i < 10; i++)
{
for (int i = 0; i < 10; i++) {
dutPtr->ext_clk_i = !dutPtr->ext_clk_i;
dutPtr->eval();
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " << static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " <<
// static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
}
dutPtr->rst_n_i = 0;
for (int i = 0; i < 10; i++)
{
for (int i = 0; i < 10; i++) {
dutPtr->ext_clk_i = !dutPtr->ext_clk_i;
dutPtr->eval();
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " << static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " <<
// static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
}
dutPtr->rst_n_i = 1;
for (int i = 0; i < 5; i++)
{
for (int i = 0; i < 5; i++) {
dutPtr->ext_clk_i = !dutPtr->ext_clk_i;
dutPtr->eval();
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " << static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " <<
// static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
}
std::cout << rang::fg::yellow << "Initializing and resetting DUT done" << rang::fg::reset << std::endl;
std::cout << rang::fg::yellow << "Initializing and resetting DUT done" << rang::fg::reset
<< std::endl;
}
void Emulator::step()
{
void Emulator::step() {
dutPtr->ext_clk_i = !dutPtr->ext_clk_i;
dutPtr->eval();
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " << static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
// std::cout << "rst_n_i: " << static_cast<unsigned>(dutPtr->rst_n_i) << " ext_clk_i: " <<
// static_cast<unsigned>(dutPtr->ext_clk_i) << std::endl;
++cycle;
if (args.dumpWave && args.dumpBegin <= cycle && cycle <= args.dumpEnd)
{
if (args.dumpWave && args.dumpBegin <= cycle && cycle <= args.dumpEnd) {
wavePtr->dump((vluint64_t)cycle);
}
}
void Emulator::state()
{
void Emulator::state() {
auto elapsed = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - startTime);
std::cout << rang::fg::yellow << "Simulation " << cycle << " cycles in " << elapsed.count() << "s" << rang::fg::reset << std::endl;
std::cout << rang::fg::yellow << "Simulation " << cycle << " cycles in " << elapsed.count()
<< "s" << rang::fg::reset << std::endl;
}
bool Emulator::getArriveTime()
{
bool Emulator::getArriveTime() {
auto elapsed = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - startTime);
if (elapsed.count() > args.simTime)
return true;
@@ -146,11 +140,9 @@ bool Emulator::getArriveTime()
return false;
}
void Emulator::runSim()
{
void Emulator::runSim() {
std::cout << rang::fg::yellow << "Running DUT simulation..." << rang::fg::reset << std::endl;
while (!Verilated::gotFinish() && signal_received == 0 && !getArriveTime())
{
while (!Verilated::gotFinish() && signal_received == 0 && !getArriveTime()) {
step();
}
dutPtr->final();
+8 -13
View File
@@ -10,24 +10,20 @@
static Emulator *emu = nullptr;
cxxopts::Options args("emu", "retroSoC Verilator Emulator");
void release()
{
if (emu != nullptr)
{
void release() {
if (emu != nullptr) {
emu->state();
delete emu;
}
}
void parseArgs(int argc, char *argv[])
{
void parseArgs(int argc, char *argv[]) {
// clang-format off
args.add_options()
("h, help", "print usage")
("d, dump-wave", "dump FST format waveform when log is enabled", cxxopts::value<bool>()->default_value("false"))
("b, log-begin", "display log from [NUM] th cycle", cxxopts::value<unsigned long>()->default_value("0"))
("e, log-end", "stop display log at [NUM] th cycle", cxxopts::value<unsigned long>()->default_value("0"))
("s, core-sel", "select id [NUM] core", cxxopts::value<unsigned long>()->default_value("0"))
("t, sim-time", "stop simulation after [NUM] seconds", cxxopts::value<unsigned long>()->default_value("0"))
("i, image", "run with this image file", cxxopts::value<std::string>());
// clang-format on
@@ -35,21 +31,20 @@ void parseArgs(int argc, char *argv[])
}
extern void env_init();
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
env_init();
atexit(release);
parseArgs(argc, argv);
auto res = args.parse(argc, argv);
if (res.count("help"))
{
if (res.count("help")) {
std::cout << args.help() << std::endl;
exit(0);
}
emu = new Emulator(res);
std::cout << rang::fg::yellow << "[verilator]start simulating ..." << rang::fg::reset << std::endl;
std::cout << rang::fg::yellow << "[verilator]start simulating ..." << rang::fg::reset
<< std::endl;
emu->runSim();
return 0;
}
}
+18 -22
View File
@@ -21,31 +21,27 @@
`timescale 1 ns / 1 ps
module retrosoc_top (
input wire ext_clk_i,
input wire rst_n_i,
input wire [4:0] core_sel_i
input wire ext_clk_i,
input wire rst_n_i
);
wire s_clk;
wire s_rst_n;
wire [4:0] s_core_sel;
wire s_psram_sck;
wire s_psram_nss0;
wire s_psram_dat0;
wire s_psram_dat1;
wire s_psram_dat2;
wire s_psram_dat3;
wire s_xpi_nss0_o;
wire s_xpi_sck_o;
wire s_xpi_dat0_io;
wire s_xpi_dat1_io;
wire s_xpi_dat2_io;
wire s_xpi_dat3_io;
assign s_clk = ext_clk_i;
assign s_rst_n = rst_n_i;
assign s_core_sel = core_sel_i;
wire s_clk;
wire s_rst_n;
wire s_psram_sck;
wire s_psram_nss0;
wire s_psram_dat0;
wire s_psram_dat1;
wire s_psram_dat2;
wire s_psram_dat3;
wire s_xpi_nss0_o;
wire s_xpi_sck_o;
wire s_xpi_dat0_io;
wire s_xpi_dat1_io;
wire s_xpi_dat2_io;
wire s_xpi_dat3_io;
assign s_clk = ext_clk_i;
assign s_rst_n = rst_n_i;
retrosoc_asic u_retrosoc_asic (
`include "retrosoc_asic_verilator_bindings.svh"
);
-1
View File
@@ -11,7 +11,6 @@
/top/mgmt_core_wrapper.sv
/top/user_core_design_template.sv
/top/user_core_top.sv
/top/user_core_wrapper.sv
/top/user_ip_design_template.sv
/top/user_ip_top.sv
/top/user_ip_wrapper.sv
+56 -48
View File
@@ -1,45 +1,42 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
module bus_formal_design (
input logic clk_i,
output logic rst_n_i,
output logic f_past_valid,
output logic core_valid,
output logic [31:0] core_addr,
output logic [31:0] core_wdata,
output logic [ 3:0] core_wstrb,
output logic core_ready,
output logic mgmt_valid,
output logic [31:0] mgmt_addr,
output logic [ 3:0] mgmt_wstrb,
output logic mgmt_ready,
output logic user_valid,
output logic [31:0] user_addr,
output logic [ 3:0] user_wstrb,
output logic user_ready,
output logic dma_valid,
output logic [31:0] dma_addr,
output logic [31:0] dma_wdata,
output logic [ 3:0] dma_wstrb,
output logic dma_ready,
output logic natv_valid,
output logic apb_valid,
output logic fault_valid,
output logic fault_reserved,
output logic fault_sel,
output logic fault_access,
output logic arb_locked,
output logic arb_dma_owner
output logic [ 1:0] arb_owner
);
nmi_if core_nmi ();
nmi_if mgmt_nmi ();
nmi_if user_nmi ();
nmi_if dma_nmi ();
nmi_if natv_nmi ();
nmi_if apb_nmi ();
(* anyseq *)logic f_core_valid;
(* anyseq *)logic [31:0] f_core_addr;
(* anyseq *)logic [31:0] f_core_wdata;
(* anyseq *)logic [ 3:0] f_core_wstrb;
(* anyseq *)logic f_mgmt_valid;
(* anyseq *)logic [31:0] f_mgmt_addr;
(* anyseq *)logic [31:0] f_mgmt_wdata;
(* anyseq *)logic [ 3:0] f_mgmt_wstrb;
(* anyseq *)logic f_user_valid;
(* anyseq *)logic [31:0] f_user_addr;
(* anyseq *)logic [31:0] f_user_wdata;
(* anyseq *)logic [ 3:0] f_user_wstrb;
(* anyseq *)logic f_dma_valid;
(* anyseq *)logic [31:0] f_dma_addr;
(* anyseq *)logic [31:0] f_dma_wdata;
@@ -50,11 +47,18 @@ module bus_formal_design (
(* anyseq *)logic [31:0] f_apb_rdata;
logic [31:0] fault_addr;
logic [ 3:0] fault_wstrb;
logic fault_reserved;
logic [ 1:0] fault_master;
logic user_idle;
assign core_nmi.valid = f_core_valid;
assign core_nmi.addr = f_core_addr;
assign core_nmi.wdata = f_core_wdata;
assign core_nmi.wstrb = f_core_wstrb;
assign mgmt_nmi.valid = f_mgmt_valid;
assign mgmt_nmi.addr = f_mgmt_addr;
assign mgmt_nmi.wdata = f_mgmt_wdata;
assign mgmt_nmi.wstrb = f_mgmt_wstrb;
assign user_nmi.valid = f_user_valid;
assign user_nmi.addr = f_user_addr;
assign user_nmi.wdata = f_user_wdata;
assign user_nmi.wstrb = f_user_wstrb;
assign dma_nmi.valid = f_dma_valid;
assign dma_nmi.addr = f_dma_addr;
assign dma_nmi.wdata = f_dma_wdata;
@@ -64,35 +68,39 @@ module bus_formal_design (
assign apb_nmi.ready = f_apb_ready;
assign apb_nmi.rdata = f_apb_rdata;
assign core_valid = core_nmi.valid;
assign core_addr = core_nmi.addr;
assign core_wdata = core_nmi.wdata;
assign core_wstrb = core_nmi.wstrb;
assign core_ready = core_nmi.ready;
assign mgmt_valid = mgmt_nmi.valid;
assign mgmt_addr = mgmt_nmi.addr;
assign mgmt_wstrb = mgmt_nmi.wstrb;
assign mgmt_ready = mgmt_nmi.ready;
assign user_valid = user_nmi.valid;
assign user_addr = user_nmi.addr;
assign user_wstrb = user_nmi.wstrb;
assign user_ready = user_nmi.ready;
assign dma_valid = dma_nmi.valid;
assign dma_addr = dma_nmi.addr;
assign dma_wdata = dma_nmi.wdata;
assign dma_wstrb = dma_nmi.wstrb;
assign dma_ready = dma_nmi.ready;
assign natv_valid = natv_nmi.valid;
assign apb_valid = apb_nmi.valid;
bus u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.core_nmi (core_nmi),
.dma_nmi (dma_nmi),
.natv_nmi (natv_nmi),
.apb_nmi (apb_nmi),
.fault_valid_o (fault_valid),
.fault_addr_o (fault_addr),
.fault_wstrb_o (fault_wstrb),
.fault_reserved_o(fault_reserved)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.mgmt_nmi (mgmt_nmi),
.user_nmi (user_nmi),
.dma_nmi (dma_nmi),
.user_bus_enable_i(1'b1),
.user_bus_idle_o (user_idle),
.natv_nmi (natv_nmi),
.apb_nmi (apb_nmi),
.fault_valid_o (fault_valid),
.fault_addr_o (fault_addr),
.fault_wstrb_o (fault_wstrb),
.fault_reserved_o (fault_reserved),
.fault_access_o (fault_access),
.fault_master_o (fault_master)
);
assign fault_sel = u_dut.s_fault_sel;
assign arb_locked = u_dut.s_mstr_lock_q;
assign arb_dma_owner = u_dut.s_mstr_id_q;
assign arb_locked = u_dut.s_mstr_lock_q;
assign arb_owner = u_dut.s_mstr_id_q;
initial begin
rst_n_i = 1'b0;
+45 -56
View File
@@ -1,85 +1,74 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
module bus_formal;
(* anyseq *) (* gclk *)reg clk_i;
wire rst_n_i;
wire f_past_valid;
wire core_valid;
wire [31:0] core_addr;
wire [31:0] core_wdata;
wire [ 3:0] core_wstrb;
wire core_ready;
wire mgmt_valid;
wire [31:0] mgmt_addr;
wire [ 3:0] mgmt_wstrb;
wire mgmt_ready;
wire user_valid;
wire [31:0] user_addr;
wire [ 3:0] user_wstrb;
wire user_ready;
wire dma_valid;
wire [31:0] dma_addr;
wire [31:0] dma_wdata;
wire [ 3:0] dma_wstrb;
wire dma_ready;
wire natv_valid;
wire apb_valid;
wire fault_valid;
wire fault_reserved;
wire fault_sel;
wire fault_access;
wire arb_locked;
wire arb_dma_owner;
wire [ 1:0] arb_owner;
bus_formal_design u_design (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.f_past_valid (f_past_valid),
.core_valid (core_valid),
.core_addr (core_addr),
.core_wdata (core_wdata),
.core_wstrb (core_wstrb),
.core_ready (core_ready),
.dma_valid (dma_valid),
.dma_addr (dma_addr),
.dma_wdata (dma_wdata),
.dma_wstrb (dma_wstrb),
.dma_ready (dma_ready),
.natv_valid (natv_valid),
.apb_valid (apb_valid),
.fault_valid (fault_valid),
.fault_reserved(fault_reserved),
.fault_sel (fault_sel),
.arb_locked (arb_locked),
.arb_dma_owner (arb_dma_owner)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.f_past_valid(f_past_valid),
.mgmt_valid (mgmt_valid),
.mgmt_addr (mgmt_addr),
.mgmt_wstrb (mgmt_wstrb),
.mgmt_ready (mgmt_ready),
.user_valid (user_valid),
.user_addr (user_addr),
.user_wstrb (user_wstrb),
.user_ready (user_ready),
.dma_valid (dma_valid),
.dma_ready (dma_ready),
.natv_valid (natv_valid),
.apb_valid (apb_valid),
.fault_valid (fault_valid),
.fault_access(fault_access),
.arb_locked (arb_locked),
.arb_owner (arb_owner)
);
always @(posedge clk_i) begin
if (f_past_valid && $past(rst_n_i && core_valid && !core_ready)) begin
assume (core_valid);
assume (core_addr == $past(core_addr));
assume (core_wdata == $past(core_wdata));
assume (core_wstrb == $past(core_wstrb));
if (f_past_valid && $past(rst_n_i && mgmt_valid && !mgmt_ready)) begin
assume (mgmt_valid);
assume (mgmt_addr == $past(mgmt_addr));
assume (mgmt_wstrb == $past(mgmt_wstrb));
end
if (f_past_valid && $past(rst_n_i && dma_valid && !dma_ready)) begin
assume (dma_valid);
assume (dma_addr == $past(dma_addr));
assume (dma_wdata == $past(dma_wdata));
assume (dma_wstrb == $past(dma_wstrb));
if (f_past_valid && $past(rst_n_i && user_valid && !user_ready)) begin
assume (user_valid);
assume (user_addr == $past(user_addr));
assume (user_wstrb == $past(user_wstrb));
end
if (rst_n_i) begin
assert (!(natv_valid && apb_valid));
assert (!(fault_valid && (natv_valid || apb_valid)));
assert (fault_valid == fault_sel);
if (f_past_valid && $past(rst_n_i && !arb_locked && dma_valid)) begin
assert (arb_locked && arb_dma_owner);
if (fault_access) begin
assert (fault_valid);
end
if (f_past_valid && $past(rst_n_i && !arb_locked && core_valid && !dma_valid)) begin
assert (arb_locked && !arb_dma_owner);
if (f_past_valid && $past(
rst_n_i && !arb_locked && mgmt_valid && !user_valid && !dma_valid
)) begin
assert (arb_locked && arb_owner == 2'd0);
end
cover (arb_locked && arb_dma_owner);
cover (fault_valid && fault_reserved);
cover (arb_locked && arb_owner == 2'd1);
cover (fault_access);
end
end
+13 -6
View File
@@ -23,8 +23,6 @@ TOP = ROOT / "rtl/mini/top"
def target_defines(target: str) -> list[str]:
if target == "gpio_mdd":
return ["+define+SV_ASSRT_DISABLE", "+define+IP_MDD"]
return ["+define+SV_ASSRT_DISABLE"]
@@ -65,23 +63,30 @@ def source_files(target: str) -> list[Path]:
TOP / "rcu.sv",
SCRIPT_DIR / "pll_rcu_formal.sv",
]
if target == "gpio_mdd":
if target == "gpio_user":
return [
*common,
COMMON_RTL / "cdc/cdc_sync.sv",
COMMON_RTL / "utils/edge_det.sv",
PERIPHERAL / "gpio.sv",
SCRIPT_DIR / "gpio_mdd_formal.sv",
SCRIPT_DIR / "gpio_user_formal.sv",
]
raise ValueError(f"unsupported formal target: {target}")
def generate(target: str, output: Path, memory_map_dir: Path, soc_topology_dir: Path) -> bool:
def generate(
target: str,
output: Path,
memory_map_dir: Path,
soc_topology_dir: Path,
user_extensions_dir: Path,
) -> bool:
filelist = FileList(
defines=target_defines(target),
incdirs=[
memory_map_dir.resolve() / "rtl",
soc_topology_dir.resolve() / "rtl",
user_extensions_dir.resolve() / "rtl",
TOP,
COMMON_RTL,
COMMON_RTL / "interface",
@@ -98,12 +103,13 @@ def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--target",
choices=("bus", "nmi2apb", "sysctrl", "pll_rcu", "gpio_mdd"),
choices=("bus", "nmi2apb", "sysctrl", "pll_rcu", "gpio_user"),
required=True,
)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--memory-map-dir", type=Path, required=True)
parser.add_argument("--soc-topology-dir", type=Path, required=True)
parser.add_argument("--user-extensions-dir", type=Path, required=True)
return parser.parse_args()
@@ -114,6 +120,7 @@ def main() -> int:
args.output,
args.memory_map_dir,
args.soc_topology_dir,
args.user_extensions_dir,
)
print(f"formal filelist {'updated' if changed else 'unchanged'}: {args.output.resolve()}")
return 0
@@ -1,7 +1,7 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module gpio_mdd_formal_design (
module gpio_user_formal_design (
input logic clk_i,
output logic rst_n_i,
output logic f_past_valid,
@@ -1,7 +1,7 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module gpio_mdd_formal;
module gpio_user_formal;
(* anyseq *) (* gclk *)reg clk_i;
wire rst_n_i;
@@ -24,7 +24,7 @@ module gpio_mdd_formal;
wire [31:0] native_oe;
wire [31:0] native_do;
gpio_mdd_formal_design u_design (
gpio_user_formal_design u_design (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.f_past_valid(f_past_valid),
+10 -3
View File
@@ -12,6 +12,9 @@ module sysctrl_formal_design (
output logic nmi_ready,
output logic [ 7:0] ip_sel,
output logic [ 4:0] core_sel,
output logic [ 5:0] user_reset,
output logic user_bus_enable,
output logic user_config_error,
output logic [ 2:0] pll_cfg,
output logic pll_req_valid,
output logic pll_req_ready,
@@ -25,7 +28,7 @@ module sysctrl_formal_design (
output logic fault_reserved,
output logic fault_pending,
output logic fault_write,
output logic [ 1:0] fault_reason,
output logic [ 2:0] fault_reason,
output logic [31:0] fault_addr_q,
output logic [31:0] fault_count
);
@@ -38,7 +41,6 @@ module sysctrl_formal_design (
(* anyseq *)logic [31:0] f_nmi_addr;
(* anyseq *)logic [31:0] f_nmi_wdata;
(* anyseq *)logic [ 3:0] f_nmi_wstrb;
(* anyseq *)logic [ 4:0] f_core_sel;
(* anyseq *)logic f_pll_req_ready;
(* anyseq *)logic [ 2:0] f_pll_active_sel;
(* anyseq *)logic f_pll_active_valid;
@@ -56,7 +58,9 @@ module sysctrl_formal_design (
assign nmi.addr = f_nmi_addr;
assign nmi.wdata = f_nmi_wdata;
assign nmi.wstrb = f_nmi_wstrb;
assign sysctrl.core_sel_i = f_core_sel;
assign sysctrl.user_bus_idle_i = 1'b1;
assign sysctrl.fault_access_i = 1'b0;
assign sysctrl.fault_master_i = '0;
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_valid_i = f_pll_active_valid;
@@ -73,6 +77,9 @@ module sysctrl_formal_design (
assign nmi_ready = nmi.ready;
assign ip_sel = sysctrl.ip_sel_o;
assign core_sel = u_dut.s_sysctrl_coresel_q;
assign user_reset = u_dut.s_user_reset_q;
assign user_bus_enable = u_dut.s_user_running_q;
assign user_config_error = u_dut.s_user_config_error_q;
assign pll_cfg = u_dut.s_pll_cfg_q;
assign pll_req_valid = pll_ctrl.req_valid_o;
assign pll_req_ready = pll_ctrl.req_ready_i;
+56 -28
View File
@@ -7,6 +7,7 @@ module sysctrl_formal;
localparam [7:0] SYSCTRL_PLL_CFG_OFFSET = 8'h08;
localparam [7:0] SYSCTRL_PLL_CMD_OFFSET = 8'h0c;
localparam [7:0] SYSCTRL_FAULT_STATUS_OFFSET = 8'h10;
localparam [7:0] SYSCTRL_USER_CORE_RESET_OFFSET = 8'h20;
(* anyseq *) (* gclk *)reg clk_i;
wire rst_n_i;
@@ -18,6 +19,9 @@ module sysctrl_formal;
wire nmi_ready;
wire [ 7:0] ip_sel;
wire [ 4:0] core_sel;
wire [ 5:0] user_reset;
wire user_bus_enable;
wire user_config_error;
wire [ 2:0] pll_cfg;
wire pll_req_valid;
wire pll_req_ready;
@@ -31,37 +35,40 @@ module sysctrl_formal;
wire fault_reserved;
wire fault_pending;
wire fault_write;
wire [ 1:0] fault_reason;
wire [ 2:0] fault_reason;
wire [31:0] fault_addr_q;
wire [31:0] fault_count;
sysctrl_formal_design u_design (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.f_past_valid (f_past_valid),
.nmi_valid (nmi_valid),
.nmi_addr (nmi_addr),
.nmi_wdata (nmi_wdata),
.nmi_wstrb (nmi_wstrb),
.nmi_ready (nmi_ready),
.ip_sel (ip_sel),
.core_sel (core_sel),
.pll_cfg (pll_cfg),
.pll_req_valid (pll_req_valid),
.pll_req_ready (pll_req_ready),
.pll_busy (pll_busy),
.pll_error (pll_error),
.pll_error_reason(pll_error_reason),
.pll_rsp_valid (pll_rsp_valid),
.fault_valid (fault_valid),
.fault_addr (fault_addr),
.fault_wstrb (fault_wstrb),
.fault_reserved (fault_reserved),
.fault_pending (fault_pending),
.fault_write (fault_write),
.fault_reason (fault_reason),
.fault_addr_q (fault_addr_q),
.fault_count (fault_count)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.f_past_valid (f_past_valid),
.nmi_valid (nmi_valid),
.nmi_addr (nmi_addr),
.nmi_wdata (nmi_wdata),
.nmi_wstrb (nmi_wstrb),
.nmi_ready (nmi_ready),
.ip_sel (ip_sel),
.core_sel (core_sel),
.user_reset (user_reset),
.user_bus_enable (user_bus_enable),
.user_config_error(user_config_error),
.pll_cfg (pll_cfg),
.pll_req_valid (pll_req_valid),
.pll_req_ready (pll_req_ready),
.pll_busy (pll_busy),
.pll_error (pll_error),
.pll_error_reason (pll_error_reason),
.pll_rsp_valid (pll_rsp_valid),
.fault_valid (fault_valid),
.fault_addr (fault_addr),
.fault_wstrb (fault_wstrb),
.fault_reserved (fault_reserved),
.fault_pending (fault_pending),
.fault_write (fault_write),
.fault_reason (fault_reason),
.fault_addr_q (fault_addr_q),
.fault_count (fault_count)
);
always @(posedge clk_i) begin
@@ -76,6 +83,27 @@ module sysctrl_formal;
end
if (rst_n_i && f_past_valid) begin
if ($past(
rst_n_i && nmi_valid && !nmi_ready && nmi_wstrb[0] &&
nmi_addr[7:0] == 8'h00 && nmi_wdata[4:0] < 6 && user_reset == 6'h3f && !user_bus_enable
)) begin
assert (core_sel == $past(nmi_wdata[4:0]));
end
if ($past(
rst_n_i && nmi_valid && !nmi_ready && nmi_wstrb[0] &&
nmi_addr[7:0] == 8'h00 && nmi_wdata[4:0] >= 6
)) begin
assert (core_sel == $past(core_sel));
assert (user_config_error);
end
if ($past(
rst_n_i && nmi_valid && !nmi_ready && nmi_wstrb[0] &&
nmi_addr[7:0] == SYSCTRL_USER_CORE_RESET_OFFSET &&
nmi_wdata[5:0] == 6'h3f
)) begin
assert (user_reset == 6'h3f);
assert (!user_bus_enable);
end
if ($past(
rst_n_i && nmi_valid && !nmi_ready && |nmi_wstrb &&
nmi_addr[7:0] == SYSCTRL_IPSEL_OFFSET
@@ -106,7 +134,7 @@ module sysctrl_formal;
if ($past(rst_n_i && fault_valid)) begin
assert (fault_pending);
assert (fault_write == (|$past(fault_wstrb)));
assert (fault_reason == ($past(fault_reserved) ? 2'd2 : 2'd1));
assert (fault_reason == ($past(fault_reserved) ? 3'd2 : 3'd1));
assert (fault_addr_q == $past(fault_addr));
if (!$past(&fault_count)) begin
assert (fault_count == $past(fault_count) + 32'd1);
+3 -3
View File
@@ -19,9 +19,9 @@ peripheral output path. Values are restricted to scalar signal references and
one-bit constants so malformed expressions are rejected before RTL generation.
The `apb_targets` list defines the stable APB response slot, timed/pure APB
interface names, and corresponding active APB address-map region. A target that
declares `requires_ip: "MDD"` is generated only for `IP=MDD`; its presence is
checked against the same condition in the canonical memory map.
interface names, and corresponding active APB address-map region. The user-IP
target is part of the fixed platform integration and its presence is checked
against the canonical memory map.
`irq_vector_width`, `irq_groups`, and `interrupts` define the complete core
interrupt topology. `nmi` and `apb` group entries declare the wrapper output
+26 -54
View File
@@ -16,7 +16,7 @@ from typing import Any
SV_IDENTIFIER_RE = re.compile(r"[A-Za-z_][A-Za-z0-9_]*$")
SV_REFERENCE_RE = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*(?:\[[0-9]+\])?$")
SV_CONSTANT_RE = re.compile(r"(?:1'[bB][01]|'[01])$")
FABRIC_LINK_NAMES = ("core", "dma", "native", "apb")
FABRIC_LINK_NAMES = ("mgmt", "user", "dma", "native", "apb")
IRQ_GROUP_NAMES = ("nmi", "apb")
IRQ_VECTOR_WIDTH = 32
COMPATIBILITY_IRQ_BINDINGS = (
@@ -56,7 +56,6 @@ class ApbTarget:
timed_interface: str
pure_interface: str
region: str
requires_ip: str | None
@dataclass(frozen=True)
@@ -174,14 +173,6 @@ def parse_regions(value: Any, field: str) -> tuple[str, ...]:
return regions
def parse_requires_ip(value: Any, field: str) -> str | None:
if value is None:
return None
if value != "MDD":
raise ValueError(f"{field} must be MDD when present")
return value
def parse_native_targets(
value: Any, memory_regions: dict[str, dict[str, Any]]
) -> list[NativeTarget]:
@@ -256,9 +247,7 @@ def parse_native_targets(
return ordered
def parse_apb_targets(
value: Any, memory_regions: dict[str, dict[str, Any]], ip: str
) -> list[ApbTarget]:
def parse_apb_targets(value: Any, memory_regions: dict[str, dict[str, Any]]) -> list[ApbTarget]:
if not isinstance(value, list) or not value:
raise ValueError("apb_targets must be a non-empty list")
targets: list[ApbTarget] = []
@@ -280,9 +269,6 @@ def parse_apb_targets(
target.get("pure_interface"), f"apb_targets[{index}].pure_interface"
)
region_name = require_identifier(target.get("region"), f"apb_targets[{index}].region")
requires_ip = parse_requires_ip(
target.get("requires_ip"), f"apb_targets[{index}].requires_ip"
)
region = memory_regions.get(region_name)
if region is None:
raise ValueError(f"apb_targets[{index}] references unknown region {region_name}")
@@ -290,10 +276,6 @@ def parse_apb_targets(
raise ValueError(
f"apb_targets[{index}] region {region_name} is not an active APB region"
)
if requires_ip != region.get("requires_ip"):
raise ValueError(
f"apb_targets[{index}] requires_ip does not match region {region_name}"
)
if name in names:
raise ValueError(f"APB target name {name} is duplicated")
if timed_interface in timed_interfaces:
@@ -309,22 +291,15 @@ def parse_apb_targets(
pure_interfaces.add(pure_interface)
regions.add(region_name)
slots.add(slot)
targets.append(
ApbTarget(slot, name, timed_interface, pure_interface, region_name, requires_ip)
)
targets.append(ApbTarget(slot, name, timed_interface, pure_interface, region_name))
enabled = [
target for target in targets if target.requires_ip is None or target.requires_ip == ip
]
ordered = sorted(enabled, key=lambda item: item.slot)
ordered = sorted(targets, key=lambda item: item.slot)
if [target.slot for target in ordered] != list(range(len(ordered))):
raise ValueError("enabled APB target slots must be contiguous from zero")
active_regions = {
symbol
for symbol, region in memory_regions.items()
if region.get("route") == "apb"
and region.get("kind") == "active"
and (region.get("requires_ip") is None or region.get("requires_ip") == ip)
if region.get("route") == "apb" and region.get("kind") == "active"
}
claimed_regions = {target.region for target in ordered}
if claimed_regions != active_regions:
@@ -419,9 +394,7 @@ def parse_irq_groups(value: Any) -> list[IrqGroup]:
width = group.get("width")
if not isinstance(width, int) or width <= 0:
raise ValueError(f"irq_groups[{index}].width must be a positive integer")
top_signal = require_identifier(
group.get("top_signal"), f"irq_groups[{index}].top_signal"
)
top_signal = require_identifier(group.get("top_signal"), f"irq_groups[{index}].top_signal")
if name not in IRQ_GROUP_NAMES:
raise ValueError(f"irq_groups[{index}].name is not a supported interrupt group")
if name in names:
@@ -437,9 +410,7 @@ def parse_irq_groups(value: Any) -> list[IrqGroup]:
return sorted(groups, key=lambda item: IRQ_GROUP_NAMES.index(item.name))
def parse_interrupts(
value: Any, groups: list[IrqGroup], vector_width: int
) -> list[Interrupt]:
def parse_interrupts(value: Any, groups: list[IrqGroup], vector_width: int) -> list[Interrupt]:
if not isinstance(value, list) or not value:
raise ValueError("interrupts must be a non-empty list")
group_widths = {group.name: group.width for group in groups}
@@ -506,13 +477,11 @@ def validate_compatibility_irq_bindings(interrupts: list[Interrupt]) -> None:
)
expected = (name, group, group_bit, core_bit, signal)
if actual != expected:
raise ValueError(
f"core interrupt bit {core_bit} must retain its compatibility binding"
)
raise ValueError(f"core interrupt bit {core_bit} must retain its compatibility binding")
def read_topology(
topology_path: Path, memory_map_path: Path, ip: str
topology_path: Path, memory_map_path: Path
) -> tuple[
list[NativeTarget],
list[ApbTarget],
@@ -537,7 +506,7 @@ def read_topology(
validate_compatibility_irq_bindings(interrupts)
return (
parse_native_targets(document.get("native_targets"), memory_regions),
parse_apb_targets(document.get("apb_targets"), memory_regions, ip),
parse_apb_targets(document.get("apb_targets"), memory_regions),
parse_fabric_links(document.get("fabric_links")),
parse_gpio_functions(document.get("gpio_alt_functions"), gpio_pins),
irq_vector_width,
@@ -736,7 +705,8 @@ def render_fabric_connection(links: list[FabricLink], name: str, port: str) -> s
def render_bus_fabric_connections(links: list[FabricLink]) -> str:
port_names = {
"core": "core_nmi",
"mgmt": "mgmt_nmi",
"user": "user_nmi",
"dma": "dma_nmi",
"native": "natv_nmi",
"apb": "apb_nmi",
@@ -829,8 +799,7 @@ def render_irq_sva(vector_width: int, groups: list[IrqGroup], interrupts: list[I
" input logic [`SOC_IRQ_VECTOR_WIDTH-1:0] irq_i,",
]
lines.extend(
f" input logic [`{irq_width_macro(group)}-1:0] {group.name}_irq_i,"
for group in groups
f" input logic [`{irq_width_macro(group)}-1:0] {group.name}_irq_i," for group in groups
)
lines[-1] = lines[-1].removesuffix(",")
lines.extend([");", ""])
@@ -852,7 +821,9 @@ def render_irq_sva(vector_width: int, groups: list[IrqGroup], interrupts: list[I
f" irq_i[{core_bit}] == 1'b0);",
]
)
lines.extend(["", "endmodule", "", "bind retrosoc soc_irq_topology_sva u_soc_irq_topology_sva ("])
lines.extend(
["", "endmodule", "", "bind retrosoc soc_irq_topology_sva u_soc_irq_topology_sva ("]
)
lines.extend(
[
" .clk_i(clk_i),",
@@ -867,7 +838,7 @@ def render_irq_sva(vector_width: int, groups: list[IrqGroup], interrupts: list[I
return "\n".join(lines) + "\n"
def generate(topology_path: Path, memory_map_path: Path, output_dir: Path, ip: str) -> None:
def generate(topology_path: Path, memory_map_path: Path, output_dir: Path) -> None:
(
targets,
apb_targets,
@@ -876,9 +847,7 @@ def generate(topology_path: Path, memory_map_path: Path, output_dir: Path, ip: s
irq_vector_width,
irq_groups,
interrupts,
) = read_topology(
topology_path, memory_map_path, ip
)
) = read_topology(topology_path, memory_map_path)
memory_regions = read_memory_regions(memory_map_path)
rtl_dir = output_dir / "rtl"
atomic_write(rtl_dir / "soc_nmi_interfaces.svh", render_nmi_interfaces(targets))
@@ -893,8 +862,12 @@ def generate(topology_path: Path, memory_map_path: Path, output_dir: Path, ip: s
atomic_write(rtl_dir / "soc_apb_response_mux.svh", render_apb_response_mux(apb_targets))
atomic_write(rtl_dir / "soc_fabric_interfaces.svh", render_fabric_interfaces(fabric_links))
atomic_write(
rtl_dir / "soc_core_wrapper_fabric.svh",
render_fabric_connection(fabric_links, "core", "nmi"),
rtl_dir / "soc_mgmt_core_wrapper_fabric.svh",
render_fabric_connection(fabric_links, "mgmt", "nmi"),
)
atomic_write(
rtl_dir / "soc_user_core_fabric.svh",
render_fabric_connection(fabric_links, "user", "nmi"),
)
atomic_write(rtl_dir / "soc_bus_fabric.svh", render_bus_fabric_connections(fabric_links))
atomic_write(
@@ -929,16 +902,15 @@ def main() -> int:
parser.add_argument("--map", required=True, type=Path)
parser.add_argument("--memory-map", required=True, type=Path)
parser.add_argument("--output-dir", type=Path)
parser.add_argument("--ip", choices=("NONE", "MDD"), default="NONE")
parser.add_argument("--check", action="store_true", help="validate only; write nothing")
arguments = parser.parse_args()
try:
if arguments.check:
read_topology(arguments.map, arguments.memory_map, arguments.ip)
read_topology(arguments.map, arguments.memory_map)
else:
if arguments.output_dir is None:
parser.error("--output-dir is required unless --check is used")
generate(arguments.map, arguments.memory_map, arguments.output_dir, arguments.ip)
generate(arguments.map, arguments.memory_map, arguments.output_dir)
except (OSError, ValueError, json.JSONDecodeError) as error:
parser.error(str(error))
return 0
@@ -65,7 +65,9 @@ def require_positive_integer(value: Any, field: str) -> int:
return value
def parse_targets(value: Any, field: str, selector_width: int) -> tuple[ExtensionTarget, ...]:
def parse_targets(
value: Any, field: str, selector_width: int, first_slot: int
) -> tuple[ExtensionTarget, ...]:
if not isinstance(value, list) or not value:
raise ValueError(f"{field} must be a non-empty list")
targets: list[ExtensionTarget] = []
@@ -74,7 +76,7 @@ def parse_targets(value: Any, field: str, selector_width: int) -> tuple[Extensio
for index, entry in enumerate(value):
target = require_object(entry, f"{field}[{index}]")
slot = target.get("slot")
if not isinstance(slot, int) or not 0 < slot < (1 << selector_width):
if not isinstance(slot, int) or not first_slot <= slot < (1 << selector_width):
raise ValueError(f"{field}[{index}].slot must be within the selector range")
module = require_identifier(target.get("module"), f"{field}[{index}].module")
instance = require_identifier(target.get("instance"), f"{field}[{index}].instance")
@@ -86,8 +88,8 @@ def parse_targets(value: Any, field: str, selector_width: int) -> tuple[Extensio
instances.add(instance)
targets.append(ExtensionTarget(slot, module, instance))
ordered = tuple(sorted(targets, key=lambda item: item.slot))
if [target.slot for target in ordered] != list(range(1, len(ordered) + 1)):
raise ValueError(f"{field} slots must be contiguous from one")
if [target.slot for target in ordered] != list(range(first_slot, first_slot + len(ordered))):
raise ValueError(f"{field} slots must be contiguous from {first_slot}")
return ordered
@@ -106,8 +108,8 @@ def read_extensions(path: Path) -> ExtensionMap:
core_selector_width,
ip_selector_width,
gpio_width,
parse_targets(document.get("core_targets"), "core_targets", core_selector_width),
parse_targets(document.get("ip_targets"), "ip_targets", ip_selector_width),
parse_targets(document.get("core_targets"), "core_targets", core_selector_width, 0),
parse_targets(document.get("ip_targets"), "ip_targets", ip_selector_width, 1),
)
@@ -159,7 +161,7 @@ def render_core_bindings(extensions: ExtensionMap) -> str:
[
f" {target.module} #({target.slot}) {target.instance} (",
" .clk_i (clk_i),",
" .rst_n_i(rst_n_i),",
f" .rst_n_i(rst_n_i && ~core_reset_i[{target.slot}]),",
f" .irq_i (s_user_{target.slot}_irq),",
f" .nmi (u_user_{target.slot}_nmi_if)",
" );",
@@ -169,6 +171,44 @@ def render_core_bindings(extensions: ExtensionMap) -> str:
return "\n".join(lines)
def render_config(extensions: ExtensionMap) -> str:
return "\n".join(
[
"// Generated by rtl/mini/integration/generate_user_extensions.py; do not edit.",
"`ifndef RETROSOC_USER_EXTENSIONS_CONFIG_SVH",
"`define RETROSOC_USER_EXTENSIONS_CONFIG_SVH",
"",
f"`define USER_CORESEL_WIDTH {extensions.core_selector_width}",
f"`define USER_CORE_COUNT {len(extensions.core_targets)}",
f"`define USER_IPSEL_WIDTH {extensions.ip_selector_width}",
f"`define USER_IP_COUNT {len(extensions.ip_targets)}",
f"`define USER_GPIO_NUM {extensions.gpio_width}",
"",
"`endif",
"",
]
)
def render_c_config(extensions: ExtensionMap) -> str:
return "\n".join(
[
"/* Generated by rtl/mini/integration/generate_user_extensions.py; do not edit. */",
"#ifndef RETROSOC_GENERATED_USER_EXTENSIONS_H",
"#define RETROSOC_GENERATED_USER_EXTENSIONS_H",
"",
"#include <stdint.h>",
"",
f"#define RS_SOC_USER_CORE_COUNT UINT32_C({len(extensions.core_targets)})",
f"#define RS_SOC_USER_CORESEL_WIDTH UINT32_C({extensions.core_selector_width})",
f"#define RS_SOC_USER_IP_COUNT UINT32_C({len(extensions.ip_targets)})",
"",
"#endif",
"",
]
)
def render_ip_bindings(extensions: ExtensionMap) -> str:
lines = ["// Generated by rtl/mini/integration/generate_user_extensions.py; do not edit."]
for target in extensions.ip_targets:
@@ -234,6 +274,11 @@ def generate(source: Path, output_dir: Path) -> None:
rtl_dir = output_dir / "rtl"
atomic_write(rtl_dir / "user_core_bindings.svh", render_core_bindings(extensions))
atomic_write(rtl_dir / "user_ip_bindings.svh", render_ip_bindings(extensions))
atomic_write(rtl_dir / "user_extensions_config.svh", render_config(extensions))
atomic_write(
output_dir / "include" / "retrosoc" / "generated" / "user_extensions.h",
render_c_config(extensions),
)
atomic_write(output_dir / "user_extensions.fl", f"+incdir+{rtl_dir}\n")
+3 -2
View File
@@ -46,7 +46,8 @@
{"slot": 17, "name": "i2c1", "interface": "u_i2c1_nmi_if", "regions": ["NMI_I2C1"]}
],
"fabric_links": [
{"name": "core", "interface": "u_core_nmi_if"},
{"name": "mgmt", "interface": "u_mgmt_nmi_if"},
{"name": "user", "interface": "u_user_nmi_if"},
{"name": "dma", "interface": "u_dma_nmi_if"},
{"name": "native", "interface": "u_nmi_nmi_if"},
{"name": "apb", "interface": "u_apb_nmi_if"}
@@ -61,7 +62,7 @@
{"slot": 6, "name": "wdg", "timed_interface": "u_wdg_apb_if", "pure_interface": "u_wdg_apb_pure_if", "region": "APB_WDG"},
{"slot": 7, "name": "crc", "timed_interface": "u_crc_apb_if", "pure_interface": "u_crc_apb_pure_if", "region": "APB_CRC"},
{"slot": 8, "name": "tmr", "timed_interface": "u_tmr_apb_if", "pure_interface": "u_tmr_apb_pure_if", "region": "APB_TMR"},
{"slot": 9, "name": "user_ip", "timed_interface": "u_user_ip_apb_if", "pure_interface": "u_user_ip_apb_pure_if", "region": "APB_USER_IP", "requires_ip": "MDD"}
{"slot": 9, "name": "user_ip", "timed_interface": "u_user_ip_apb_if", "pure_interface": "u_user_ip_apb_pure_if", "region": "APB_USER_IP"}
],
"gpio_alt_functions": [
{"pin": 0, "alt0": {"inputs": ["u_uart1_if.rx_i"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": ["u_ps2_if.ps2_clk_i"], "do": "1'b0", "oe": "1'b0"}},
+6 -6
View File
@@ -4,12 +4,12 @@
"ip_selector_width": 8,
"gpio_width": 32,
"core_targets": [
{"slot": 1, "module": "user_core_design_username1", "instance": "u_user_core_design_username1"},
{"slot": 2, "module": "user_core_design_username2", "instance": "u_user_core_design_username2"},
{"slot": 3, "module": "user_core_design_username3", "instance": "u_user_core_design_username3"},
{"slot": 4, "module": "user_core_design_username4", "instance": "u_user_core_design_username4"},
{"slot": 5, "module": "user_core_design_username5", "instance": "u_user_core_design_username5"},
{"slot": 6, "module": "user_core_design_username6", "instance": "u_user_core_design_username6"}
{"slot": 0, "module": "user_core_design_username1", "instance": "u_user_core_design_username1"},
{"slot": 1, "module": "user_core_design_username2", "instance": "u_user_core_design_username2"},
{"slot": 2, "module": "user_core_design_username3", "instance": "u_user_core_design_username3"},
{"slot": 3, "module": "user_core_design_username4", "instance": "u_user_core_design_username4"},
{"slot": 4, "module": "user_core_design_username5", "instance": "u_user_core_design_username5"},
{"slot": 5, "module": "user_core_design_username6", "instance": "u_user_core_design_username6"}
],
"ip_targets": [
{"slot": 1, "module": "user_ip_design_username1", "instance": "u_user_ip_design_username1"},
+8 -7
View File
@@ -6,7 +6,7 @@ FORMAL_SOLVER_DIR := $(FORMAL_DIR)/bin
FORMAL_SOLVER_WRAPPER := $(FORMAL_SOLVER_DIR)/bitwuzla
FORMAL_DEPTH ?= 20
FORMAL_TIMEOUT ?= 60
FORMAL_TARGETS := bus nmi2apb sysctrl pll_rcu gpio_mdd
FORMAL_TARGETS := bus nmi2apb sysctrl pll_rcu gpio_user
FORMAL_FILELIST_GENERATOR := $(RTL_PATH)/formal/generate_formal_filelist.py
FORMAL_SBY_GENERATOR := $(RTL_PATH)/formal/generate_sby_config.py
FORMAL_RESULT_GENERATOR := $(RTL_PATH)/formal/formal_results.py
@@ -18,8 +18,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
$(RTL_PATH)/formal/sysctrl_formal_props.v \
$(RTL_PATH)/formal/pll_rcu_formal.sv \
$(RTL_PATH)/formal/pll_rcu_formal_props.v \
$(RTL_PATH)/formal/gpio_mdd_formal.sv \
$(RTL_PATH)/formal/gpio_mdd_formal_props.v \
$(RTL_PATH)/formal/gpio_user_formal.sv \
$(RTL_PATH)/formal/gpio_user_formal_props.v \
$(RTL_PATH)/top/bus.sv \
$(ROOT_PATH)/rtl/ip/native/interconnect/nmi2apb.sv \
$(ROOT_PATH)/rtl/ip/native/interconnect/nmi_regslice.sv \
@@ -45,10 +45,11 @@ FORMAL_RESULT := $(META_DIR)/formal.json
.SECONDARY: $(FORMAL_INTERMEDIATES)
$(FORMAL_DIR)/%/formal.fl: $(FORMAL_FILELIST_GENERATOR) $(FORMAL_SOURCE_FILES) \
$(MEMORY_MAP_STAMP) $(SOC_TOPOLOGY_STAMP)
$(MEMORY_MAP_STAMP) $(SOC_TOPOLOGY_STAMP) $(USER_EXTENSIONS_STAMP)
@mkdir -p $(@D)
python3 $(FORMAL_FILELIST_GENERATOR) --target $* --output $@ \
--memory-map-dir $(MEMORY_MAP_DIR) --soc-topology-dir $(SOC_TOPOLOGY_DIR)
--memory-map-dir $(MEMORY_MAP_DIR) --soc-topology-dir $(SOC_TOPOLOGY_DIR) \
--user-extensions-dir $(USER_EXTENSIONS_DIR)
$(FORMAL_DIR)/%/design.v: $(FORMAL_DIR)/%/formal.fl $(RTL_PATH)/script/convt_sv2v.py \
$(RTL_PATH)/script/filelist.py
@@ -110,7 +111,7 @@ formal-sysctrl: $(FORMAL_DIR)/sysctrl/.stamp | manifest
formal-pll-rcu: $(FORMAL_DIR)/pll_rcu/.stamp | manifest
formal-gpio-mdd: $(FORMAL_DIR)/gpio_mdd/.stamp | manifest
formal-gpio-user: $(FORMAL_DIR)/gpio_user/.stamp | manifest
formal-doctor:
$(MAKE) FORMAL=YES SIMU=IVERILOG SYNTH=YOSYS STA=NONE doctor
@@ -118,4 +119,4 @@ formal-doctor:
formal-clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR)
.PHONY: formal formal-bus formal-nmi2apb formal-sysctrl formal-pll-rcu formal-gpio-mdd formal-doctor formal-clean
.PHONY: formal formal-bus formal-nmi2apb formal-sysctrl formal-pll-rcu formal-gpio-user formal-doctor formal-clean
+1 -1
View File
@@ -32,7 +32,7 @@ TECH_CELL_TEST_DIR := $(IVERILOG_ROOT)/tech-cells
IVERILOG_COMMON_OPTS := -g2012
IVERILOG_TIME_OPTS := -gno-specify
IVERILOG_POST_OPTS := -gspecify -Tmin
IVERILOG_SIM_OPTS := +core_sel=$(RTL_SIM_CORESEL) +sim_timeout=$(RTL_SIM_TIMEOUT) +wave_$(WAVE)
IVERILOG_SIM_OPTS := +sim_timeout=$(RTL_SIM_TIMEOUT) +wave_$(WAVE)
$(CONVERTED_SOC): $(MPW_VARIANT_STAMP) $(FILELIST_STAMP)
@mkdir -p $(@D)
+5 -6
View File
@@ -40,9 +40,8 @@ ISA_FLAGS += -march=rv32im
endif
endif
DEF_VAL += -DCORE_$(CORE)
DEF_VAL += -DIP_$(IP)
DEF_VAL += -DAPP_$(APP)
DEF_VAL += -DRS_SOC_MGMT_CORE_$(CORE)
DEF_VAL += -DCOMPILER_NAME='"$(CC)"'
DEF_VAL += -DCOMPILER_CFLAGS='"$(GCC_FLAGS) $(SW_WARN_FLAGS)"'
DEF_VAL += -DCOMPILER_ISA='"$(ISA_FLAGS)"'
@@ -83,7 +82,8 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
$(ROOT_PATH)/crt/src/hal/lcd.c \
$(ROOT_PATH)/crt/src/hal/psram.c \
$(ROOT_PATH)/crt/src/hal/spisd.c \
$(ROOT_PATH)/crt/src/hal/qspi.c
$(ROOT_PATH)/crt/src/hal/qspi.c \
$(ROOT_PATH)/crt/src/hal/user_core.c
ifeq ($(HAVE_CSR),YES)
CRT_SRCS += $(ROOT_PATH)/crt/arch/riscv/system_irq.S
@@ -100,9 +100,7 @@ $(error Application profile not found: $(APP_MK))
endif
include $(APP_MK)
ifneq ($(findstring MDD,$(CORE) $(IP)),)
APP_INC_DIRS += $(MPW_OUTPUT_DIR)
endif
ifneq ($(filter RV32E RV32I,$(ISA)),)
CRT_SRCS += $(ROOT_PATH)/crt/arch/riscv/libgcc/div.S
@@ -112,6 +110,7 @@ endif
INC_PATH := -I$(SW_BUILD_DIR)/include \
-I$(MEMORY_MAP_C_DIR) \
-I$(USER_EXTENSIONS_DIR)/include \
-I$(ROOT_PATH)/crt/include \
$(addprefix -I,$(APP_INC_DIRS))
SRC_PATH := $(CRT_SRCS) $(APP_SRCS)
@@ -138,7 +137,7 @@ asm: $(MPW_VARIANT_STAMP)
cp $(SW_BUILD_DIR)/asm/hello-asm.bin $(SW_BUILD_DIR)/$(ASM_FIRMWARE_NAME).bin
cp $(SW_BUILD_DIR)/asm/hello-asm.txt $(SW_BUILD_DIR)/$(ASM_FIRMWARE_NAME)_all.txt
$(FIRMWARE_ELF): $(MPW_VARIANT_STAMP) $(MEMORY_MAP_STAMP) $(VERSION_HEADER) $(SRC_PATH) $(SW_HEADERS) $(LDS_PATH) \
$(FIRMWARE_ELF): $(MPW_VARIANT_STAMP) $(MEMORY_MAP_STAMP) $(USER_EXTENSIONS_STAMP) $(VERSION_HEADER) $(SRC_PATH) $(SW_HEADERS) $(LDS_PATH) \
$(ROOT_PATH)/rtl/mini/mk/software.mk
@mkdir -p $(SW_BUILD_DIR)
cd $(SW_BUILD_DIR) && $(CP) -P -o $(LINK_TYPE).lds $(LDS_PATH)
+1 -1
View File
@@ -46,7 +46,7 @@ POST_OPTS := -sdf min:retrosoc_tb.u_retrosoc_asic:$(SDF_PATH) \
TIME_OPTION := +notimingcheck +nospecify
SIM_OPTS := +vcs+loopreport+1000 -suppress=ASLR_DETECTED_INFO \
+core_sel=$(RTL_SIM_CORESEL) +sim_timeout=$(RTL_SIM_TIMEOUT) +wave_$(WAVE)
+sim_timeout=$(RTL_SIM_TIMEOUT) +wave_$(WAVE)
VCS_BEHV_DIR := $(SIM_BUILD_ROOT)/behv
VCS_NETL_DIR := $(SIM_BUILD_ROOT)/netl
+1 -1
View File
@@ -97,7 +97,7 @@ sim: comp
python3 $(ROOT_PATH)/scripts/run_flow.py --tool verilator-sim \
--log $(BUILD_DIR)/sim.log --result $(BUILD_DIR)/result-sim.json \
--cwd $(BUILD_DIR) -- $(BUILD_DIR)/emu -i $(SW_BUILD_DIR)/$(SIM_FIRMWARE_NAME).bin \
-s $(RTL_SIM_CORESEL) -t $(SOC_SIM_TIME)
-t $(SOC_SIM_TIME)
python3 $(ROOT_PATH)/scripts/check_simulation.py --log $(BUILD_DIR)/sim.log \
--result $(BUILD_DIR)/result-sim-check.json --require '$(SIM_SUCCESS_MARKER)'
+6 -2
View File
@@ -13,7 +13,7 @@ from pathlib import Path
from typing import Any
VALID_FEATURES = {"HAVE_PLL", "CORE_MDD", "IP_MDD"}
VALID_FEATURES = {"HAVE_PLL"}
VALID_KINDS = {
"full",
"schmitt_input",
@@ -112,7 +112,11 @@ def parse_pad(entry: dict[str, Any], defaults: dict[str, Any], index: int | None
def expand_group(group: Any, index: int) -> list[Pad]:
if not isinstance(group, dict):
raise ValueError(f"pads[{index}] must be an object")
defaults = {key: value for key, value in group.items() if key not in {"ports", "count", "prefix", "suffix"}}
defaults = {
key: value
for key, value in group.items()
if key not in {"ports", "count", "prefix", "suffix"}
}
ports = group.get("ports")
if ports is not None:
if not isinstance(ports, list) or not ports:
-24
View File
@@ -24,15 +24,6 @@
{"name": "xo_o_pad", "direction": "output", "bind": false}
]
},
{
"kind": "tri_input",
"direction": "inout",
"feature": "CORE_MDD",
"prefix": "core_sel_",
"suffix": "_i_pad",
"count": 5,
"signal": "s_core_sel[{index}]"
},
{
"kind": "full",
"direction": "inout",
@@ -128,11 +119,6 @@
"audclk_i_pad": "s_aud_clk",
"ext_rst_n_i_pad": "rst_n_i",
"xi_i_pad": "s_sys_clk",
"core_sel_0_i_pad": "1'b0",
"core_sel_1_i_pad": "1'b0",
"core_sel_2_i_pad": "1'b0",
"core_sel_3_i_pad": "1'b0",
"core_sel_4_i_pad": "1'b0",
"gpio_0_io_pad": "ps2_clk_i",
"gpio_1_io_pad": "ps2_dat_i",
"gpio_2_io_pad": "onewire_dat_o",
@@ -208,11 +194,6 @@
"bindings": {
"extclk_i_pad": "s_clk",
"ext_rst_n_i_pad": "s_rst_n",
"core_sel_0_i_pad": "s_core_sel[0]",
"core_sel_1_i_pad": "s_core_sel[1]",
"core_sel_2_i_pad": "s_core_sel[2]",
"core_sel_3_i_pad": "s_core_sel[3]",
"core_sel_4_i_pad": "s_core_sel[4]",
"gpio_21_io_pad": "s_psram_sck",
"gpio_22_io_pad": "s_psram_nss0",
"gpio_23_io_pad": "s_psram_dat0",
@@ -233,11 +214,6 @@
"audclk_i_pad": "s_aud_clk",
"ext_rst_n_i_pad": "s_rst_n",
"xi_i_pad": "r_xtal_clk",
"core_sel_0_i_pad": "s_core_sel[0]",
"core_sel_1_i_pad": "s_core_sel[1]",
"core_sel_2_i_pad": "s_core_sel[2]",
"core_sel_3_i_pad": "s_core_sel[3]",
"core_sel_4_i_pad": "s_core_sel[4]",
"gpio_0_io_pad": "s_gpio_0_io",
"gpio_1_io_pad": "s_gpio_1_io",
"gpio_7_io_pad": "s_i2c0_scl_io",
+119 -50
View File
@@ -5,7 +5,7 @@
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "mmap_define.svh"
@@ -17,41 +17,89 @@ module bus (
`ifdef HAVE_SRAM_IF
ram_if.master ram,
`endif
nmi_if.slave core_nmi,
nmi_if.slave mgmt_nmi,
nmi_if.slave user_nmi,
nmi_if.slave dma_nmi,
input logic user_bus_enable_i,
output logic user_bus_idle_o,
nmi_if.master natv_nmi,
nmi_if.master apb_nmi,
output logic fault_valid_o,
output logic [31:0] fault_addr_o,
output logic [3:0] fault_wstrb_o,
output logic fault_reserved_o
output logic fault_reserved_o,
output logic fault_access_o,
output logic [1:0] fault_master_o
// verilog_format: on
);
logic s_natv_sel, s_apb_sel, s_ram_sel, s_fault_sel;
localparam logic [1:0] MSTR_MGMT = 2'd0;
localparam logic [1:0] MSTR_USER = 2'd1;
localparam logic [1:0] MSTR_DMA = 2'd2;
logic s_natv_sel, s_apb_sel, s_ram_sel, s_fault_sel, s_access_denied;
logic s_ram_valid, s_ram_ready;
logic s_mstr_lock_d, s_mstr_lock_q;
logic s_mstr_id_d, s_mstr_id_q;
logic [1:0] s_mstr_id_d, s_mstr_id_q;
logic [1:0] s_mstr_rr_d, s_mstr_rr_q;
logic s_user_request;
logic s_user_access_allowed;
nmi_if u_mstr_nmi_if ();
nmi_if u_mstr_rgsl_nmi_if ();
assign s_user_request = user_bus_enable_i && user_nmi.valid;
assign user_bus_idle_o = ~s_mstr_lock_q || s_mstr_id_q != MSTR_USER;
always_comb begin
s_mstr_lock_d = s_mstr_lock_q;
s_mstr_id_d = s_mstr_id_q;
s_mstr_rr_d = s_mstr_rr_q;
if (~s_mstr_lock_q) begin
if (core_nmi.valid && ~dma_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = 1'b0;
end else if (dma_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = 1'b1;
end
end else begin
if (~s_mstr_id_q && core_nmi.ready) begin
s_mstr_lock_d = 1'b0;
end else if (s_mstr_id_q && dma_nmi.ready) begin
s_mstr_lock_d = 1'b0;
end
unique case (s_mstr_rr_q)
MSTR_MGMT: begin
if (mgmt_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_MGMT;
end else if (s_user_request) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_USER;
end else if (dma_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_DMA;
end
end
MSTR_USER: begin
if (s_user_request) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_USER;
end else if (dma_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_DMA;
end else if (mgmt_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_MGMT;
end
end
default: begin
if (dma_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_DMA;
end else if (mgmt_nmi.valid) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_MGMT;
end else if (s_user_request) begin
s_mstr_lock_d = 1'b1;
s_mstr_id_d = MSTR_USER;
end
end
endcase
end else if (u_mstr_nmi_if.ready) begin
s_mstr_lock_d = 1'b0;
unique case (s_mstr_id_q)
MSTR_MGMT: s_mstr_rr_d = MSTR_USER;
MSTR_USER: s_mstr_rr_d = MSTR_DMA;
default: s_mstr_rr_d = MSTR_MGMT;
endcase
end
end
dffr #(1) u_mstr_lock_dffr (
@@ -60,50 +108,69 @@ module bus (
s_mstr_lock_d,
s_mstr_lock_q
);
dffr #(1) u_mstr_id_dffr (
dffr #(2) u_mstr_id_dffr (
clk_i,
rst_n_i,
s_mstr_id_d,
s_mstr_id_q
);
// simple arbiter
// verilog_format: off
assign u_mstr_nmi_if.valid = s_mstr_id_q ? dma_nmi.valid : core_nmi.valid;
assign u_mstr_nmi_if.addr = s_mstr_id_q ? dma_nmi.addr : core_nmi.addr;
assign u_mstr_nmi_if.wdata = s_mstr_id_q ? dma_nmi.wdata : core_nmi.wdata;
assign u_mstr_nmi_if.wstrb = s_mstr_id_q ? dma_nmi.wstrb : core_nmi.wstrb;
assign dma_nmi.ready = s_mstr_id_q ? u_mstr_nmi_if.ready : '0;
assign dma_nmi.rdata = s_mstr_id_q ? u_mstr_nmi_if.rdata : '0;
assign core_nmi.ready = ~s_mstr_id_q ? u_mstr_nmi_if.ready : '0;
assign core_nmi.rdata = ~s_mstr_id_q ? u_mstr_nmi_if.rdata : '0;
// verilog_format: on
// regslice to opt the timing
nmi_regslice u_nmi_regslice (
dffr #(2) u_mstr_rr_dffr (
clk_i,
rst_n_i,
u_mstr_nmi_if,
u_mstr_rgsl_nmi_if
s_mstr_rr_d,
s_mstr_rr_q
);
// bus mux — address ownership comes from the generated address map.
// The owner is locked from request acceptance through its response.
// verilog_format: off
assign s_natv_sel = `SOC_ADDR_IS_NATIVE(u_mstr_rgsl_nmi_if.addr);
assign u_mstr_nmi_if.valid = s_mstr_lock_q && (s_mstr_id_q == MSTR_MGMT ? mgmt_nmi.valid :
s_mstr_id_q == MSTR_USER ? user_nmi.valid :
dma_nmi.valid);
assign u_mstr_nmi_if.addr = s_mstr_id_q == MSTR_MGMT ? mgmt_nmi.addr :
s_mstr_id_q == MSTR_USER ? user_nmi.addr : dma_nmi.addr;
assign u_mstr_nmi_if.wdata = s_mstr_id_q == MSTR_MGMT ? mgmt_nmi.wdata :
s_mstr_id_q == MSTR_USER ? user_nmi.wdata : dma_nmi.wdata;
assign u_mstr_nmi_if.wstrb = s_mstr_id_q == MSTR_MGMT ? mgmt_nmi.wstrb :
s_mstr_id_q == MSTR_USER ? user_nmi.wstrb : dma_nmi.wstrb;
assign mgmt_nmi.ready = s_mstr_lock_q && s_mstr_id_q == MSTR_MGMT ? u_mstr_nmi_if.ready : '0;
assign mgmt_nmi.rdata = s_mstr_lock_q && s_mstr_id_q == MSTR_MGMT ? u_mstr_nmi_if.rdata : '0;
assign user_nmi.ready = s_mstr_lock_q && s_mstr_id_q == MSTR_USER ? u_mstr_nmi_if.ready : '0;
assign user_nmi.rdata = s_mstr_lock_q && s_mstr_id_q == MSTR_USER ? u_mstr_nmi_if.rdata : '0;
assign dma_nmi.ready = s_mstr_lock_q && s_mstr_id_q == MSTR_DMA ? u_mstr_nmi_if.ready : '0;
assign dma_nmi.rdata = s_mstr_lock_q && s_mstr_id_q == MSTR_DMA ? u_mstr_nmi_if.rdata : '0;
// verilog_format: on
nmi_regslice u_nmi_regslice (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.nmi_slv(u_mstr_nmi_if),
.nmi_mst(u_mstr_rgsl_nmi_if)
);
assign s_user_access_allowed = |u_mstr_rgsl_nmi_if.wstrb ?
`SOC_USER_ADDR_WRITABLE(u_mstr_rgsl_nmi_if.addr) :
`SOC_USER_ADDR_READABLE(u_mstr_rgsl_nmi_if.addr);
assign s_access_denied = u_mstr_rgsl_nmi_if.valid && s_mstr_id_q == MSTR_USER &&
~s_user_access_allowed;
// Address ownership comes from the generated address map. User requests are
// filtered before any target observes valid.
// verilog_format: off
assign s_natv_sel = `SOC_ADDR_IS_NATIVE(u_mstr_rgsl_nmi_if.addr) && ~s_access_denied;
assign natv_nmi.valid = u_mstr_rgsl_nmi_if.valid && s_natv_sel;
assign natv_nmi.addr = u_mstr_rgsl_nmi_if.addr;
assign natv_nmi.wdata = u_mstr_rgsl_nmi_if.wdata;
assign natv_nmi.wstrb = u_mstr_rgsl_nmi_if.wstrb;
assign s_apb_sel = `SOC_ADDR_IS_APB(u_mstr_rgsl_nmi_if.addr);
assign s_apb_sel = `SOC_ADDR_IS_APB(u_mstr_rgsl_nmi_if.addr) && ~s_access_denied;
assign apb_nmi.valid = u_mstr_rgsl_nmi_if.valid && s_apb_sel;
assign apb_nmi.addr = u_mstr_rgsl_nmi_if.addr;
assign apb_nmi.wdata = u_mstr_rgsl_nmi_if.wdata;
assign apb_nmi.wstrb = u_mstr_rgsl_nmi_if.wstrb;
`ifdef HAVE_SRAM_IF
assign s_ram_sel = `SOC_ADDR_IS_RAM(u_mstr_rgsl_nmi_if.addr);
assign s_ram_sel = `SOC_ADDR_IS_RAM(u_mstr_rgsl_nmi_if.addr) && ~s_access_denied;
assign s_ram_valid = u_mstr_rgsl_nmi_if.valid && s_ram_sel;
assign ram.addr = u_mstr_rgsl_nmi_if.addr[16:2];
assign ram.wdata = u_mstr_rgsl_nmi_if.wdata;
@@ -113,11 +180,13 @@ module bus (
`endif
assign s_fault_sel = u_mstr_rgsl_nmi_if.valid &&
~(s_natv_sel || s_apb_sel || s_ram_sel);
(s_access_denied || ~(s_natv_sel || s_apb_sel || s_ram_sel));
assign fault_valid_o = s_fault_sel;
assign fault_addr_o = u_mstr_rgsl_nmi_if.addr;
assign fault_wstrb_o = u_mstr_rgsl_nmi_if.wstrb;
assign fault_reserved_o = `SOC_ADDR_IS_RESERVED(u_mstr_rgsl_nmi_if.addr);
assign fault_access_o = s_access_denied;
assign fault_master_o = s_mstr_id_q;
// verilog_format: on
`ifdef HAVE_SRAM_MACRO
@@ -131,23 +200,23 @@ module bus (
// verilog_format: off
`ifdef HAVE_SRAM_IF
assign u_mstr_rgsl_nmi_if.ready = (natv_nmi.valid && natv_nmi.ready) ||
(apb_nmi.valid && apb_nmi.ready) ||
s_ram_ready || s_fault_sel;
assign u_mstr_rgsl_nmi_if.ready = s_access_denied || (natv_nmi.valid && natv_nmi.ready) ||
(apb_nmi.valid && apb_nmi.ready) || s_ram_ready || s_fault_sel;
`else
assign u_mstr_rgsl_nmi_if.ready = (natv_nmi.valid && natv_nmi.ready) ||
assign u_mstr_rgsl_nmi_if.ready = s_access_denied || (natv_nmi.valid && natv_nmi.ready) ||
(apb_nmi.valid && apb_nmi.ready) || s_fault_sel;
`endif
`ifdef HAVE_SRAM_IF
assign u_mstr_rgsl_nmi_if.rdata = (natv_nmi.valid && natv_nmi.ready) ? natv_nmi.rdata :
assign u_mstr_rgsl_nmi_if.rdata = s_access_denied ? '0 :
(natv_nmi.valid && natv_nmi.ready) ? natv_nmi.rdata :
(apb_nmi.valid && apb_nmi.ready) ? apb_nmi.rdata :
s_ram_ready ? ram.rdata : '0;
`else
assign u_mstr_rgsl_nmi_if.rdata = (natv_nmi.valid && natv_nmi.ready) ? natv_nmi.rdata :
assign u_mstr_rgsl_nmi_if.rdata = s_access_denied ? '0 :
(natv_nmi.valid && natv_nmi.ready) ? natv_nmi.rdata :
(apb_nmi.valid && apb_nmi.ready) ? apb_nmi.rdata : '0;
`endif
// verilog_format: on
endmodule
+6 -177
View File
@@ -5,194 +5,23 @@
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "mmap_define.svh"
`include "mdd_config.svh"
module core_wrapper (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic [31:0] irq_i,
`ifdef CORE_MDD
input logic [`USER_CORESEL_WIDTH-1:0] core_sel_i,
`endif
nmi_if.master nmi
input logic clk_i,
input logic rst_n_i,
input logic [31:0] irq_i,
nmi_if.master nmi
// verilog_format: on
);
`ifdef CORE_PICORV32
picorv32 #(
.BARREL_SHIFTER (1),
.COMPRESSED_ISA (1),
.ENABLE_MUL (1),
.ENABLE_FAST_MUL(1),
.ENABLE_DIV (1),
.ENABLE_IRQ (0),
.PROGADDR_RESET (`SOC_CPU_RESET_ADDR),
.PROGADDR_IRQ (`SOC_IRQ_START_ADDR)
) u_picorv32 (
.clk (clk_i),
.resetn (rst_n_i),
.trap (),
.mem_valid (nmi.valid),
.mem_instr (),
.mem_addr (nmi.addr),
.mem_wdata (nmi.wdata),
.mem_wstrb (nmi.wstrb),
.mem_rdata (nmi.rdata),
.mem_ready (nmi.ready),
.mem_la_read (),
.mem_la_write(),
.mem_la_addr (),
.mem_la_wdata(),
.mem_la_wstrb(),
.pcpi_valid (),
.pcpi_insn (),
.pcpi_rs1 (),
.pcpi_rs2 (),
.pcpi_wr (),
.pcpi_rd (),
.pcpi_wait (),
.pcpi_ready (),
.irq (irq_i),
.eoi (),
.trace_valid (),
.trace_data ()
);
`elsif CORE_HAZARD3
logic s_pwrup_req;
// verilog_format: off
ahbl_if u_ahbl_if (clk_i, rst_n_i);
ahbl2nmi u_ahbl2nmi (u_ahbl_if, nmi);
// verilog_format: on
hazard3_cpu_1port #(
.RESET_VECTOR (`SOC_CPU_RESET_ADDR),
.MTVEC_INIT (32'h0000_0000),
.EXTENSION_A (1),
.EXTENSION_C (1),
.EXTENSION_E (0),
.EXTENSION_M (1),
.EXTENSION_ZBA (1),
.EXTENSION_ZBB (1),
.EXTENSION_ZBC (1),
.EXTENSION_ZBKB (1),
.EXTENSION_ZBKX (1),
.EXTENSION_ZBS (1),
.EXTENSION_ZCB (0),
.EXTENSION_ZCLSD (0),
.EXTENSION_ZCMP (0),
.EXTENSION_ZIFENCEI (1),
.EXTENSION_ZILSD (1),
.EXTENSION_XH3BEXTM (1),
.EXTENSION_XH3IRQ (1),
.EXTENSION_XH3PMPM (0),
.EXTENSION_XH3POWER (0),
.CSR_M_MANDATORY (1),
.CSR_M_TRAP (1),
.CSR_COUNTER (1),
.U_MODE (0),
.PMP_REGIONS (0),
.PMP_GRAIN (0),
.PMP_MATCH_NAPOT (1),
.PMP_MATCH_TOR (0),
.PMP_HARDWIRED (0),
.PMP_HARDWIRED_ADDR (0),
.PMP_HARDWIRED_CFG (0),
.DEBUG_SUPPORT (0),
.BREAKPOINT_TRIGGERS(0),
.NUM_IRQS (30),
.IRQ_PRIORITY_BITS (2),
.IRQ_INPUT_BYPASS (30'h0),
.MVENDORID_VAL (32'h0),
.MCONFIGPTR_VAL (32'h0),
.REDUCED_BYPASS (0),
.MULDIV_UNROLL (1),
.MUL_FAST (1),
.MUL_FASTER (1),
.MULH_FAST (1),
.FAST_BRANCHCMP (1),
.RESET_REGFILE (1),
.BRANCH_PREDICTOR (0),
.MTVEC_WMASK (32'hfffffffd)
) u_hazard3_cpu_1port (
// Global signals
.clk (clk_i),
.clk_always_on (clk_i),
.rst_n (rst_n_i),
// Power control signals
.pwrup_req (s_pwrup_req),
.pwrup_ack (s_pwrup_req), // tied back
.clk_en (),
.unblock_out (),
.unblock_in (1'b0),
// AHB5 Master port
.haddr (u_ahbl_if.haddr),
.hwrite (u_ahbl_if.hwrite),
.htrans (u_ahbl_if.htrans),
.hsize (u_ahbl_if.hsize),
.hburst (u_ahbl_if.hburst),
.hprot (u_ahbl_if.hprot),
.hmastlock (u_ahbl_if.hmastlock),
.hmaster (),
.hexcl (),
.hready (u_ahbl_if.hready),
.hresp (u_ahbl_if.hresp),
.hexokay (1'b1),
.hwdata (u_ahbl_if.hwdata),
.hrdata (u_ahbl_if.hrdata),
// Memory ordering signals
.fence_i_vld (),
.fence_d_vld (),
.fence_rdy (1'b1),
// Debugger run/halt control
.dbg_req_halt (1'b0),
.dbg_req_halt_on_reset (1'b0),
.dbg_req_resume (1'b0),
.dbg_halted (),
.dbg_running (),
// Debugger access to data0 CSR
.dbg_data0_rdata ('0),
.dbg_data0_wdata (),
.dbg_data0_wen (),
// Debugger instruction injection
.dbg_instr_data ('0),
.dbg_instr_data_vld ('0),
.dbg_instr_data_rdy (),
.dbg_instr_caught_exception(),
.dbg_instr_caught_ebreak (),
// Optional debug system bus access patch-through
.dbg_sbus_addr ('0),
.dbg_sbus_write ('0),
.dbg_sbus_size ('0),
.dbg_sbus_vld ('0),
.dbg_sbus_rdy (),
.dbg_sbus_err (),
.dbg_sbus_wdata ('0),
.dbg_sbus_rdata (),
// Identification CSR values
.mhartid_val ('0),
.eco_version ('0),
// Level-sensitive interrupt sources
.irq (irq_i[31:2]),
.soft_irq (irq_i[0]),
.timer_irq (irq_i[1])
);
`elsif CORE_MDD
user_core_wrapper u_user_core_wrapper (
mgmt_core_wrapper u_mgmt_core_wrapper (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.irq_i (irq_i),
.sel_i (core_sel_i),
.nmi (nmi)
);
`endif
endmodule
+1 -5
View File
@@ -12,7 +12,7 @@
`include "uart_define.svh"
`include "pwm_define.svh"
`include "ps2_define.svh"
`include "mdd_config.svh"
`include "user_extensions.svh"
`include "soc_irq_config.svh"
module ip_apb_wrapper (
@@ -26,10 +26,8 @@ module ip_apb_wrapper (
uart_if.dut uart,
pwm_if.dut pwm,
ps2_if.dut ps2,
`ifdef IP_MDD
input logic [`USER_IPSEL_WIDTH-1:0] ip_sel_i,
user_gpio_if.user_ip user_gpio,
`endif
output logic [`SOC_IRQ_APB_WIDTH-1:0] irq_o
// verilog_format: on
);
@@ -71,7 +69,6 @@ nmi2apb u_nmi2apb (
`include "soc_apb_connections.svh"
);
`ifdef IP_MDD
user_ip_wrapper u_user_ip_wrapper (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
@@ -79,6 +76,5 @@ nmi2apb u_nmi2apb (
.gpio (user_gpio),
.apb (u_user_ip_apb_if)
);
`endif
endmodule
+115
View File
@@ -19,6 +19,7 @@ module mgmt_core_wrapper (
// verilog_format: on
);
`ifdef CORE_PICORV32
picorv32 #(
.BARREL_SHIFTER (1),
.COMPRESSED_ISA (1),
@@ -57,4 +58,118 @@ module mgmt_core_wrapper (
.trace_valid (),
.trace_data ()
);
`elsif CORE_HAZARD3
logic s_pwrup_req;
// verilog_format: off
ahbl_if u_ahbl_if (clk_i, rst_n_i);
ahbl2nmi u_ahbl2nmi (u_ahbl_if, nmi);
// verilog_format: on
hazard3_cpu_1port #(
.RESET_VECTOR (`SOC_CPU_RESET_ADDR),
.MTVEC_INIT (32'h0000_0000),
.EXTENSION_A (1),
.EXTENSION_C (1),
.EXTENSION_E (0),
.EXTENSION_M (1),
.EXTENSION_ZBA (1),
.EXTENSION_ZBB (1),
.EXTENSION_ZBC (1),
.EXTENSION_ZBKB (1),
.EXTENSION_ZBKX (1),
.EXTENSION_ZBS (1),
.EXTENSION_ZCB (0),
.EXTENSION_ZCLSD (0),
.EXTENSION_ZCMP (0),
.EXTENSION_ZIFENCEI (1),
.EXTENSION_ZILSD (1),
.EXTENSION_XH3BEXTM (1),
.EXTENSION_XH3IRQ (1),
.EXTENSION_XH3PMPM (0),
.EXTENSION_XH3POWER (0),
.CSR_M_MANDATORY (1),
.CSR_M_TRAP (1),
.CSR_COUNTER (1),
.U_MODE (0),
.PMP_REGIONS (0),
.PMP_GRAIN (0),
.PMP_MATCH_NAPOT (1),
.PMP_MATCH_TOR (0),
.PMP_HARDWIRED (0),
.PMP_HARDWIRED_ADDR (0),
.PMP_HARDWIRED_CFG (0),
.DEBUG_SUPPORT (0),
.BREAKPOINT_TRIGGERS(0),
.NUM_IRQS (30),
.IRQ_PRIORITY_BITS (2),
.IRQ_INPUT_BYPASS (30'h0),
.MVENDORID_VAL (32'h0),
.MCONFIGPTR_VAL (32'h0),
.REDUCED_BYPASS (0),
.MULDIV_UNROLL (1),
.MUL_FAST (1),
.MUL_FASTER (1),
.MULH_FAST (1),
.FAST_BRANCHCMP (1),
.RESET_REGFILE (1),
.BRANCH_PREDICTOR (0),
.MTVEC_WMASK (32'hfffffffd)
) u_hazard3_cpu_1port (
.clk (clk_i),
.clk_always_on (clk_i),
.rst_n (rst_n_i),
.pwrup_req (s_pwrup_req),
.pwrup_ack (s_pwrup_req),
.clk_en (),
.unblock_out (),
.unblock_in (1'b0),
.haddr (u_ahbl_if.haddr),
.hwrite (u_ahbl_if.hwrite),
.htrans (u_ahbl_if.htrans),
.hsize (u_ahbl_if.hsize),
.hburst (u_ahbl_if.hburst),
.hprot (u_ahbl_if.hprot),
.hmastlock (u_ahbl_if.hmastlock),
.hmaster (),
.hexcl (),
.hready (u_ahbl_if.hready),
.hresp (u_ahbl_if.hresp),
.hexokay (1'b1),
.hwdata (u_ahbl_if.hwdata),
.hrdata (u_ahbl_if.hrdata),
.fence_i_vld (),
.fence_d_vld (),
.fence_rdy (1'b1),
.dbg_req_halt (1'b0),
.dbg_req_halt_on_reset (1'b0),
.dbg_req_resume (1'b0),
.dbg_halted (),
.dbg_running (),
.dbg_data0_rdata ('0),
.dbg_data0_wdata (),
.dbg_data0_wen (),
.dbg_instr_data ('0),
.dbg_instr_data_vld ('0),
.dbg_instr_data_rdy (),
.dbg_instr_caught_exception(),
.dbg_instr_caught_ebreak (),
.dbg_sbus_addr ('0),
.dbg_sbus_write ('0),
.dbg_sbus_size ('0),
.dbg_sbus_vld ('0),
.dbg_sbus_rdy (),
.dbg_sbus_err (),
.dbg_sbus_wdata ('0),
.dbg_sbus_rdata (),
.mhartid_val ('0),
.eco_version ('0),
.irq (irq_i[31:2]),
.soft_irq (irq_i[0]),
.timer_irq (irq_i[1])
);
`else
initial begin
$error("exactly one management core macro must be defined");
end
`endif
endmodule
+32 -31
View File
@@ -9,7 +9,7 @@
// See the Mulan PSL v2 for more details.
`include "mmap_define.svh"
`include "mdd_config.svh"
`include "user_extensions.svh"
`include "soc_irq_config.svh"
module retrosoc (
@@ -20,9 +20,6 @@ module retrosoc (
input logic rst_aud_n_i,
input logic clkdiv4_i,
pll_ctrl_if.sysctrl pll_ctrl,
`ifdef CORE_MDD
input logic [`USER_CORESEL_WIDTH-1:0] core_sel_i,
`endif
`ifdef HAVE_SRAM_IF
ram_if.master ram,
`endif
@@ -62,23 +59,18 @@ module retrosoc (
logic [ 31:0] s_bus_fault_addr;
logic [ 3:0] s_bus_fault_wstrb;
logic s_bus_fault_reserved;
logic s_bus_fault_access;
logic [ 1:0] s_bus_fault_master;
logic [`SOC_IRQ_VECTOR_WIDTH-1:0] s_user_irq;
assign u_sysctrl_if.fault_access_i = s_bus_fault_access;
assign u_sysctrl_if.fault_master_i = s_bus_fault_master;
gpio_pad_bridge u_gpio_pad_bridge (
.inner(u_gpio_if),
.outer(gpio)
);
`ifndef IP_MDD
assign u_user_gpio_if.do_o = '0;
assign u_user_gpio_if.oe_o = '0;
`endif
`ifdef CORE_MDD
assign u_sysctrl_if.core_sel_i = core_sel_i;
`else
assign u_sysctrl_if.core_sel_i = '0;
`endif
// Generated IRQ vector wiring defaults all unallocated core IRQ bits low.
`include "soc_irq_wiring.svh"
@@ -86,26 +78,37 @@ module retrosoc (
`include "soc_gpio_alt_bindings.svh"
core_wrapper u_core_wrapper (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
`ifdef CORE_MDD
.core_sel_i(core_sel_i),
`endif
`include "soc_core_wrapper_fabric.svh"
.irq_i (s_irq)
.clk_i (clk_i),
.rst_n_i(rst_n_i),
`include "soc_mgmt_core_wrapper_fabric.svh"
.irq_i (s_irq)
);
assign s_user_irq = u_sysctrl_if.user_bus_enable_o ? s_irq : '0;
user_core_top u_user_core_top (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.irq_i (s_user_irq),
.sel_i (u_sysctrl_if.core_sel_o),
`include "soc_user_core_fabric.svh"
.core_reset_i(u_sysctrl_if.core_reset_o)
);
bus u_bus (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clk_i (clk_i),
.rst_n_i (rst_n_i),
`ifdef HAVE_SRAM_IF
.ram (ram),
.ram (ram),
`endif
.user_bus_enable_i(u_sysctrl_if.user_bus_enable_o),
.user_bus_idle_o (u_sysctrl_if.user_bus_idle_i),
`include "soc_bus_fabric.svh"
.fault_valid_o (s_bus_fault_valid),
.fault_addr_o (s_bus_fault_addr),
.fault_wstrb_o (s_bus_fault_wstrb),
.fault_reserved_o(s_bus_fault_reserved)
.fault_valid_o (s_bus_fault_valid),
.fault_addr_o (s_bus_fault_addr),
.fault_wstrb_o (s_bus_fault_wstrb),
.fault_reserved_o (s_bus_fault_reserved),
.fault_access_o (s_bus_fault_access),
.fault_master_o (s_bus_fault_master)
);
ip_nmi_wrapper u_ip_nmi_wrapper (
@@ -147,10 +150,8 @@ core_wrapper u_core_wrapper (
.uart (u_uart1_if),
.pwm (u_pwm_if),
.ps2 (u_ps2_if),
`ifdef IP_MDD
.ip_sel_i (u_sysctrl_if.ip_sel_o),
.user_gpio (u_user_gpio_if),
`endif
.irq_o (s_apb_irq)
);
+1 -8
View File
@@ -9,7 +9,7 @@
// See the Mulan PSL v2 for more details.
`include "gpio_define.svh"
`include "mdd_config.svh"
`include "user_extensions.svh"
module retrosoc_asic (
`include "retrosoc_asic_ports.svh"
@@ -25,10 +25,6 @@ module retrosoc_asic (
logic s_sys_rst_n;
logic s_aud_rst_n;
`ifdef CORE_MDD
logic [`USER_CORESEL_WIDTH-1:0] s_core_sel;
`endif
`ifdef HAVE_SRAM_IF
ram_if u_ram_if ();
`endif
@@ -69,9 +65,6 @@ rcu u_rcu (
.rst_aud_n_i(s_aud_rst_n),
.clkdiv4_i (s_sys_clkdiv4),
.pll_ctrl (u_pll_ctrl_if),
`ifdef CORE_MDD
.core_sel_i (s_core_sel),
`endif
`ifdef HAVE_SRAM_IF
.ram (u_ram_if),
`endif
+2 -1
View File
@@ -8,7 +8,7 @@
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "mdd_config.svh"
`include "user_extensions.svh"
module user_core_top (
// verilog_format: off
@@ -16,6 +16,7 @@ module user_core_top (
input logic rst_n_i,
input logic [ 31:0] irq_i,
input logic [`USER_CORESEL_WIDTH-1:0] sel_i,
input logic [`USER_CORE_COUNT-1:0] core_reset_i,
nmi_if.master nmi
// verilog_format: on
);
-56
View File
@@ -1,56 +0,0 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "mdd_config.svh"
module user_core_wrapper (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic [ 31:0] irq_i,
input logic [`USER_CORESEL_WIDTH-1:0] sel_i,
nmi_if.master nmi
// verilog_format: on
);
nmi_if u_mgmt_nmi_if ();
nmi_if u_user_nmi_if ();
logic [31:0] s_mgmt_irq, s_user_irq;
assign nmi.valid = ~(|sel_i) ? u_mgmt_nmi_if.valid : u_user_nmi_if.valid;
assign nmi.addr = ~(|sel_i) ? u_mgmt_nmi_if.addr : u_user_nmi_if.addr;
assign nmi.wdata = ~(|sel_i) ? u_mgmt_nmi_if.wdata : u_user_nmi_if.wdata;
assign nmi.wstrb = ~(|sel_i) ? u_mgmt_nmi_if.wstrb : u_user_nmi_if.wstrb;
assign u_mgmt_nmi_if.rdata = ~(|sel_i) ? nmi.rdata : '0;
assign u_mgmt_nmi_if.ready = ~(|sel_i) ? nmi.ready : '0;
assign s_mgmt_irq = ~(|sel_i) ? irq_i : '0;
assign u_user_nmi_if.rdata = (|sel_i) ? nmi.rdata : '0;
assign u_user_nmi_if.ready = (|sel_i) ? nmi.ready : '0;
assign s_user_irq = (|sel_i) ? irq_i : '0;
mgmt_core_wrapper u_mgmt_core_wrapper (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.irq_i (s_mgmt_irq),
.nmi (u_mgmt_nmi_if)
);
user_core_top u_user_core_top (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.irq_i (s_user_irq),
.sel_i (sel_i),
.nmi (u_user_nmi_if)
);
endmodule
@@ -9,11 +9,9 @@
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`ifndef MDD_CONFIG_DEF_SVH
`define MDD_CONFIG_DEF_SVH
`ifndef USER_EXTENSIONS_DEF_SVH
`define USER_EXTENSIONS_DEF_SVH
`define USER_CORESEL_WIDTH 5
`define USER_IPSEL_WIDTH 8
`define USER_GPIO_NUM 32
`include "user_extensions_config.svh"
`endif
+1 -1
View File
@@ -9,7 +9,7 @@
// See the Mulan PSL v2 for more details.
`include "mdd_config.svh"
`include "user_extensions.svh"
module user_ip_top (
// verilog_format: off
+1 -1
View File
@@ -8,7 +8,7 @@
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "mdd_config.svh"
`include "user_extensions.svh"
module user_ip_wrapper (
// verilog_format: off
+13
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import argparse
import hashlib
import json
import posixpath
import re
import sys
from collections import Counter
@@ -26,6 +27,10 @@ LOCATION_RE = re.compile(
r"(?:c|cc|cpp|cxx|h|hpp|py|sv|svh|tcl|v|vh)):\d+(?::\d+)?",
re.IGNORECASE,
)
GENERATED_MPW_PATH_RE = re.compile(
r"\$BUILD/generated/mpw/[A-Za-z0-9_-]+/(?P<tree>core|ip)/(?P<path>[^\s:]+)"
)
MPW_INSTANCE_FILE_SUFFIX_RE = re.compile(r"_username[0-9]+(?=\.(?:sv|svh|v|vh)$)")
def warning_line(tool: str, line: str) -> tuple[str, str] | None:
@@ -58,11 +63,19 @@ def normalize(root: Path, identifier: str, message: str) -> str:
value,
)
value = value.replace(resolved_root, "$ROOT")
value = GENERATED_MPW_PATH_RE.sub(_normalize_generated_mpw_path, value)
value = LOCATION_RE.sub(lambda match: match.group("path") + ":<line>", value)
value = re.sub(r"\s+", " ", value)
return f"{identifier}:{value}"
def _normalize_generated_mpw_path(match: re.Match[str]) -> str:
"""Map isolated MPW copies back to their managed source locations."""
relative_path = posixpath.normpath(match.group("path"))
relative_path = MPW_INSTANCE_FILE_SUFFIX_RE.sub("", relative_path)
return f"$ROOT/rtl/managed/mpw/{match.group('tree')}/{relative_path}"
def scan(tool: str, logs: list[Path], root: Path) -> dict[str, object]:
counts: Counter[str] = Counter()
examples: dict[str, str] = {}
-2
View File
@@ -23,8 +23,6 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--synth", required=True)
parser.add_argument("--sta", required=True)
parser.add_argument("--pdk", required=True)
parser.add_argument("--core", required=True)
parser.add_argument("--ip", required=True)
parser.add_argument("--formal", choices=("YES", "NO"), default="NO")
parser.add_argument("--lock", type=Path, default=DEFAULT_LOCK)
parser.add_argument("--format", choices=("text", "json"), default="text")
+25 -28
View File
@@ -83,6 +83,17 @@ def migrate_user_gpio_interfaces(root: Path) -> list[Path]:
return migrated
def remove_legacy_picorv32_entry(filelist: Path, management_core_dir: Path) -> None:
"""Remove the PicoRV32 line emitted by the legacy user-core generator."""
excluded = {
str((management_core_dir / "picorv32.v").resolve()),
str((management_core_dir / "picorv32_ver.v").resolve()),
}
content = filelist.read_text(encoding="utf-8")
filtered = [line for line in content.splitlines() if line.strip() not in excluded]
filelist.write_text("\n".join(filtered) + "\n", encoding="utf-8")
def remove_tree(path: Path) -> None:
"""Remove an MPW workspace, tolerating transient NFS directory entries."""
for attempt in range(3):
@@ -126,41 +137,28 @@ def generate(args: argparse.Namespace) -> None:
root = args.root.resolve()
managed_mpw = root / "rtl/managed/mpw"
output = args.output.resolve()
needs_core = args.core == "MDD"
needs_ip = args.ip == "MDD"
log_path = output.parent / f"{output.name}-generation.log"
output.parent.mkdir(parents=True, exist_ok=True)
with log_path.open("w", encoding="utf-8") as log, temporary_workspace(
output.parent, f".{output.name}."
) as workspace:
log.write(f"simulator={args.simu} core={args.core} ip={args.ip}\n")
with (
log_path.open("w", encoding="utf-8") as log,
temporary_workspace(output.parent, f".{output.name}.") as workspace,
):
log.write(f"simulator={args.simu} user-extensions=enabled\n")
candidate = workspace / "output"
candidate.mkdir()
if not needs_core and not needs_ip:
if tree_digest(candidate) == tree_digest(output):
print(f"[mpw] generated output unchanged: {output} (log: {log_path})")
return
if output.exists():
shutil.rmtree(output)
os.replace(candidate, output)
print(f"[mpw] generated isolated output: {output} (log: {log_path})")
return
mpw = prepare_legacy_mpw_workspace(root, managed_mpw, workspace)
shared = mpw / ".build"
(shared / "user_design_info.h").unlink(missing_ok=True)
if needs_ip:
run(workspace, log, mpw / "ip.py")
run(workspace, log, mpw / "info.py", "IP")
shutil.copytree(shared / "ip", candidate / "ip")
migrated = migrate_user_gpio_interfaces(candidate / "ip")
log.write(f"migrated user GPIO interfaces: {len(migrated)}\n")
if needs_core:
run(workspace, log, mpw / "core.py", args.simu)
run(workspace, log, mpw / "info.py", "CORE")
shutil.copytree(shared / "core", candidate / "core")
run(workspace, log, mpw / "ip.py")
run(workspace, log, mpw / "info.py", "IP")
shutil.copytree(shared / "ip", candidate / "ip")
migrated = migrate_user_gpio_interfaces(candidate / "ip")
log.write(f"migrated user GPIO interfaces: {len(migrated)}\n")
run(workspace, log, mpw / "core.py", args.simu)
run(workspace, log, mpw / "info.py", "CORE")
shutil.copytree(shared / "core", candidate / "core")
info = shared / "user_design_info.h"
if info.is_file():
shutil.copy2(info, candidate / info.name)
@@ -172,6 +170,7 @@ def generate(args: argparse.Namespace) -> None:
(workspace / "rtl" / "mini" / "core", root / "rtl/managed/picorv32/rtl"),
),
)
remove_legacy_picorv32_entry(candidate / "core/core.fl", root / "rtl/managed/picorv32/rtl")
if tree_digest(candidate) == tree_digest(output):
print(f"[mpw] generated output unchanged: {output} (log: {log_path})")
return
@@ -186,8 +185,6 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--root", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--simu", choices=("VCS", "VERILATOR", "IVERILOG"), required=True)
parser.add_argument("--core", choices=("PICORV32", "HAZARD3", "MDD"), required=True)
parser.add_argument("--ip", choices=("NONE", "MDD"), required=True)
parser.add_argument("--lock-file", type=Path, required=True)
return parser.parse_args()
+26 -7
View File
@@ -43,7 +43,9 @@ def make_sbom(lock: dict[str, object]) -> dict[str, object]:
components = [component(name, "source", spec) for name, spec in lock["sources"].items()]
components.extend(component(name, "archive", spec) for name, spec in lock["archives"].items())
for platform, tools in lock["toolchains"].items():
components.extend(component(f"{platform}/{name}", "toolchain", spec) for name, spec in tools.items())
components.extend(
component(f"{platform}/{name}", "toolchain", spec) for name, spec in tools.items()
)
return {
"bomFormat": "CycloneDX",
"specVersion": "1.5",
@@ -66,19 +68,34 @@ def main() -> int:
lock = load_lock(args.lock)
args.output_dir.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory(prefix="retrosoc-package-", dir=args.output_dir.parent) as temp:
with tempfile.TemporaryDirectory(
prefix="retrosoc-package-", dir=args.output_dir.parent
) as temp:
staging = Path(temp) / "package"
staging.mkdir()
command = [
"python3", str(root / "syn/tools/export_soc_sources.py"), "sv",
"--output-dir", str(staging), "--pdk", config["PDK"],
"--core", config["CORE"], "--ip", config["IP"], "--simu", config["SIMU"],
"python3",
str(root / "syn/tools/export_soc_sources.py"),
"sv",
"--output-dir",
str(staging),
"--pdk",
config["PDK"],
"--simu",
config["SIMU"],
"--core",
config.get("CORE", "HAZARD3"),
"--dynamic-core-filelist",
str(args.variant_root / "generated/mpw" / config["SIMU"].lower() / "core/core.fl"),
"--dynamic-ip-filelist",
str(args.variant_root / "generated/mpw" / config["SIMU"].lower() / "ip/ip.fl"),
]
for key, flag in (("HAVE_PLL", "--have-pll"), ("HAVE_SRAM_IF", "--have-sram-if"), ("HAVE_SRAM_MACRO", "--have-sram-macro"), ("HAVE_SVA", "--have-sva")):
for key, flag in (
("HAVE_PLL", "--have-pll"),
("HAVE_SRAM_IF", "--have-sram-if"),
("HAVE_SRAM_MACRO", "--have-sram-macro"),
("HAVE_SVA", "--have-sva"),
):
if config.get(key) == "YES":
command.append(flag)
subprocess.run(command, cwd=root, check=True)
@@ -87,7 +104,9 @@ def main() -> int:
shutil.rmtree(staging / "rtl")
shutil.copy2(args.lock, staging / "dependencies.lock.json")
shutil.copy2(manifest_path, staging / "manifest.json")
(staging / "sbom.cdx.json").write_text(json.dumps(make_sbom(lock), indent=2, sort_keys=True) + "\n", encoding="utf-8")
(staging / "sbom.cdx.json").write_text(
json.dumps(make_sbom(lock), indent=2, sort_keys=True) + "\n", encoding="utf-8"
)
checksums = []
for path in sorted(item for item in staging.iterdir() if item.is_file()):
checksums.append(f"{hashlib.sha256(path.read_bytes()).hexdigest()} {path.name}")
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Publish the archive pinned by config/dependencies.lock.json to retroSoC/artifact.
set -euo pipefail
readonly REPOSITORY="retroSoC/artifact"
readonly RELEASE_TAG="fatfs-r0.16"
readonly ASSET_NAME="fatfs-r0.16.zip"
readonly ARCHIVE_SHA256="99f7dc1f7e095356e4a9e3dbe29959090d8b948afe2bbc5441e52fdf4b85449e"
readonly ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
readonly SOURCE_ARCHIVE="${1:-${ROOT_DIR}/app/fatfs/ff16/ff16.zip}"
command -v gh >/dev/null
gh auth status --hostname github.com
if [[ ! -f "${SOURCE_ARCHIVE}" ]]; then
printf 'FatFs archive not found: %s\n' "${SOURCE_ARCHIVE}" >&2
exit 1
fi
actual_sha256="$(sha256sum "${SOURCE_ARCHIVE}" | awk '{print $1}')"
if [[ "${actual_sha256}" != "${ARCHIVE_SHA256}" ]]; then
printf 'FatFs archive checksum mismatch: expected %s, got %s\n' \
"${ARCHIVE_SHA256}" "${actual_sha256}" >&2
exit 1
fi
if gh release view "${RELEASE_TAG}" --repo "${REPOSITORY}" >/dev/null 2>&1; then
printf 'Release already exists: %s\n' "${RELEASE_TAG}" >&2
exit 1
fi
temporary_dir="$(mktemp -d)"
trap 'rm -rf "${temporary_dir}"' EXIT
publish_archive="${temporary_dir}/${ASSET_NAME}"
cp "${SOURCE_ARCHIVE}" "${publish_archive}"
gh release create "${RELEASE_TAG}" --repo "${REPOSITORY}" --title "FatFs R0.16" \
--notes "Locked FatFs R0.16 source archive." "${publish_archive}"
gh release download "$RELEASE_TAG" --repo "$REPOSITORY" --pattern "$ASSET_NAME" \
--dir "${temporary_dir}/download"
published_sha256="$(sha256sum "${temporary_dir}/download/${ASSET_NAME}" | awk '{print $1}')"
if [[ "${published_sha256}" != "${ARCHIVE_SHA256}" ]]; then
printf 'Published FatFs archive checksum mismatch: expected %s, got %s\n' \
"${ARCHIVE_SHA256}" "${published_sha256}" >&2
exit 1
fi
printf 'Published https://github.com/%s/releases/download/%s/%s\n' \
"${REPOSITORY}" "${RELEASE_TAG}" "${ASSET_NAME}"
+18 -46
View File
@@ -19,29 +19,14 @@ RTL_LINT_VALUES = ("SIMU=VERILATOR", "HAVE_SVA=YES", "rtl-lint", "check-rtl-lint
PR_COMMANDS = (
("configs/ci/hazard3-rv32im-ihp130.mk", RTL_LINT_VALUES),
("configs/ci/hazard3-rv32im-ihp130.mk", ("firmware",)),
("configs/ci/hazard3-rv32im-ihp130-shell.mk", ("firmware",)),
("configs/ci/hazard3-rv32im-ihp130-ip-mdd-shell.mk", ("firmware",)),
("configs/ci/ihp130.mk", RTL_LINT_VALUES),
("configs/ci/ihp130.mk", ("firmware",)),
("configs/ci/ihp130-shell.mk", ("firmware",)),
("configs/ci/ihp130.mk", ("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim")),
("configs/ci/ihp130.mk", ("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm")),
("configs/ci/ihp130.mk", ("SYNTH=YOSYS", "synth")),
(
"configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk",
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
),
(
"configs/ci/mdd-rv32im-ihp130.mk",
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
),
(
"configs/ci/hazard3-rv32im-ihp130.mk",
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
),
(
"configs/ci/hazard3-rv32im-ihp130.mk",
("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm"),
),
("configs/ci/hazard3-rv32im-ihp130.mk", ("SYNTH=YOSYS", "synth")),
(
"configs/ci/hazard3-rv32im-ihp130.mk",
"configs/ci/ihp130.mk",
(
"SIMU=IVERILOG",
"SIM_FIRMWARE_NAME=retrosoc_asm",
@@ -50,42 +35,29 @@ PR_COMMANDS = (
"netsim",
),
),
("configs/ci/hazard3-rv32im-ihp130.mk", ("STA=OPENSTA", "sta")),
("configs/ci/ihp130.mk", ("STA=OPENSTA", "sta")),
)
SMOKE_COMMANDS = (
("configs/ci/hazard3-rv32im-ihp130.mk", RTL_LINT_VALUES),
("configs/ci/hazard3-rv32im-ihp130.mk", ("firmware",)),
("configs/ci/ihp130.mk", RTL_LINT_VALUES),
("configs/ci/ihp130.mk", ("firmware",)),
(
"configs/ci/hazard3-rv32im-ihp130.mk",
"configs/ci/ihp130.mk",
("SIMU=VERILATOR", "HAVE_SVA=YES", "comp"),
),
(
"configs/ci/hazard3-rv32im-ihp130.mk",
"configs/ci/ihp130.mk",
("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm"),
),
)
NIGHTLY_COMMANDS = PR_COMMANDS + (
(
"configs/nightly/picorv32-rv32im-ihp130.mk",
("SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
),
(
"configs/nightly/picorv32-rv32im-ihp130.mk",
("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm"),
),
)
PR_PROFILES = (
"configs/ci/hazard3-rv32im-ihp130.mk",
"configs/ci/hazard3-rv32im-ihp130-ip-mdd.mk",
"configs/ci/mdd-rv32im-ihp130.mk",
)
NIGHTLY_COMMANDS = PR_COMMANDS
PR_PROFILES = ("configs/ci/ihp130.mk",)
SMOKE_PROFILES: tuple[str, ...] = ()
NIGHTLY_PROFILES = PR_PROFILES + ("configs/nightly/picorv32-rv32im-ihp130.mk",)
NIGHTLY_PROFILES = PR_PROFILES
PDK_PR_PROFILES = {
"GF180": "configs/ci/hazard3-rv32im-gf180.mk",
"IHP130": "configs/ci/hazard3-rv32im-ihp130.mk",
"SKY130": "configs/ci/hazard3-rv32im-sky130.mk",
"GF180": "configs/ci/gf180.mk",
"IHP130": "configs/ci/ihp130.mk",
"SKY130": "configs/ci/sky130.mk",
}
+15
View File
@@ -40,6 +40,7 @@ def main() -> int:
with tempfile.TemporaryDirectory(prefix="retrosoc-c-tests-") as temporary_directory:
temporary_root = Path(temporary_directory)
memory_map_root = temporary_root / "memory_map"
user_extensions_root = temporary_root / "user_extensions"
subprocess.run(
[
sys.executable,
@@ -51,6 +52,17 @@ def main() -> int:
],
check=True,
)
subprocess.run(
[
sys.executable,
str(root / "rtl/mini/integration/generate_user_extensions.py"),
"--map",
str(root / "rtl/mini/integration/user_extensions.json"),
"--output-dir",
str(user_extensions_root),
],
check=True,
)
executable = temporary_root / "runtime_tests"
command = [
compiler,
@@ -59,9 +71,12 @@ def main() -> int:
"-Wextra",
"-Werror",
"-fno-builtin",
"-DRS_SOC_MGMT_CORE_HAZARD3",
"-I",
str(memory_map_root / "include"),
"-I",
str(user_extensions_root / "include"),
"-I",
str(root / "crt/include"),
"-I",
str(root / "app/media/include"),
+6 -6
View File
@@ -8,12 +8,12 @@ Run synthesis before timing analysis, then invoke the supported OpenSTA flow.
All CI PDK profiles are supported:
```sh
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk STA=OPENSTA sta
make CONFIG=configs/ci/hazard3-rv32im-gf180.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/hazard3-rv32im-gf180.mk STA=OPENSTA sta
make CONFIG=configs/ci/hazard3-rv32im-sky130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/hazard3-rv32im-sky130.mk STA=OPENSTA sta
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/ihp130.mk STA=OPENSTA sta
make CONFIG=configs/ci/gf180.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/gf180.mk STA=OPENSTA sta
make CONFIG=configs/ci/sky130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/sky130.mk STA=OPENSTA sta
```
The generated SDC derives clock and reset objects from
+1 -1
View File
@@ -7,7 +7,7 @@ export tooling. `yosys/` owns the supported open-source synthesis flow;
Use a committed profile and run the supported flow:
```sh
make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SYNTH=YOSYS synth
make CONFIG=configs/ci/ihp130.mk SYNTH=YOSYS synth
```
Synthesis outputs are generated below `build/` and must not be committed.
+36 -34
View File
@@ -14,9 +14,12 @@ from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
SCRIPT_DIR = REPO_ROOT / "rtl/mini/script"
INTEGRATION_DIR = REPO_ROOT / "rtl/mini/integration"
sys.path.insert(0, str(SCRIPT_DIR))
sys.path.insert(0, str(INTEGRATION_DIR))
from filelist import FileList, atomic_write, parse_filelists # noqa: E402
from generate_filelist import generate_all # noqa: E402
from generate_user_extensions import generate as generate_user_extensions # noqa: E402
INCLUDE_RE = re.compile(r'^\s*`include\s+"([^"]+)"')
@@ -25,8 +28,6 @@ INCLUDE_RE = re.compile(r'^\s*`include\s+"([^"]+)"')
def build_defines(args: argparse.Namespace) -> list[str]:
defines = [
f"+define+PDK_{args.pdk}",
f"+define+CORE_{args.core}",
f"+define+IP_{args.ip}",
f"+define+SIMU_{args.simu}",
"+define+SYNTHESIS",
]
@@ -38,10 +39,13 @@ def build_defines(args: argparse.Namespace) -> list[str]:
defines.append("+define+HAVE_SRAM_MACRO")
if not args.have_sva:
defines.append("+define+SV_ASSRT_DISABLE")
defines.append(f"+define+CORE_{args.core}")
return defines
def configured_filelist(args: argparse.Namespace, generated_dir: Path) -> FileList:
def configured_filelist(
args: argparse.Namespace, generated_dir: Path, user_extensions_dir: Path
) -> FileList:
names = [
"def.fl",
"sys_def.fl",
@@ -51,24 +55,16 @@ def configured_filelist(args: argparse.Namespace, generated_dir: Path) -> FileLi
"ip.fl",
"tech.fl",
]
if args.core in ("HAZARD3", "PICORV32"):
names.append(f"core_{args.core.lower()}.fl")
else:
dynamic_core = args.dynamic_core_filelist
if not dynamic_core.is_file():
raise FileNotFoundError(
f"MDD core filelist is not generated: {dynamic_core}; "
"run 'make CORE=MDD gen_mpw_code'"
)
names.append(str(dynamic_core))
if args.ip == "MDD":
dynamic_ip = args.dynamic_ip_filelist
if not dynamic_ip.is_file():
raise FileNotFoundError(
f"MDD IP filelist is not generated: {dynamic_ip}; "
"run 'make IP=MDD gen_mpw_code'"
)
names.append(str(dynamic_ip))
names.append(f"core_{args.core.lower()}.fl")
dynamic_core = args.dynamic_core_filelist
if not dynamic_core.is_file():
raise FileNotFoundError(f"user core filelist is not generated: {dynamic_core}")
names.append(str(dynamic_core))
dynamic_ip = args.dynamic_ip_filelist
if not dynamic_ip.is_file():
raise FileNotFoundError(f"user IP filelist is not generated: {dynamic_ip}")
names.append(str(dynamic_ip))
names.append(str(user_extensions_dir / "user_extensions.fl"))
names.append("top.fl")
paths = [Path(name) if Path(name).is_absolute() else generated_dir / name for name in names]
return parse_filelists(paths)
@@ -134,7 +130,11 @@ def defines_to_sv(defines: list[str]) -> list[str]:
def write_single_sv(filelist: FileList, output: Path) -> None:
lines = ["// Generated by syn/tools/export_soc_sources.py", *defines_to_sv(filelist.defines), ""]
lines = [
"// Generated by syn/tools/export_soc_sources.py",
*defines_to_sv(filelist.defines),
"",
]
for source in [*filelist.library_files, *filelist.files]:
lines.append(f"// ===== file: {source.relative_to(REPO_ROOT)} =====")
lines.extend(inline_file(source, filelist.incdirs))
@@ -179,9 +179,8 @@ def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Export configured retroSoC RTL sources")
parser.add_argument("mode", choices=("tar", "sv"))
parser.add_argument("--soc", default="MINI", choices=("MINI",))
parser.add_argument("--core", default="HAZARD3", choices=("HAZARD3", "PICORV32"))
parser.add_argument("--pdk", default="IHP130", choices=("IHP130", "ICS55", "SKY130", "GF180"))
parser.add_argument("--core", default="HAZARD3", choices=("HAZARD3", "PICORV32", "MDD"))
parser.add_argument("--ip", default="NONE", choices=("NONE", "MDD"))
parser.add_argument("--simu", default="VCS", choices=("VCS", "VERILATOR", "IVERILOG"))
parser.add_argument("--have-pll", action="store_true")
parser.add_argument("--have-sram-if", action="store_true")
@@ -203,18 +202,21 @@ def parse_args() -> argparse.Namespace:
def main() -> int:
args = parse_args()
with tempfile.TemporaryDirectory(prefix="retrosoc-filelists-") as temporary:
generated_dir = Path(temporary)
generate_all(generated_dir, build_defines(args))
filelist = configured_filelist(args, generated_dir)
export_dir = args.output_dir.resolve()
export_dir.mkdir(parents=True, exist_ok=True)
if args.mode == "sv":
output = export_dir / "retrosoc_asic_sources.sv"
write_single_sv(filelist, output)
else:
output = write_tar(filelist, export_dir, args.soc)
with tempfile.TemporaryDirectory(prefix="retrosoc-filelists-") as temporary:
generated_dir = Path(temporary)
user_extensions_dir = generated_dir / "user_extensions"
generate_all(generated_dir, build_defines(args))
generate_user_extensions(
REPO_ROOT / "rtl/mini/integration/user_extensions.json", user_extensions_dir
)
filelist = configured_filelist(args, generated_dir, user_extensions_dir)
if args.mode == "sv":
output = export_dir / "retrosoc_asic_sources.sv"
write_single_sv(filelist, output)
else:
output = write_tar(filelist, export_dir, args.soc)
print(f"generated: {output}")
return 0
-2
View File
@@ -13,8 +13,6 @@ set variables {
sv_flist { SV_FLIST "" }
pdk { PDK "" }
soc { SOC "" }
core { CORE "" }
ip { IP "" }
top_design { TOP_DESIGN "" }
hier_depth { HIER_DEPTH 0 }
period_ps { YOSYS_TARGET_PERIOD_PS 5000 }
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff. Show more