mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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:
111 files changed
+3729
-2012
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 *)®_wdg_ctrl);
|
||||
printf(" 1 x CRC @%p\n", (void *)®_crc_ctrl);
|
||||
printf(" 1 x TIMER3(ADV) @%p\n", (void *)®_tim3_ctrl);
|
||||
#ifdef IP_MDD
|
||||
printf(" 1 x USER_IP(4KiB) @%p\n", (void *)®_user_ip_reg0);
|
||||
#endif
|
||||
printf("\n");
|
||||
printf("#############################################################\n");
|
||||
printf("#############################################################\n");
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
"signature": "aee22756a35889cc"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-gf180",
|
||||
"profile": "gf180",
|
||||
"schema_version": 1,
|
||||
"tool": "iverilog"
|
||||
}
|
||||
+1
-1
@@ -3016,7 +3016,7 @@
|
||||
"signature": "ffd1d68a726cc2c7"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-gf180",
|
||||
"profile": "gf180",
|
||||
"schema_version": 1,
|
||||
"tool": "rtl-lint"
|
||||
}
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
"signature": "ef9f314dab2ac31d"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-gf180",
|
||||
"profile": "gf180",
|
||||
"schema_version": 1,
|
||||
"tool": "verilator"
|
||||
}
|
||||
+1
-1
@@ -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"
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
"signature": "c4297f454f443fed"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-ihp130",
|
||||
"profile": "ihp130",
|
||||
"schema_version": 1,
|
||||
"tool": "iverilog"
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"entries": [],
|
||||
"profile": "hazard3-rv32im-ihp130",
|
||||
"profile": "ihp130",
|
||||
"schema_version": 1,
|
||||
"tool": "opensta"
|
||||
}
|
||||
+2051
-466
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -81,7 +81,7 @@
|
||||
"signature": "faa191e2dbf4a242"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-ihp130",
|
||||
"profile": "ihp130",
|
||||
"schema_version": 1,
|
||||
"tool": "verilator"
|
||||
}
|
||||
+1
-1
@@ -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"
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
"signature": "aee22756a35889cc"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"profile": "sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "iverilog"
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
"signature": "3c380feb1d0cd00a"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"profile": "sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "opensta"
|
||||
}
|
||||
+1
-1
@@ -3116,7 +3116,7 @@
|
||||
"signature": "ffd1d68a726cc2c7"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"profile": "sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "rtl-lint"
|
||||
}
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
"signature": "ef9f314dab2ac31d"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"profile": "sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "verilator"
|
||||
}
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
"signature": "ef03dcca25b39dcb"
|
||||
}
|
||||
],
|
||||
"profile": "hazard3-rv32im-sky130",
|
||||
"profile": "sky130",
|
||||
"schema_version": 1,
|
||||
"tool": "yosys"
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 ======================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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),
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
|
||||
@@ -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"}},
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)'
|
||||
|
||||
|
||||
@@ -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,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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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)
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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] = {}
|
||||
|
||||
@@ -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
@@ -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
@@ -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}")
|
||||
|
||||
Executable
+51
@@ -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
@@ -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",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
Reference in new issue
Block a user