feat: enhance build variant ID generation and regression environment setup

- Added timestamp normalization to  function in , allowing for optional timestamp input.
- Updated command-line interface to accept a timestamp argument for generating deterministic build variant IDs.
- Modified  in  to include a build timestamp in the environment variables.
- Introduced a new test suite in  to validate the pin-map generator, including tests for duplicate pads and invalid entries.
- Added a test for ensuring the regression runner uses a consistent build timestamp.
- Created a new SystemVerilog testbench for the APB4 interface bridge to verify correct signal crossing.
This commit is contained in:
maksyuki committed 2026-07-21 10:59:31 +08:00
1 parent fc898bc4ab
commit f5b373fd65
28 files changed
+1082 -754

No files matched your search

+1 -1
View File
@@ -98,7 +98,7 @@ README that states its ownership, source of truth, and validation expectations.
## Build and Repository Safety
- Start from a committed configuration profile. Build products belong below
`build/<profile>-<config-hash>/`; caches belong below `.cache/`. Do not
`build/<profile>-<YYYY-MM-DD-HH-MM>-<config-hash>/`; caches belong below `.cache/`. Do not
commit generated outputs.
- Preserve unrelated worktree changes. Do not reset, discard, or reformat files
outside the requested scope.
+8 -3
View File
@@ -51,6 +51,7 @@ LINK_TYPE ?= ld2_sram
BUILD_ROOT ?= $(ROOT_PATH)/build
CACHE_ROOT ?= $(ROOT_PATH)/.cache/retrosoc
BUILD_TIMESTAMP ?= $(shell date '+%Y-%m-%d-%H-%M')
MAX_JOBS ?= 16
HOST_CC ?= cc
CLANG_FORMAT ?= clang-format-14
@@ -60,12 +61,13 @@ JOBS ?= $(shell count=$$(nproc 2>/dev/null || printf '1'); \
CONFIG_KEY_VARS := SOC CORE IP 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) \
--lock $(LOCK_FILE) --profile $(PROFILE_NAME) --timestamp $(BUILD_TIMESTAMP) \
$(foreach var,$(CONFIG_KEY_VARS),--value $(var)=$($(var)))))
ifeq ($(VARIANT_ID),)
$(error Failed to calculate build variant ID)
endif
LOCK_DIGEST := $(strip $(shell python3 $(ROOT_PATH)/scripts/dependency_lock.py --lock $(LOCK_FILE) --digest))
export BUILD_TIMESTAMP
VARIANT_ROOT := $(abspath $(BUILD_ROOT))/$(VARIANT_ID)
SW_BUILD_DIR := $(VARIANT_ROOT)/sw
SIM_TOOL_NAME := $(shell printf '%s' '$(SIMU)' | tr '[:upper:]' '[:lower:]')
@@ -161,7 +163,8 @@ endif
.PHONY: help config doctor setup setup-mpw setup-core setup-clusterip setup-ip setup-pdk setup-app \
clean-all purge-cache manifest check-warnings metrics check-metrics package \
regress-pr regress-nightly sim-asm sw-format sw-format-check sw-policy-check sw-host-test
regress-pr regress-nightly sim-asm sw-format sw-format-check sw-policy-check sw-host-test \
pin-map check-pin-map
.NOTPARALLEL: setup
help:
@@ -178,6 +181,8 @@ help:
' config | manifest print/write the effective configuration' \
' memory-map generate the selected address-map artifacts' \
' check-memory-map validate the canonical address map' \
' pin-map generate the selected pin-map artifacts' \
' check-pin-map validate the canonical SoC pin map' \
' check-warnings | metrics analyze flow logs and reports' \
' check-metrics apply the committed metrics policy' \
' sw-format apply clang-format to self-owned embedded C code' \
@@ -194,7 +199,7 @@ help:
config:
@printf '%-18s %s\n' \
ROOT_PATH '$(ROOT_PATH)' CONFIG '$(or $(CONFIG_PATH),<defaults>)' \
VARIANT_ID '$(VARIANT_ID)' VARIANT_ROOT '$(VARIANT_ROOT)' \
BUILD_TIMESTAMP '$(BUILD_TIMESTAMP)' VARIANT_ID '$(VARIANT_ID)' VARIANT_ROOT '$(VARIANT_ROOT)' \
JOBS '$(JOBS)' \
SOC '$(SOC)' CORE '$(CORE)' IP '$(IP)' \
SIMU '$(SIMU)' SYNTH '$(SYNTH)' STA '$(STA)' PDK '$(PDK)' \
+10 -1
View File
@@ -116,12 +116,21 @@ make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk SIMU=IVERILOG \
| Nightly regression suite | `make regress-nightly` |
| Script and policy checks | `make sw-format-check sw-policy-check sw-host-test` |
Build outputs are isolated below `build/<profile>-<config-hash>/`. Each variant keeps its
Build outputs are isolated below `build/<profile>-<YYYY-MM-DD-HH-MM>-<config-hash>/`. Each variant keeps its
firmware, generated sources, simulator output, synthesis and timing reports, manifest, warning
analysis, and metrics separate from other configurations. Use `make clean` to remove the
selected backend, `make clean-all` to remove all build output, and `make purge-cache` to remove
download and compiler caches.
`BUILD_TIMESTAMP` defaults to the local build-start time. Set it explicitly when separate Make
commands must reuse one variant:
```sh
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
```
## Reproducibility And CI
[`config/dependencies.lock.json`](config/dependencies.lock.json) is the source of truth for
+2
View File
@@ -9,6 +9,8 @@ the root README and subsystem guides.
baseline, scope, partial automation, and deviation process.
- [pll-clock-control.md](pll-clock-control.md) describes the SYSCTRL PLL
register protocol and software quiesce contract.
- [soc-integration-wiring.md](soc-integration-wiring.md) defines the generated
pin-map workflow and SoC integration boundary.
Keep policy descriptions here concise and link to executable configuration as
the source of truth. Changes that alter process requirements must also update
+7 -3
View File
@@ -60,13 +60,17 @@ affected implementation change.
## Build Layout
The variant identifier is the profile name plus a hash over effective hardware/software build
settings and the dependency lock. Runtime-only settings such as wave capture and timeout do not
create a new variant.
The variant identifier is the profile name, the local creation timestamp, and a hash over effective
hardware/software build settings and the dependency lock. The timestamp has the
`YYYY-MM-DD-HH-MM` format and does not alter the hash. Runtime-only settings such as wave capture
and timeout do not alter the hash either. `BUILD_TIMESTAMP` defaults to the current local minute;
set it explicitly when separate Make commands must share one variant. The regression runner exports
one timestamp to all of its child Make commands.
```text
build/<variant>/
generated/mpw/<simulator>/
generated/pin_map/
sw/
sim/<simulator>/
syn/yosys/
+27
View File
@@ -0,0 +1,27 @@
# SoC Integration Wiring
`rtl/mini/pin_map/pin_map.json` is the single source for the Mini SoC logical
pad ABI and its ASIC, FPGA, Verilator, and RTL-testbench bindings. It does not
contain board package locations; FPGA package constraints remain in the board
`.xdc` file.
The generator emits temporary SystemVerilog include files below
`build/<variant>/generated/pin_map/`. The ASIC top includes the generated port
and pad bindings, while each platform wrapper includes its own generated
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
```
When adding a pad, define its whitelisted pad template, direction, conditional
feature, and every profile binding in the JSON map. Use `null` for an open
binding. The generator rejects duplicate pad names, unknown profile bindings,
unsupported features, and unapproved connection syntax.
SoC wrappers use the existing clusterIP interfaces for protocol boundaries.
`apb4_if_bridge` only adapts `apb4_pure_if` to `apb4_if`, and `gpio_pad_bridge`
only exposes the pad-side subset of `gpio_if`; neither module contains state.
+7
View File
@@ -4,6 +4,13 @@ This directory contains FPGA-facing top-level integration for the Mini SoC.
`mini/retrosoc_top.sv` is the FPGA top wrapper and
`mini/starrysky_v2.xdc` contains board timing and pin constraints.
The wrapper consumes the generated `retrosoc_asic_fpga_mini_bindings.svh`
include. Before invoking an FPGA tool, generate the selected profile with
`make CONFIG=configs/ci/hazard3-rv32im-ihp130.mk pin-map` and add
`build/<variant>/generated/pin_map/rtl` to the tool include path. Logical pad
names and wrapper bindings are owned by `rtl/mini/pin_map/pin_map.json`;
package locations remain in the board `.xdc` file.
FPGA constraints are board-specific implementation inputs, not generic ASIC
RTL. Validate changes with the relevant FPGA tool flow and hardware target; do
not reuse them as ASIC timing constraints. Follow the RTL and hardware-facing
+2 -116
View File
@@ -3,7 +3,6 @@
module retrosoc_top (
input clk_i,
inout rst_n_i,
// gpio
inout ps2_clk_i,
inout ps2_dat_i,
output onewire_dat_o,
@@ -75,7 +74,6 @@ module retrosoc_top (
inout sdram_dq15_io
);
wire s_sys_clk;
wire s_aud_clk;
clk_wiz_0 u_clk_wiz_0 (
@@ -85,119 +83,7 @@ module retrosoc_top (
);
retrosoc_asic u_retrosoc (
.extclk_i_pad (s_sys_clk),
.audclk_i_pad (s_aud_clk),
.ext_rst_n_i_pad (rst_n_i),
`ifdef HAVE_PLL
.xi_i_pad (s_sys_clk),
.xo_o_pad (),
`endif
`ifdef CORE_MDD
.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),
`endif
`ifdef IP_MDD
.user_gpio_0_io_pad (),
.user_gpio_1_io_pad (),
.user_gpio_2_io_pad (),
.user_gpio_3_io_pad (),
.user_gpio_4_io_pad (),
.user_gpio_5_io_pad (),
.user_gpio_6_io_pad (),
.user_gpio_7_io_pad (),
.user_gpio_8_io_pad (),
.user_gpio_9_io_pad (),
.user_gpio_10_io_pad(),
.user_gpio_11_io_pad(),
.user_gpio_12_io_pad(),
.user_gpio_13_io_pad(),
.user_gpio_14_io_pad(),
.user_gpio_15_io_pad(),
`endif
.gpio_0_io_pad (ps2_clk_i),
.gpio_1_io_pad (ps2_dat_i),
.gpio_2_io_pad (onewire_dat_o),
.gpio_3_io_pad (i2c_scl_io),
.gpio_4_io_pad (i2c_sda_io),
.gpio_5_io_pad (pwm_2_o),
.gpio_6_io_pad (spisd_sck_o),
.gpio_7_io_pad (spisd_nss_o),
.gpio_8_io_pad (spisd_mosi_o),
.gpio_9_io_pad (spisd_miso_i),
.gpio_10_io_pad (i2s_mclk_o),
.gpio_11_io_pad (i2s_sclk_o),
.gpio_12_io_pad (i2s_lrck_o),
.gpio_13_io_pad (i2s_dacdat_o),
.gpio_14_io_pad (i2s_adcdat_i),
.gpio_15_io_pad (),
.gpio_16_io_pad (),
.gpio_17_io_pad (),
.gpio_18_io_pad (),
.gpio_19_io_pad (),
.gpio_20_io_pad (),
.gpio_21_io_pad (psram_sck_o),
.gpio_22_io_pad (psram_nss0_o),
.gpio_23_io_pad (psram_dat0_io),
.gpio_24_io_pad (psram_dat1_io),
.gpio_25_io_pad (psram_dat2_io),
.gpio_26_io_pad (psram_dat3_io),
.gpio_27_io_pad (),
.gpio_28_io_pad (),
.gpio_29_io_pad (),
.gpio_30_io_pad (gpio_io30),
.gpio_31_io_pad (),
.uart0_tx_o_pad (uart0_tx_o),
.uart0_rx_i_pad (uart0_rx_i),
.xpi_sck_o_pad (xpi_sck_o),
.xpi_nss0_o_pad (xpi_nss0_o),
.xpi_nss1_o_pad (),
.xpi_nss2_o_pad (),
.xpi_nss3_o_pad (),
.xpi_dat0_io_pad (xpi_dat0_io),
.xpi_dat1_io_pad (xpi_dat1_io),
.xpi_dat2_io_pad (xpi_dat2_io),
.xpi_dat3_io_pad (xpi_dat3_io),
.sdram_clk_o_pad (sdram_clk_o),
.sdram_cke_o_pad (sdram_cke_o),
.sdram_cs_n_o_pad (sdram_cs_n_o),
.sdram_ras_n_o_pad (sdram_ras_n_o),
.sdram_cas_n_o_pad (sdram_cas_n_o),
.sdram_we_n_o_pad (sdram_we_n_o),
.sdram_ba0_o_pad (sdram_ba0_o),
.sdram_ba1_o_pad (sdram_ba1_o),
.sdram_addr0_o_pad (sdram_addr0_o),
.sdram_addr1_o_pad (sdram_addr1_o),
.sdram_addr2_o_pad (sdram_addr2_o),
.sdram_addr3_o_pad (sdram_addr3_o),
.sdram_addr4_o_pad (sdram_addr4_o),
.sdram_addr5_o_pad (sdram_addr5_o),
.sdram_addr6_o_pad (sdram_addr6_o),
.sdram_addr7_o_pad (sdram_addr7_o),
.sdram_addr8_o_pad (sdram_addr8_o),
.sdram_addr9_o_pad (sdram_addr9_o),
.sdram_addr10_o_pad (sdram_addr10_o),
.sdram_addr11_o_pad (sdram_addr11_o),
.sdram_addr12_o_pad (sdram_addr12_o),
.sdram_dqm0_o_pad (sdram_dqm0_o),
.sdram_dqm1_o_pad (sdram_dqm1_o),
.sdram_dq0_io_pad (sdram_dq0_io),
.sdram_dq1_io_pad (sdram_dq1_io),
.sdram_dq2_io_pad (sdram_dq2_io),
.sdram_dq3_io_pad (sdram_dq3_io),
.sdram_dq4_io_pad (sdram_dq4_io),
.sdram_dq5_io_pad (sdram_dq5_io),
.sdram_dq6_io_pad (sdram_dq6_io),
.sdram_dq7_io_pad (sdram_dq7_io),
.sdram_dq8_io_pad (sdram_dq8_io),
.sdram_dq9_io_pad (sdram_dq9_io),
.sdram_dq10_io_pad (sdram_dq10_io),
.sdram_dq11_io_pad (sdram_dq11_io),
.sdram_dq12_io_pad (sdram_dq12_io),
.sdram_dq13_io_pad (sdram_dq13_io),
.sdram_dq14_io_pad (sdram_dq14_io),
.sdram_dq15_io_pad (sdram_dq15_io)
`include "retrosoc_asic_fpga_mini_bindings.svh"
);
endmodule
+6 -2
View File
@@ -57,6 +57,10 @@ interface gpio_if ();
input alt1_oe_i,
output irq_o
);
modport pad(input oe_o, input cs_o, input pu_o, input pd_o, input do_o, output di_i);
modport soc_pad(output oe_o, output cs_o, output pu_o, output pd_o, output do_o, input di_i);
endinterface
module nmi_gpio (
@@ -120,8 +124,8 @@ module nmi_gpio (
assign s_gpio_alt_out[i] = s_gpio_pinmux_q[i] ? gpio.alt1_do_i[i] : gpio.alt0_do_i[i];
end
for (genvar i = 0; i < `NMI_GPIO_NUM; i++) begin : IOF_PINMUX_BLOCK
assign gpio.oe_o[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_oe[i] : s_gpio_oe_q[i];
assign gpio.do_o[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_out[i] : s_gpio_do_q[i];
assign gpio.oe_o[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_oe[i] : s_gpio_oe_q[i];
assign gpio.do_o[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_out[i] : s_gpio_do_q[i];
end
assign s_irq_stat = |s_gpio_istat_q;
assign gpio.irq_o = s_irq_stat;
+17 -3
View File
@@ -7,6 +7,11 @@ MEMORY_MAP_RTL_DIR := $(MEMORY_MAP_DIR)/rtl
MEMORY_MAP_C_DIR := $(MEMORY_MAP_DIR)/include
MEMORY_MAP_LINKER_DIR := $(MEMORY_MAP_DIR)/linker
MEMORY_MAP_FILELIST := $(MEMORY_MAP_DIR)/memory_map.fl
PIN_MAP_SOURCE := $(RTL_PATH)/pin_map/pin_map.json
PIN_MAP_SCRIPT := $(RTL_PATH)/pin_map/generate_pin_map.py
PIN_MAP_DIR := $(VARIANT_ROOT)/generated/pin_map
PIN_MAP_STAMP := $(PIN_MAP_DIR)/.stamp
PIN_MAP_FILELIST := $(PIN_MAP_DIR)/pin_map.fl
MPW_STAMP := $(CACHE_ROOT)/stamps/mpw-$(LOCK_DIGEST).prepared
MPW_OUTPUT_DIR := $(VARIANT_ROOT)/generated/mpw/$(SIM_TOOL_NAME)
MPW_VARIANT_STAMP := $(MPW_OUTPUT_DIR)/.stamp
@@ -43,8 +48,17 @@ memory-map: $(MEMORY_MAP_STAMP)
check-memory-map:
python3 $(MEMORY_MAP_SCRIPT) --map $(MEMORY_MAP_SOURCE) --check
$(PIN_MAP_STAMP): $(PIN_MAP_SOURCE) $(PIN_MAP_SCRIPT)
python3 $(PIN_MAP_SCRIPT) --map $(PIN_MAP_SOURCE) --output-dir $(PIN_MAP_DIR)
@touch $@
pin-map: $(PIN_MAP_STAMP)
check-pin-map:
python3 $(PIN_MAP_SCRIPT) --map $(PIN_MAP_SOURCE) --check
$(FILELIST_STAMP): $(FILELIST_TEMPLATES) $(RTL_PATH)/script/generate_filelist.py \
$(RTL_PATH)/script/filelist.py $(MEMORY_MAP_STAMP)
$(RTL_PATH)/script/filelist.py $(MEMORY_MAP_STAMP) $(PIN_MAP_STAMP)
python3 $(RTL_PATH)/script/generate_filelist.py \
--output-dir $(GENERATED_FL_DIR) \
$(foreach define,$(DEF_LIST),--define $(define))
@@ -71,7 +85,7 @@ NET_FLIST += -f $(GENERATED_FL_DIR)/sys_def.fl
NET_FLIST += -f $(GENERATED_FL_DIR)/commonip.fl
NET_FLIST += -f $(GENERATED_FL_DIR)/inc.fl
RTL_FLIST := -f $(MEMORY_MAP_FILELIST) $(NET_FLIST)
RTL_FLIST := -f $(MEMORY_MAP_FILELIST) -f $(PIN_MAP_FILELIST) $(NET_FLIST)
RTL_FLIST += -f $(GENERATED_FL_DIR)/clusterip.fl
RTL_FLIST += -f $(GENERATED_FL_DIR)/ip.fl
RTL_FLIST += -f $(GENERATED_FL_DIR)/tech.fl
@@ -99,4 +113,4 @@ else ifeq ($(SIMU), IVERILOG)
include $(RTL_PATH)/mk/iverilog.mk
endif
.PHONY: gen_mpw_code generate_filelist memory-map check-memory-map firmware
.PHONY: gen_mpw_code generate_filelist memory-map check-memory-map pin-map check-pin-map firmware
+1 -114
View File
@@ -91,120 +91,7 @@ module retrosoc_tb;
assign s_user_gpio_0_io = r_user_gpio_0_io;
retrosoc_asic u_retrosoc_asic (
.extclk_i_pad (s_ext_clk),
.audclk_i_pad (s_aud_clk),
.ext_rst_n_i_pad (s_rst_n),
`ifdef HAVE_PLL
.xi_i_pad (r_xtal_clk),
.xo_o_pad (),
`endif
`ifdef CORE_MDD
.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]),
`endif
`ifdef IP_MDD
.user_gpio_0_io_pad (s_user_gpio_0_io),
.user_gpio_1_io_pad (),
.user_gpio_2_io_pad (),
.user_gpio_3_io_pad (),
.user_gpio_4_io_pad (),
.user_gpio_5_io_pad (),
.user_gpio_6_io_pad (),
.user_gpio_7_io_pad (),
.user_gpio_8_io_pad (),
.user_gpio_9_io_pad (),
.user_gpio_10_io_pad(),
.user_gpio_11_io_pad(),
.user_gpio_12_io_pad(),
.user_gpio_13_io_pad(),
.user_gpio_14_io_pad(),
.user_gpio_15_io_pad(),
`endif
.gpio_0_io_pad (s_gpio_0_io),
.gpio_1_io_pad (s_gpio_1_io),
.gpio_2_io_pad (),
.gpio_3_io_pad (),
.gpio_4_io_pad (),
.gpio_5_io_pad (),
.gpio_6_io_pad (),
.gpio_7_io_pad (s_i2c0_scl_io),
.gpio_8_io_pad (s_i2c0_sda_io),
.gpio_9_io_pad (),
.gpio_10_io_pad (),
.gpio_11_io_pad (),
.gpio_12_io_pad (),
.gpio_13_io_pad (),
.gpio_14_io_pad (),
.gpio_15_io_pad (),
.gpio_16_io_pad (),
.gpio_17_io_pad (),
.gpio_18_io_pad (),
.gpio_19_io_pad (),
.gpio_20_io_pad (),
.gpio_21_io_pad (s_psram_sck),
.gpio_22_io_pad (s_psram_nss0),
.gpio_23_io_pad (s_psram_dat0),
.gpio_24_io_pad (s_psram_dat1),
.gpio_25_io_pad (s_psram_dat2),
.gpio_26_io_pad (s_psram_dat3),
.gpio_27_io_pad (s_psram_nss1),
.gpio_28_io_pad (),
.gpio_29_io_pad (),
.gpio_30_io_pad (),
.gpio_31_io_pad (),
.uart0_tx_o_pad (s_uart0_tx),
.uart0_rx_i_pad (s_uart0_rx),
.xpi_sck_o_pad (s_xpi_sck_o),
.xpi_nss0_o_pad (s_xpi_nss0_o), // xpi flash
.xpi_nss1_o_pad (s_xpi_nss1_o), // qpi flash
.xpi_nss2_o_pad (s_xpi_nss2_o),
.xpi_nss3_o_pad (), // tft test
.xpi_dat0_io_pad (s_xpi_dat0_io),
.xpi_dat1_io_pad (s_xpi_dat1_io),
.xpi_dat2_io_pad (s_xpi_dat2_io),
.xpi_dat3_io_pad (s_xpi_dat3_io),
.sdram_clk_o_pad (s_sdram_clk),
.sdram_cke_o_pad (s_sdram_cke),
.sdram_cs_n_o_pad (s_sdram_cs_n),
.sdram_ras_n_o_pad (s_sdram_ras_n),
.sdram_cas_n_o_pad (s_sdram_cas_n),
.sdram_we_n_o_pad (s_sdram_we_n),
.sdram_ba0_o_pad (s_sdram_ba[0]),
.sdram_ba1_o_pad (s_sdram_ba[1]),
.sdram_addr0_o_pad (s_sdram_addr[0]),
.sdram_addr1_o_pad (s_sdram_addr[1]),
.sdram_addr2_o_pad (s_sdram_addr[2]),
.sdram_addr3_o_pad (s_sdram_addr[3]),
.sdram_addr4_o_pad (s_sdram_addr[4]),
.sdram_addr5_o_pad (s_sdram_addr[5]),
.sdram_addr6_o_pad (s_sdram_addr[6]),
.sdram_addr7_o_pad (s_sdram_addr[7]),
.sdram_addr8_o_pad (s_sdram_addr[8]),
.sdram_addr9_o_pad (s_sdram_addr[9]),
.sdram_addr10_o_pad (s_sdram_addr[10]),
.sdram_addr11_o_pad (s_sdram_addr[11]),
.sdram_addr12_o_pad (s_sdram_addr[12]),
.sdram_dqm0_o_pad (s_sdram_dqm[0]),
.sdram_dqm1_o_pad (s_sdram_dqm[1]),
.sdram_dq0_io_pad (s_sdram_dq[0]),
.sdram_dq1_io_pad (s_sdram_dq[1]),
.sdram_dq2_io_pad (s_sdram_dq[2]),
.sdram_dq3_io_pad (s_sdram_dq[3]),
.sdram_dq4_io_pad (s_sdram_dq[4]),
.sdram_dq5_io_pad (s_sdram_dq[5]),
.sdram_dq6_io_pad (s_sdram_dq[6]),
.sdram_dq7_io_pad (s_sdram_dq[7]),
.sdram_dq8_io_pad (s_sdram_dq[8]),
.sdram_dq9_io_pad (s_sdram_dq[9]),
.sdram_dq10_io_pad (s_sdram_dq[10]),
.sdram_dq11_io_pad (s_sdram_dq[11]),
.sdram_dq12_io_pad (s_sdram_dq[12]),
.sdram_dq13_io_pad (s_sdram_dq[13]),
.sdram_dq14_io_pad (s_sdram_dq[14]),
.sdram_dq15_io_pad (s_sdram_dq[15])
`include "retrosoc_asic_tb_bindings.svh"
);
+2 -115
View File
@@ -45,121 +45,9 @@ module retrosoc_top (
assign s_clk = ext_clk_i;
assign s_rst_n = rst_n_i;
assign s_core_sel = core_sel_i;
retrosoc_asic u_retrosoc_asic (
.extclk_i_pad (s_clk),
.audclk_i_pad (),
.ext_rst_n_i_pad (s_rst_n),
`ifdef HAVE_PLL
.xi_i_pad (),
.xo_o_pad (),
`endif
`ifdef CORE_MDD
.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]),
`endif
`ifdef IP_MDD
.user_gpio_0_io_pad (),
.user_gpio_1_io_pad (),
.user_gpio_2_io_pad (),
.user_gpio_3_io_pad (),
.user_gpio_4_io_pad (),
.user_gpio_5_io_pad (),
.user_gpio_6_io_pad (),
.user_gpio_7_io_pad (),
.user_gpio_8_io_pad (),
.user_gpio_9_io_pad (),
.user_gpio_10_io_pad(),
.user_gpio_11_io_pad(),
.user_gpio_12_io_pad(),
.user_gpio_13_io_pad(),
.user_gpio_14_io_pad(),
.user_gpio_15_io_pad(),
`endif
.gpio_0_io_pad (),
.gpio_1_io_pad (),
.gpio_2_io_pad (),
.gpio_3_io_pad (),
.gpio_4_io_pad (),
.gpio_5_io_pad (),
.gpio_6_io_pad (),
.gpio_7_io_pad (),
.gpio_8_io_pad (),
.gpio_9_io_pad (),
.gpio_10_io_pad (),
.gpio_11_io_pad (),
.gpio_12_io_pad (),
.gpio_13_io_pad (),
.gpio_14_io_pad (),
.gpio_15_io_pad (),
.gpio_16_io_pad (),
.gpio_17_io_pad (),
.gpio_18_io_pad (),
.gpio_19_io_pad (),
.gpio_20_io_pad (),
.gpio_21_io_pad (s_psram_sck),
.gpio_22_io_pad (s_psram_nss0),
.gpio_23_io_pad (s_psram_dat0),
.gpio_24_io_pad (s_psram_dat1),
.gpio_25_io_pad (s_psram_dat2),
.gpio_26_io_pad (s_psram_dat3),
.gpio_27_io_pad (),
.gpio_28_io_pad (),
.gpio_29_io_pad (),
.gpio_30_io_pad (),
.gpio_31_io_pad (),
.uart0_tx_o_pad (),
.uart0_rx_i_pad (),
.xpi_sck_o_pad (s_xpi_sck_o),
.xpi_nss0_o_pad (s_xpi_nss0_o),
.xpi_nss1_o_pad (),
.xpi_nss2_o_pad (),
.xpi_nss3_o_pad (),
.xpi_dat0_io_pad (s_xpi_dat0_io),
.xpi_dat1_io_pad (s_xpi_dat1_io),
.xpi_dat2_io_pad (s_xpi_dat2_io),
.xpi_dat3_io_pad (s_xpi_dat3_io),
.sdram_clk_o_pad (),
.sdram_cke_o_pad (),
.sdram_cs_n_o_pad (),
.sdram_ras_n_o_pad (),
.sdram_cas_n_o_pad (),
.sdram_we_n_o_pad (),
.sdram_ba0_o_pad (),
.sdram_ba1_o_pad (),
.sdram_addr0_o_pad (),
.sdram_addr1_o_pad (),
.sdram_addr2_o_pad (),
.sdram_addr3_o_pad (),
.sdram_addr4_o_pad (),
.sdram_addr5_o_pad (),
.sdram_addr6_o_pad (),
.sdram_addr7_o_pad (),
.sdram_addr8_o_pad (),
.sdram_addr9_o_pad (),
.sdram_addr10_o_pad (),
.sdram_addr11_o_pad (),
.sdram_addr12_o_pad (),
.sdram_dqm0_o_pad (),
.sdram_dqm1_o_pad (),
.sdram_dq0_io_pad (),
.sdram_dq1_io_pad (),
.sdram_dq2_io_pad (),
.sdram_dq3_io_pad (),
.sdram_dq4_io_pad (),
.sdram_dq5_io_pad (),
.sdram_dq6_io_pad (),
.sdram_dq7_io_pad (),
.sdram_dq8_io_pad (),
.sdram_dq9_io_pad (),
.sdram_dq10_io_pad (),
.sdram_dq11_io_pad (),
.sdram_dq12_io_pad (),
.sdram_dq13_io_pad (),
.sdram_dq14_io_pad (),
.sdram_dq15_io_pad ()
`include "retrosoc_asic_verilator_bindings.svh"
);
QSPIFlash u_QSPIFlash (
@@ -177,5 +65,4 @@ module retrosoc_top (
.sio ({s_psram_dat3, s_psram_dat2, s_psram_dat1, s_psram_dat0})
);
endmodule
+2
View File
@@ -1,3 +1,5 @@
/top/apb4_if_bridge.sv
/top/gpio_pad_bridge.sv
/top/core_wrapper.sv
/top/retrosoc.sv
/top/retrosoc_asic.sv
+3 -3
View File
@@ -40,19 +40,19 @@ $(IVERILOG_BEHV_FLIST): $(FILELIST_STAMP) $(CONVERTED_SOC)
@mkdir -p $(@D)
python3 $(RTL_PATH)/script/gen_iverilog_filelist.py \
--mode behv --pdk $(PDK) --generated-dir $(GENERATED_FL_DIR) \
--output $@ --converted $(CONVERTED_SOC)
--pin-map-rtl-dir $(PIN_MAP_DIR)/rtl --output $@ --converted $(CONVERTED_SOC)
$(IVERILOG_NETL_FLIST): $(FILELIST_STAMP) $(NETLIST_PATH)
@mkdir -p $(@D)
python3 $(RTL_PATH)/script/gen_iverilog_filelist.py \
--mode netl --pdk $(PDK) --generated-dir $(GENERATED_FL_DIR) \
--output $@ --netlist $(NETLIST_PATH)
--pin-map-rtl-dir $(PIN_MAP_DIR)/rtl --output $@ --netlist $(NETLIST_PATH)
$(IVERILOG_POST_FLIST): $(FILELIST_STAMP) $(POST_PATH) $(SDF_PATH)
@mkdir -p $(@D)
python3 $(RTL_PATH)/script/gen_iverilog_filelist.py \
--mode post --pdk $(PDK) --generated-dir $(GENERATED_FL_DIR) \
--output $@ --netlist $(POST_PATH) --sdf $(SDF_PATH) \
--pin-map-rtl-dir $(PIN_MAP_DIR)/rtl --output $@ --netlist $(POST_PATH) --sdf $(SDF_PATH) \
--sdf-scope $(SDF_SCOPE)
convt_sv2v: $(CONVERTED_SOC)
+10
View File
@@ -0,0 +1,10 @@
# Canonical SoC Pin Map
`pin_map.json` is the single source for the Mini SoC logical pad ABI and its
ASIC, FPGA, Verilator, and RTL-testbench bindings. The generator emits
temporary SystemVerilog include files below the selected build variant; do not
edit generated files.
The map intentionally does not contain FPGA package locations. Board-level
locations remain owned by the FPGA constraint file. Validate changes with
`make check-pin-map` and the pin-map tests before running a regression.
+290
View File
@@ -0,0 +1,290 @@
#!/usr/bin/env python3
"""Generate SoC pad declarations and platform bindings from one JSON map."""
from __future__ import annotations
import argparse
import json
import os
import re
import tempfile
from dataclasses import dataclass
from pathlib import Path
from typing import Any
VALID_FEATURES = {"HAVE_PLL", "CORE_MDD", "IP_MDD"}
VALID_KINDS = {
"full",
"schmitt_input",
"sdram_dq",
"tri_input",
"tri_output",
"xpi_data",
"xtal",
}
REQUIRED_PROFILES = {"fpga_mini", "tb", "verilator"}
CONNECTION_RE = re.compile(r"(?:[A-Za-z_][A-Za-z0-9_]*)(?:\[[0-9]+\])?$")
CONSTANT_RE = re.compile(r"[0-9]+'[bBdDhHoO][0-9a-fA-F_xXzZ]+$")
@dataclass(frozen=True)
class Pad:
name: str
direction: str
feature: str | None
kind: str
index: int | None
signal: str | None
interface: str | None
peer: str | None
bind: bool
def atomic_write(path: Path, content: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
if path.exists() and path.read_text(encoding="utf-8") == content:
return
descriptor, temporary_name = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent)
try:
with os.fdopen(descriptor, "w", encoding="utf-8", newline="\n") as output:
output.write(content)
os.replace(temporary_name, path)
except BaseException:
Path(temporary_name).unlink(missing_ok=True)
raise
def require_string(value: Any, field: str) -> str:
if not isinstance(value, str) or not value:
raise ValueError(f"{field} must be a non-empty string")
return value
def parse_feature(value: Any, field: str) -> str | None:
if value is None:
return None
feature = require_string(value, field)
if feature not in VALID_FEATURES:
raise ValueError(f"{field} must be one of {sorted(VALID_FEATURES)}")
return feature
def format_template(value: str | None, index: int | None, field: str) -> str | None:
if value is None:
return None
if not isinstance(value, str):
raise ValueError(f"{field} must be a string")
if "{index}" in value:
if index is None:
raise ValueError(f"{field} uses {{index}} without an indexed pad")
return value.format(index=index)
return value
def parse_pad(entry: dict[str, Any], defaults: dict[str, Any], index: int | None) -> Pad:
data = {**defaults, **entry}
name = require_string(format_template(data.get("name"), index, "pad.name"), "pad.name")
direction = require_string(data.get("direction"), f"{name}.direction")
if direction not in {"input", "output", "inout"}:
raise ValueError(f"{name}.direction must be input, output, or inout")
kind = require_string(data.get("kind"), f"{name}.kind")
if kind not in VALID_KINDS:
raise ValueError(f"{name}.kind is not supported")
feature = parse_feature(data.get("feature"), f"{name}.feature")
signal = format_template(data.get("signal"), index, f"{name}.signal")
interface = format_template(data.get("interface"), index, f"{name}.interface")
peer = format_template(data.get("peer"), index, f"{name}.peer")
bind = data.get("bind", True)
if not isinstance(bind, bool):
raise ValueError(f"{name}.bind must be boolean")
if kind in {"tri_input", "schmitt_input", "tri_output"} and signal is None:
raise ValueError(f"{name}.signal is required for {kind}")
if kind == "full" and (interface is None or index is None):
raise ValueError(f"{name} requires an interface and index")
if kind in {"xpi_data", "sdram_dq"} and index is None:
raise ValueError(f"{name} requires an index")
if kind == "xtal" and bind and (signal is None or peer is None):
raise ValueError(f"{name} requires signal and peer")
return Pad(name, direction, feature, kind, index, signal, interface, peer, bind)
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"}}
ports = group.get("ports")
if ports is not None:
if not isinstance(ports, list) or not ports:
raise ValueError(f"pads[{index}].ports must be a non-empty list")
if not all(isinstance(port, dict) for port in ports):
raise ValueError(f"pads[{index}].ports entries must be objects")
return [parse_pad(port, defaults, None) for port in ports]
count = group.get("count")
if not isinstance(count, int) or count <= 0:
raise ValueError(f"pads[{index}].count must be a positive integer")
prefix = require_string(group.get("prefix"), f"pads[{index}].prefix")
suffix = require_string(group.get("suffix"), f"pads[{index}].suffix")
return [
parse_pad({"name": f"{prefix}{pad_index}{suffix}"}, defaults, pad_index)
for pad_index in range(count)
]
def validate_connection(value: Any, field: str) -> str | None:
if value is None:
return None
connection = require_string(value, field)
if CONNECTION_RE.fullmatch(connection) or CONSTANT_RE.fullmatch(connection):
return connection
raise ValueError(f"{field} must be a signal, bit-select, constant, or null")
def read_map(path: Path) -> tuple[list[Pad], dict[str, dict[str, str | None]]]:
with path.open(encoding="utf-8") as source:
document = json.load(source)
if document.get("schema_version") != 1:
raise ValueError("schema_version must be 1")
groups = document.get("pads")
if not isinstance(groups, list) or not groups:
raise ValueError("pads must be a non-empty list")
pads: list[Pad] = []
for index, group in enumerate(groups):
expanded = expand_group(group, index)
if len(expanded) == 0:
raise ValueError(f"pads[{index}] does not expand to any pads")
pads.extend(expanded)
names = [pad.name for pad in pads]
if len(names) != len(set(names)):
raise ValueError("pad names must be unique")
known_names = set(names)
for pad in pads:
if pad.peer is not None and pad.peer not in known_names:
raise ValueError(f"{pad.name}.peer is not a known pad")
profiles = document.get("profiles")
if not isinstance(profiles, dict) or set(profiles) != REQUIRED_PROFILES:
raise ValueError(f"profiles must contain exactly {sorted(REQUIRED_PROFILES)}")
normalized_profiles: dict[str, dict[str, str | None]] = {}
for profile, profile_data in profiles.items():
if not isinstance(profile_data, dict):
raise ValueError(f"profiles.{profile} must be an object")
bindings = profile_data.get("bindings", {})
if not isinstance(bindings, dict):
raise ValueError(f"profiles.{profile}.bindings must be an object")
if any(name not in known_names for name in bindings):
raise ValueError(f"profiles.{profile} contains an unknown pad")
normalized_profiles[profile] = {
name: validate_connection(value, f"profiles.{profile}.bindings.{name}")
for name, value in bindings.items()
}
return pads, normalized_profiles
def wrap_feature(pad: Pad, line: str) -> list[str]:
if pad.feature is None:
return [line]
return [f"`ifdef {pad.feature}", line, "`endif"]
def render_ports(pads: list[Pad]) -> str:
lines = ["// Generated by rtl/mini/pin_map/generate_pin_map.py; do not edit."]
for index, pad in enumerate(pads):
suffix = "," if index != len(pads) - 1 else ""
lines.extend(wrap_feature(pad, f" {pad.direction} {pad.name}{suffix}"))
return "\n".join(lines) + "\n"
def render_pad_instance(pad: Pad) -> str | None:
instance = f"u_{pad.name}"
if pad.kind == "tri_input":
return (
f" tc_io_tri_pad {instance} (.pad({pad.name}), .c2p(1'b0), .c2p_en(1'b0), "
f".p2c({pad.signal}));"
)
if pad.kind == "schmitt_input":
return (
f" tc_io_tri_schmitt_pad {instance} (.pad({pad.name}), .c2p(1'b0), "
f".c2p_en(1'b0), .p2c({pad.signal}));"
)
if pad.kind == "tri_output":
return (
f" tc_io_tri_pad {instance} (.pad({pad.name}), .c2p({pad.signal}), .c2p_en(1'b1), "
".p2c());"
)
if pad.kind == "full":
return (
f" tc_io_tri_full_pad {instance} (.pad({pad.name}), .c2p({pad.interface}.do_o[{pad.index}]), "
f".c2p_en({pad.interface}.oe_o[{pad.index}]), .p2c({pad.interface}.di_i[{pad.index}]), "
f".cs({pad.interface}.cs_o[{pad.index}]), .pu({pad.interface}.pu_o[{pad.index}]), "
f".pd({pad.interface}.pd_o[{pad.index}]));"
)
if pad.kind == "xpi_data":
return (
f" tc_io_tri_pad {instance} (.pad({pad.name}), .c2p(u_xpi_if.io_do_o[{pad.index}]), "
f".c2p_en(u_xpi_if.io_oe_o[{pad.index}]), .p2c(u_xpi_if.io_di_i[{pad.index}]));"
)
if pad.kind == "sdram_dq":
return (
f" tc_io_tri_pad {instance} (.pad({pad.name}), .c2p(u_sdram_if.dq_o[{pad.index}]), "
f".c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[{pad.index}]));"
)
if pad.kind == "xtal" and pad.bind:
return (
f" tc_io_xtl_pad u_xtal_io_pad (.xi_pad({pad.name}), .xo_pad({pad.peer}), "
f".en(1'b1), .clk({pad.signal}));"
)
return None
def render_pad_bindings(pads: list[Pad]) -> str:
lines = ["// Generated by rtl/mini/pin_map/generate_pin_map.py; do not edit."]
for pad in pads:
line = render_pad_instance(pad)
if line is not None:
lines.extend(wrap_feature(pad, line))
return "\n".join(lines) + "\n"
def render_profile_bindings(pads: list[Pad], bindings: dict[str, str | None]) -> str:
lines = ["// Generated by rtl/mini/pin_map/generate_pin_map.py; do not edit."]
for index, pad in enumerate(pads):
connection = bindings.get(pad.name)
suffix = "," if index != len(pads) - 1 else ""
value = "" if connection is None else connection
lines.extend(wrap_feature(pad, f" .{pad.name}({value}){suffix}"))
return "\n".join(lines) + "\n"
def generate(map_path: Path, output_dir: Path) -> None:
pads, profiles = read_map(map_path)
rtl_dir = output_dir / "rtl"
atomic_write(rtl_dir / "retrosoc_asic_ports.svh", render_ports(pads))
atomic_write(rtl_dir / "retrosoc_asic_pad_bindings.svh", render_pad_bindings(pads))
for profile, bindings in profiles.items():
atomic_write(
rtl_dir / f"retrosoc_asic_{profile}_bindings.svh",
render_profile_bindings(pads, bindings),
)
atomic_write(output_dir / "pin_map.fl", f"+incdir+{rtl_dir}\n")
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--map", required=True, type=Path)
parser.add_argument("--output-dir", type=Path)
parser.add_argument("--check", action="store_true", help="validate only; write nothing")
arguments = parser.parse_args()
try:
if arguments.check:
read_map(arguments.map)
else:
if arguments.output_dir is None:
parser.error("--output-dir is required unless --check is used")
generate(arguments.map, arguments.output_dir)
except (OSError, ValueError, json.JSONDecodeError) as error:
parser.error(str(error))
return 0
if __name__ == "__main__":
raise SystemExit(main())
+314
View File
@@ -0,0 +1,314 @@
{
"schema_version": 1,
"pads": [
{
"kind": "tri_input",
"direction": "inout",
"ports": [
{"name": "extclk_i_pad", "signal": "s_ext_clk"},
{"name": "audclk_i_pad", "signal": "s_aud_clk"}
]
},
{
"kind": "schmitt_input",
"direction": "inout",
"ports": [
{"name": "ext_rst_n_i_pad", "signal": "s_ext_rst_n"}
]
},
{
"kind": "xtal",
"feature": "HAVE_PLL",
"ports": [
{"name": "xi_i_pad", "direction": "input", "signal": "s_xtal_io", "peer": "xo_o_pad"},
{"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",
"feature": "IP_MDD",
"prefix": "user_gpio_",
"suffix": "_io_pad",
"count": 16,
"interface": "u_user_gpio_if"
},
{
"kind": "full",
"direction": "inout",
"prefix": "gpio_",
"suffix": "_io_pad",
"count": 32,
"interface": "u_gpio_if"
},
{
"kind": "tri_output",
"direction": "output",
"ports": [
{"name": "uart0_tx_o_pad", "signal": "u_uart0_if.tx_o"}
]
},
{
"kind": "tri_input",
"direction": "inout",
"ports": [
{"name": "uart0_rx_i_pad", "signal": "u_uart0_if.rx_i"}
]
},
{
"kind": "tri_output",
"direction": "output",
"ports": [
{"name": "xpi_sck_o_pad", "signal": "u_xpi_if.sck_o"}
]
},
{
"kind": "tri_output",
"direction": "output",
"prefix": "xpi_nss",
"suffix": "_o_pad",
"count": 4,
"signal": "u_xpi_if.nss_o[{index}]"
},
{
"kind": "xpi_data",
"direction": "inout",
"prefix": "xpi_dat",
"suffix": "_io_pad",
"count": 4
},
{
"kind": "tri_output",
"direction": "output",
"ports": [
{"name": "sdram_clk_o_pad", "signal": "u_sdram_if.clk_o"},
{"name": "sdram_cke_o_pad", "signal": "u_sdram_if.cke_o"},
{"name": "sdram_cs_n_o_pad", "signal": "u_sdram_if.cs_n_o"},
{"name": "sdram_ras_n_o_pad", "signal": "u_sdram_if.ras_n_o"},
{"name": "sdram_cas_n_o_pad", "signal": "u_sdram_if.cas_n_o"},
{"name": "sdram_we_n_o_pad", "signal": "u_sdram_if.we_n_o"}
]
},
{
"kind": "tri_output",
"direction": "output",
"prefix": "sdram_ba",
"suffix": "_o_pad",
"count": 2,
"signal": "u_sdram_if.ba_o[{index}]"
},
{
"kind": "tri_output",
"direction": "output",
"prefix": "sdram_addr",
"suffix": "_o_pad",
"count": 13,
"signal": "u_sdram_if.addr_o[{index}]"
},
{
"kind": "tri_output",
"direction": "output",
"prefix": "sdram_dqm",
"suffix": "_o_pad",
"count": 2,
"signal": "u_sdram_if.dqm_o[{index}]"
},
{
"kind": "sdram_dq",
"direction": "inout",
"prefix": "sdram_dq",
"suffix": "_io_pad",
"count": 16
}
],
"profiles": {
"fpga_mini": {
"bindings": {
"extclk_i_pad": "s_sys_clk",
"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",
"gpio_3_io_pad": "i2c_scl_io",
"gpio_4_io_pad": "i2c_sda_io",
"gpio_5_io_pad": "pwm_2_o",
"gpio_6_io_pad": "spisd_sck_o",
"gpio_7_io_pad": "spisd_nss_o",
"gpio_8_io_pad": "spisd_mosi_o",
"gpio_9_io_pad": "spisd_miso_i",
"gpio_10_io_pad": "i2s_mclk_o",
"gpio_11_io_pad": "i2s_sclk_o",
"gpio_12_io_pad": "i2s_lrck_o",
"gpio_13_io_pad": "i2s_dacdat_o",
"gpio_14_io_pad": "i2s_adcdat_i",
"gpio_21_io_pad": "psram_sck_o",
"gpio_22_io_pad": "psram_nss0_o",
"gpio_23_io_pad": "psram_dat0_io",
"gpio_24_io_pad": "psram_dat1_io",
"gpio_25_io_pad": "psram_dat2_io",
"gpio_26_io_pad": "psram_dat3_io",
"gpio_30_io_pad": "gpio_io30",
"uart0_tx_o_pad": "uart0_tx_o",
"uart0_rx_i_pad": "uart0_rx_i",
"xpi_sck_o_pad": "xpi_sck_o",
"xpi_nss0_o_pad": "xpi_nss0_o",
"xpi_dat0_io_pad": "xpi_dat0_io",
"xpi_dat1_io_pad": "xpi_dat1_io",
"xpi_dat2_io_pad": "xpi_dat2_io",
"xpi_dat3_io_pad": "xpi_dat3_io",
"sdram_clk_o_pad": "sdram_clk_o",
"sdram_cke_o_pad": "sdram_cke_o",
"sdram_cs_n_o_pad": "sdram_cs_n_o",
"sdram_ras_n_o_pad": "sdram_ras_n_o",
"sdram_cas_n_o_pad": "sdram_cas_n_o",
"sdram_we_n_o_pad": "sdram_we_n_o",
"sdram_ba0_o_pad": "sdram_ba0_o",
"sdram_ba1_o_pad": "sdram_ba1_o",
"sdram_addr0_o_pad": "sdram_addr0_o",
"sdram_addr1_o_pad": "sdram_addr1_o",
"sdram_addr2_o_pad": "sdram_addr2_o",
"sdram_addr3_o_pad": "sdram_addr3_o",
"sdram_addr4_o_pad": "sdram_addr4_o",
"sdram_addr5_o_pad": "sdram_addr5_o",
"sdram_addr6_o_pad": "sdram_addr6_o",
"sdram_addr7_o_pad": "sdram_addr7_o",
"sdram_addr8_o_pad": "sdram_addr8_o",
"sdram_addr9_o_pad": "sdram_addr9_o",
"sdram_addr10_o_pad": "sdram_addr10_o",
"sdram_addr11_o_pad": "sdram_addr11_o",
"sdram_addr12_o_pad": "sdram_addr12_o",
"sdram_dqm0_o_pad": "sdram_dqm0_o",
"sdram_dqm1_o_pad": "sdram_dqm1_o",
"sdram_dq0_io_pad": "sdram_dq0_io",
"sdram_dq1_io_pad": "sdram_dq1_io",
"sdram_dq2_io_pad": "sdram_dq2_io",
"sdram_dq3_io_pad": "sdram_dq3_io",
"sdram_dq4_io_pad": "sdram_dq4_io",
"sdram_dq5_io_pad": "sdram_dq5_io",
"sdram_dq6_io_pad": "sdram_dq6_io",
"sdram_dq7_io_pad": "sdram_dq7_io",
"sdram_dq8_io_pad": "sdram_dq8_io",
"sdram_dq9_io_pad": "sdram_dq9_io",
"sdram_dq10_io_pad": "sdram_dq10_io",
"sdram_dq11_io_pad": "sdram_dq11_io",
"sdram_dq12_io_pad": "sdram_dq12_io",
"sdram_dq13_io_pad": "sdram_dq13_io",
"sdram_dq14_io_pad": "sdram_dq14_io",
"sdram_dq15_io_pad": "sdram_dq15_io"
}
},
"verilator": {
"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",
"gpio_24_io_pad": "s_psram_dat1",
"gpio_25_io_pad": "s_psram_dat2",
"gpio_26_io_pad": "s_psram_dat3",
"xpi_sck_o_pad": "s_xpi_sck_o",
"xpi_nss0_o_pad": "s_xpi_nss0_o",
"xpi_dat0_io_pad": "s_xpi_dat0_io",
"xpi_dat1_io_pad": "s_xpi_dat1_io",
"xpi_dat2_io_pad": "s_xpi_dat2_io",
"xpi_dat3_io_pad": "s_xpi_dat3_io"
}
},
"tb": {
"bindings": {
"extclk_i_pad": "s_ext_clk",
"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]",
"user_gpio_0_io_pad": "s_user_gpio_0_io",
"gpio_0_io_pad": "s_gpio_0_io",
"gpio_1_io_pad": "s_gpio_1_io",
"gpio_7_io_pad": "s_i2c0_scl_io",
"gpio_8_io_pad": "s_i2c0_sda_io",
"gpio_21_io_pad": "s_psram_sck",
"gpio_22_io_pad": "s_psram_nss0",
"gpio_23_io_pad": "s_psram_dat0",
"gpio_24_io_pad": "s_psram_dat1",
"gpio_25_io_pad": "s_psram_dat2",
"gpio_26_io_pad": "s_psram_dat3",
"gpio_27_io_pad": "s_psram_nss1",
"uart0_tx_o_pad": "s_uart0_tx",
"uart0_rx_i_pad": "s_uart0_rx",
"xpi_sck_o_pad": "s_xpi_sck_o",
"xpi_nss0_o_pad": "s_xpi_nss0_o",
"xpi_nss1_o_pad": "s_xpi_nss1_o",
"xpi_nss2_o_pad": "s_xpi_nss2_o",
"xpi_dat0_io_pad": "s_xpi_dat0_io",
"xpi_dat1_io_pad": "s_xpi_dat1_io",
"xpi_dat2_io_pad": "s_xpi_dat2_io",
"xpi_dat3_io_pad": "s_xpi_dat3_io",
"sdram_clk_o_pad": "s_sdram_clk",
"sdram_cke_o_pad": "s_sdram_cke",
"sdram_cs_n_o_pad": "s_sdram_cs_n",
"sdram_ras_n_o_pad": "s_sdram_ras_n",
"sdram_cas_n_o_pad": "s_sdram_cas_n",
"sdram_we_n_o_pad": "s_sdram_we_n",
"sdram_ba0_o_pad": "s_sdram_ba[0]",
"sdram_ba1_o_pad": "s_sdram_ba[1]",
"sdram_addr0_o_pad": "s_sdram_addr[0]",
"sdram_addr1_o_pad": "s_sdram_addr[1]",
"sdram_addr2_o_pad": "s_sdram_addr[2]",
"sdram_addr3_o_pad": "s_sdram_addr[3]",
"sdram_addr4_o_pad": "s_sdram_addr[4]",
"sdram_addr5_o_pad": "s_sdram_addr[5]",
"sdram_addr6_o_pad": "s_sdram_addr[6]",
"sdram_addr7_o_pad": "s_sdram_addr[7]",
"sdram_addr8_o_pad": "s_sdram_addr[8]",
"sdram_addr9_o_pad": "s_sdram_addr[9]",
"sdram_addr10_o_pad": "s_sdram_addr[10]",
"sdram_addr11_o_pad": "s_sdram_addr[11]",
"sdram_addr12_o_pad": "s_sdram_addr[12]",
"sdram_dqm0_o_pad": "s_sdram_dqm[0]",
"sdram_dqm1_o_pad": "s_sdram_dqm[1]",
"sdram_dq0_io_pad": "s_sdram_dq[0]",
"sdram_dq1_io_pad": "s_sdram_dq[1]",
"sdram_dq2_io_pad": "s_sdram_dq[2]",
"sdram_dq3_io_pad": "s_sdram_dq[3]",
"sdram_dq4_io_pad": "s_sdram_dq[4]",
"sdram_dq5_io_pad": "s_sdram_dq[5]",
"sdram_dq6_io_pad": "s_sdram_dq[6]",
"sdram_dq7_io_pad": "s_sdram_dq[7]",
"sdram_dq8_io_pad": "s_sdram_dq[8]",
"sdram_dq9_io_pad": "s_sdram_dq[9]",
"sdram_dq10_io_pad": "s_sdram_dq[10]",
"sdram_dq11_io_pad": "s_sdram_dq[11]",
"sdram_dq12_io_pad": "s_sdram_dq[12]",
"sdram_dq13_io_pad": "s_sdram_dq[13]",
"sdram_dq14_io_pad": "s_sdram_dq[14]",
"sdram_dq15_io_pad": "s_sdram_dq[15]"
}
}
}
}
+5
View File
@@ -19,6 +19,7 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--mode", required=True, choices=("behv", "netl", "post"))
parser.add_argument("--pdk", required=True)
parser.add_argument("--generated-dir", type=Path, default=DEFAULT_GENERATED_DIR)
parser.add_argument("--pin-map-rtl-dir", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--converted", type=Path)
parser.add_argument("--netlist", type=Path)
@@ -60,6 +61,10 @@ def main() -> int:
base_names = ["def.fl", "sys_def.fl", "inc.fl", "tb.fl"]
base = parse_filelists(generated_dir / name for name in base_names)
base.options.insert(0, "+timescale+1ns/1ps")
pin_map_rtl_dir = args.pin_map_rtl_dir.resolve()
if not pin_map_rtl_dir.is_dir():
raise FileNotFoundError(f"pin-map RTL directory not found: {pin_map_rtl_dir}")
base.incdirs.append(pin_map_rtl_dir)
if args.mode == "behv":
base.files.append(_require(args.converted, "converted behavioral RTL"))
+28
View File
@@ -0,0 +1,28 @@
// 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 FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
module apb4_if_bridge (
apb4_pure_if.slave apb_pure,
apb4_if.master timed
);
assign timed.paddr = apb_pure.paddr;
assign timed.pprot = apb_pure.pprot;
assign timed.psel = apb_pure.psel;
assign timed.penable = apb_pure.penable;
assign timed.pwrite = apb_pure.pwrite;
assign timed.pwdata = apb_pure.pwdata;
assign timed.pstrb = apb_pure.pstrb;
assign apb_pure.pready = timed.pready;
assign apb_pure.prdata = timed.prdata;
assign apb_pure.pslverr = timed.pslverr;
endmodule
+23
View File
@@ -0,0 +1,23 @@
// 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 FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
module gpio_pad_bridge (
gpio_if.pad inner,
gpio_if.soc_pad outer
);
assign outer.oe_o = inner.oe_o;
assign outer.cs_o = inner.cs_o;
assign outer.pu_o = inner.pu_o;
assign outer.pd_o = inner.pd_o;
assign outer.do_o = inner.do_o;
assign inner.di_i = outer.di_i;
endmodule
+40 -109
View File
@@ -70,116 +70,47 @@ module ip_apb_wrapper (
`endif
// verilog_format: on
// archinfo
assign u_archinfo_apb_if.paddr = u_archinfo_apb_pure_if.paddr;
assign u_archinfo_apb_if.pprot = u_archinfo_apb_pure_if.pprot;
assign u_archinfo_apb_if.psel = u_archinfo_apb_pure_if.psel;
assign u_archinfo_apb_if.penable = u_archinfo_apb_pure_if.penable;
assign u_archinfo_apb_if.pwrite = u_archinfo_apb_pure_if.pwrite;
assign u_archinfo_apb_if.pwdata = u_archinfo_apb_pure_if.pwdata;
assign u_archinfo_apb_if.pstrb = u_archinfo_apb_pure_if.pstrb;
assign u_archinfo_apb_pure_if.pready = u_archinfo_apb_if.pready;
assign u_archinfo_apb_pure_if.prdata = u_archinfo_apb_if.prdata;
assign u_archinfo_apb_pure_if.pslverr = u_archinfo_apb_if.pslverr;
// rng
assign u_rng_apb_if.paddr = u_rng_apb_pure_if.paddr;
assign u_rng_apb_if.pprot = u_rng_apb_pure_if.pprot;
assign u_rng_apb_if.psel = u_rng_apb_pure_if.psel;
assign u_rng_apb_if.penable = u_rng_apb_pure_if.penable;
assign u_rng_apb_if.pwrite = u_rng_apb_pure_if.pwrite;
assign u_rng_apb_if.pwdata = u_rng_apb_pure_if.pwdata;
assign u_rng_apb_if.pstrb = u_rng_apb_pure_if.pstrb;
assign u_rng_apb_pure_if.pready = u_rng_apb_if.pready;
assign u_rng_apb_pure_if.prdata = u_rng_apb_if.prdata;
assign u_rng_apb_pure_if.pslverr = u_rng_apb_if.pslverr;
// uart1
assign u_uart1_apb_if.paddr = u_uart1_apb_pure_if.paddr;
assign u_uart1_apb_if.pprot = u_uart1_apb_pure_if.pprot;
assign u_uart1_apb_if.psel = u_uart1_apb_pure_if.psel;
assign u_uart1_apb_if.penable = u_uart1_apb_pure_if.penable;
assign u_uart1_apb_if.pwrite = u_uart1_apb_pure_if.pwrite;
assign u_uart1_apb_if.pwdata = u_uart1_apb_pure_if.pwdata;
assign u_uart1_apb_if.pstrb = u_uart1_apb_pure_if.pstrb;
assign u_uart1_apb_pure_if.pready = u_uart1_apb_if.pready;
assign u_uart1_apb_pure_if.prdata = u_uart1_apb_if.prdata;
assign u_uart1_apb_pure_if.pslverr = u_uart1_apb_if.pslverr;
// pwm
assign u_pwm_apb_if.paddr = u_pwm_apb_pure_if.paddr;
assign u_pwm_apb_if.pprot = u_pwm_apb_pure_if.pprot;
assign u_pwm_apb_if.psel = u_pwm_apb_pure_if.psel;
assign u_pwm_apb_if.penable = u_pwm_apb_pure_if.penable;
assign u_pwm_apb_if.pwrite = u_pwm_apb_pure_if.pwrite;
assign u_pwm_apb_if.pwdata = u_pwm_apb_pure_if.pwdata;
assign u_pwm_apb_if.pstrb = u_pwm_apb_pure_if.pstrb;
assign u_pwm_apb_pure_if.pready = u_pwm_apb_if.pready;
assign u_pwm_apb_pure_if.prdata = u_pwm_apb_if.prdata;
assign u_pwm_apb_pure_if.pslverr = u_pwm_apb_if.pslverr;
// ps2
assign u_ps2_apb_if.paddr = u_ps2_apb_pure_if.paddr;
assign u_ps2_apb_if.pprot = u_ps2_apb_pure_if.pprot;
assign u_ps2_apb_if.psel = u_ps2_apb_pure_if.psel;
assign u_ps2_apb_if.penable = u_ps2_apb_pure_if.penable;
assign u_ps2_apb_if.pwrite = u_ps2_apb_pure_if.pwrite;
assign u_ps2_apb_if.pwdata = u_ps2_apb_pure_if.pwdata;
assign u_ps2_apb_if.pstrb = u_ps2_apb_pure_if.pstrb;
assign u_ps2_apb_pure_if.pready = u_ps2_apb_if.pready;
assign u_ps2_apb_pure_if.prdata = u_ps2_apb_if.prdata;
assign u_ps2_apb_pure_if.pslverr = u_ps2_apb_if.pslverr;
// rtc
assign u_rtc_apb_if.paddr = u_rtc_apb_pure_if.paddr;
assign u_rtc_apb_if.pprot = u_rtc_apb_pure_if.pprot;
assign u_rtc_apb_if.psel = u_rtc_apb_pure_if.psel;
assign u_rtc_apb_if.penable = u_rtc_apb_pure_if.penable;
assign u_rtc_apb_if.pwrite = u_rtc_apb_pure_if.pwrite;
assign u_rtc_apb_if.pwdata = u_rtc_apb_pure_if.pwdata;
assign u_rtc_apb_if.pstrb = u_rtc_apb_pure_if.pstrb;
assign u_rtc_apb_pure_if.pready = u_rtc_apb_if.pready;
assign u_rtc_apb_pure_if.prdata = u_rtc_apb_if.prdata;
assign u_rtc_apb_pure_if.pslverr = u_rtc_apb_if.pslverr;
// wdg
assign u_wdg_apb_if.paddr = u_wdg_apb_pure_if.paddr;
assign u_wdg_apb_if.pprot = u_wdg_apb_pure_if.pprot;
assign u_wdg_apb_if.psel = u_wdg_apb_pure_if.psel;
assign u_wdg_apb_if.penable = u_wdg_apb_pure_if.penable;
assign u_wdg_apb_if.pwrite = u_wdg_apb_pure_if.pwrite;
assign u_wdg_apb_if.pwdata = u_wdg_apb_pure_if.pwdata;
assign u_wdg_apb_if.pstrb = u_wdg_apb_pure_if.pstrb;
assign u_wdg_apb_pure_if.pready = u_wdg_apb_if.pready;
assign u_wdg_apb_pure_if.prdata = u_wdg_apb_if.prdata;
assign u_wdg_apb_pure_if.pslverr = u_wdg_apb_if.pslverr;
// crc
assign u_crc_apb_if.paddr = u_crc_apb_pure_if.paddr;
assign u_crc_apb_if.pprot = u_crc_apb_pure_if.pprot;
assign u_crc_apb_if.psel = u_crc_apb_pure_if.psel;
assign u_crc_apb_if.penable = u_crc_apb_pure_if.penable;
assign u_crc_apb_if.pwrite = u_crc_apb_pure_if.pwrite;
assign u_crc_apb_if.pwdata = u_crc_apb_pure_if.pwdata;
assign u_crc_apb_if.pstrb = u_crc_apb_pure_if.pstrb;
assign u_crc_apb_pure_if.pready = u_crc_apb_if.pready;
assign u_crc_apb_pure_if.prdata = u_crc_apb_if.prdata;
assign u_crc_apb_pure_if.pslverr = u_crc_apb_if.pslverr;
// tmr
assign u_tmr_apb_if.paddr = u_tmr_apb_pure_if.paddr;
assign u_tmr_apb_if.pprot = u_tmr_apb_pure_if.pprot;
assign u_tmr_apb_if.psel = u_tmr_apb_pure_if.psel;
assign u_tmr_apb_if.penable = u_tmr_apb_pure_if.penable;
assign u_tmr_apb_if.pwrite = u_tmr_apb_pure_if.pwrite;
assign u_tmr_apb_if.pwdata = u_tmr_apb_pure_if.pwdata;
assign u_tmr_apb_if.pstrb = u_tmr_apb_pure_if.pstrb;
assign u_tmr_apb_pure_if.pready = u_tmr_apb_if.pready;
assign u_tmr_apb_pure_if.prdata = u_tmr_apb_if.prdata;
assign u_tmr_apb_pure_if.pslverr = u_tmr_apb_if.pslverr;
apb4_if_bridge u_archinfo_apb_bridge (
.apb_pure(u_archinfo_apb_pure_if),
.timed (u_archinfo_apb_if)
);
apb4_if_bridge u_rng_apb_bridge (
.apb_pure(u_rng_apb_pure_if),
.timed (u_rng_apb_if)
);
apb4_if_bridge u_uart1_apb_bridge (
.apb_pure(u_uart1_apb_pure_if),
.timed (u_uart1_apb_if)
);
apb4_if_bridge u_pwm_apb_bridge (
.apb_pure(u_pwm_apb_pure_if),
.timed (u_pwm_apb_if)
);
apb4_if_bridge u_ps2_apb_bridge (
.apb_pure(u_ps2_apb_pure_if),
.timed (u_ps2_apb_if)
);
apb4_if_bridge u_rtc_apb_bridge (
.apb_pure(u_rtc_apb_pure_if),
.timed (u_rtc_apb_if)
);
apb4_if_bridge u_wdg_apb_bridge (
.apb_pure(u_wdg_apb_pure_if),
.timed (u_wdg_apb_if)
);
apb4_if_bridge u_crc_apb_bridge (
.apb_pure(u_crc_apb_pure_if),
.timed (u_crc_apb_if)
);
apb4_if_bridge u_tmr_apb_bridge (
.apb_pure(u_tmr_apb_pure_if),
.timed (u_tmr_apb_if)
);
`ifdef IP_MDD
assign u_user_ip_apb_if.paddr = u_user_ip_apb_pure_if.paddr;
assign u_user_ip_apb_if.pprot = u_user_ip_apb_pure_if.pprot;
assign u_user_ip_apb_if.psel = u_user_ip_apb_pure_if.psel;
assign u_user_ip_apb_if.penable = u_user_ip_apb_pure_if.penable;
assign u_user_ip_apb_if.pwrite = u_user_ip_apb_pure_if.pwrite;
assign u_user_ip_apb_if.pwdata = u_user_ip_apb_pure_if.pwdata;
assign u_user_ip_apb_if.pstrb = u_user_ip_apb_pure_if.pstrb;
assign u_user_ip_apb_pure_if.pready = u_user_ip_apb_if.pready;
assign u_user_ip_apb_pure_if.prdata = u_user_ip_apb_if.prdata;
assign u_user_ip_apb_pure_if.pslverr = u_user_ip_apb_if.pslverr;
apb4_if_bridge u_user_ip_apb_bridge (
.apb_pure(u_user_ip_apb_pure_if),
.timed (u_user_ip_apb_if)
);
`endif
// verilog_format: off
+6 -12
View File
@@ -28,12 +28,7 @@ module retrosoc (
`ifdef HAVE_SRAM_IF
ram_if.master ram,
`endif
output logic [31:0] gpio_oe_o,
output logic [31:0] gpio_cs_o,
output logic [31:0] gpio_pu_o,
output logic [31:0] gpio_pd_o,
output logic [31:0] gpio_do_o,
input logic [31:0] gpio_di_i,
gpio_if.soc_pad gpio,
uart_if.dut uart0,
xpi_if.dut xpi,
sdram_if.dut sdram
@@ -73,6 +68,11 @@ module retrosoc (
logic [ 3:0] s_bus_fault_wstrb;
logic s_bus_fault_reserved;
gpio_pad_bridge u_gpio_pad_bridge (
.inner(u_gpio_if),
.outer(gpio)
);
`ifdef CORE_MDD
assign u_sysctrl_if.core_sel_i = core_sel_i;
`else
@@ -122,12 +122,6 @@ module retrosoc (
// | 30 | opipsram_dat7_io_pad | __NONE_FUNC__ |
// | 31 | opipsram_dqs_o_pad | __NONE_FUNC__ |
// =====================================================
assign gpio_oe_o = u_gpio_if.oe_o;
assign gpio_cs_o = u_gpio_if.cs_o;
assign gpio_pu_o = u_gpio_if.pu_o;
assign gpio_pd_o = u_gpio_if.pd_o;
assign gpio_do_o = u_gpio_if.do_o;
assign u_gpio_if.di_i = gpio_di_i;
// GPIO0 FUNC0
// pad0
assign u_uart1_if.rx_i = u_gpio_if.di_i[0];
+10 -262
View File
@@ -5,135 +5,15 @@
// 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.
// NOTE: need to focus on the port dir
`include "gpio_define.svh"
`include "mdd_config.svh"
module retrosoc_asic (
inout extclk_i_pad,
inout audclk_i_pad,
inout ext_rst_n_i_pad,
`ifdef HAVE_PLL
input xi_i_pad,
output xo_o_pad,
`endif
`ifdef CORE_MDD
inout core_sel_0_i_pad,
inout core_sel_1_i_pad,
inout core_sel_2_i_pad,
inout core_sel_3_i_pad,
inout core_sel_4_i_pad,
`endif
`ifdef IP_MDD
inout user_gpio_0_io_pad,
inout user_gpio_1_io_pad,
inout user_gpio_2_io_pad,
inout user_gpio_3_io_pad,
inout user_gpio_4_io_pad,
inout user_gpio_5_io_pad,
inout user_gpio_6_io_pad,
inout user_gpio_7_io_pad,
inout user_gpio_8_io_pad,
inout user_gpio_9_io_pad,
inout user_gpio_10_io_pad,
inout user_gpio_11_io_pad,
inout user_gpio_12_io_pad,
inout user_gpio_13_io_pad,
inout user_gpio_14_io_pad,
inout user_gpio_15_io_pad,
`endif
// gpio
inout gpio_0_io_pad,
inout gpio_1_io_pad,
inout gpio_2_io_pad,
inout gpio_3_io_pad,
inout gpio_4_io_pad,
inout gpio_5_io_pad,
inout gpio_6_io_pad,
inout gpio_7_io_pad,
inout gpio_8_io_pad,
inout gpio_9_io_pad,
inout gpio_10_io_pad,
inout gpio_11_io_pad,
inout gpio_12_io_pad,
inout gpio_13_io_pad,
inout gpio_14_io_pad,
inout gpio_15_io_pad,
inout gpio_16_io_pad,
inout gpio_17_io_pad,
inout gpio_18_io_pad,
inout gpio_19_io_pad,
inout gpio_20_io_pad,
inout gpio_21_io_pad,
inout gpio_22_io_pad,
inout gpio_23_io_pad,
inout gpio_24_io_pad,
inout gpio_25_io_pad,
inout gpio_26_io_pad,
inout gpio_27_io_pad,
inout gpio_28_io_pad,
inout gpio_29_io_pad,
inout gpio_30_io_pad,
inout gpio_31_io_pad,
// uart
output uart0_tx_o_pad,
inout uart0_rx_i_pad,
// xpi
output xpi_sck_o_pad,
output xpi_nss0_o_pad,
output xpi_nss1_o_pad,
output xpi_nss2_o_pad,
output xpi_nss3_o_pad,
inout xpi_dat0_io_pad,
inout xpi_dat1_io_pad,
inout xpi_dat2_io_pad,
inout xpi_dat3_io_pad,
// sdram
output sdram_clk_o_pad,
output sdram_cke_o_pad,
output sdram_cs_n_o_pad,
output sdram_ras_n_o_pad,
output sdram_cas_n_o_pad,
output sdram_we_n_o_pad,
output sdram_ba0_o_pad,
output sdram_ba1_o_pad,
output sdram_addr0_o_pad,
output sdram_addr1_o_pad,
output sdram_addr2_o_pad,
output sdram_addr3_o_pad,
output sdram_addr4_o_pad,
output sdram_addr5_o_pad,
output sdram_addr6_o_pad,
output sdram_addr7_o_pad,
output sdram_addr8_o_pad,
output sdram_addr9_o_pad,
output sdram_addr10_o_pad,
output sdram_addr11_o_pad,
output sdram_addr12_o_pad,
output sdram_dqm0_o_pad,
output sdram_dqm1_o_pad,
inout sdram_dq0_io_pad,
inout sdram_dq1_io_pad,
inout sdram_dq2_io_pad,
inout sdram_dq3_io_pad,
inout sdram_dq4_io_pad,
inout sdram_dq5_io_pad,
inout sdram_dq6_io_pad,
inout sdram_dq7_io_pad,
inout sdram_dq8_io_pad,
inout sdram_dq9_io_pad,
inout sdram_dq10_io_pad,
inout sdram_dq11_io_pad,
inout sdram_dq12_io_pad,
inout sdram_dq13_io_pad,
inout sdram_dq14_io_pad,
inout sdram_dq15_io_pad
`include "retrosoc_asic_ports.svh"
);
// clk&rst
logic s_ext_clk;
logic s_aud_clk;
logic s_sys_clkdiv4;
@@ -144,7 +24,6 @@ module retrosoc_asic (
logic s_ext_rst_n;
logic s_sys_rst_n;
logic s_aud_rst_n;
logic s_tmr_capch;
`ifdef CORE_MDD
logic [`USER_CORESEL_WIDTH-1:0] s_core_sel;
@@ -158,141 +37,15 @@ module retrosoc_asic (
ram_if u_ram_if ();
`endif
// verilog_format: off
logic [31:0] s_gpio_oe;
logic [31:0] s_gpio_cs;
logic [31:0] s_gpio_pu;
logic [31:0] s_gpio_pd;
logic [31:0] s_gpio_do;
logic [31:0] s_gpio_di;
uart_if u_uart0_if ();
xpi_if u_xpi_if ();
sdram_if u_sdram_if ();
pll_ctrl_if u_pll_ctrl_if ();
gpio_if u_gpio_if ();
uart_if u_uart0_if ();
xpi_if u_xpi_if ();
sdram_if u_sdram_if ();
pll_ctrl_if u_pll_ctrl_if ();
`include "retrosoc_asic_pad_bindings.svh"
tc_io_tri_pad u_extclk_i_pad (.pad(extclk_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_ext_clk));
tc_io_tri_pad u_audclk_i_pad (.pad(audclk_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_aud_clk));
tc_io_tri_schmitt_pad u_ext_rst_n_i_pad (.pad(ext_rst_n_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_ext_rst_n));
`ifdef HAVE_PLL
tc_io_xtl_pad u_xtal_io_pad (.xi_pad(xi_i_pad), .xo_pad(xo_o_pad), .en(1'b1), .clk(s_xtal_io));
`endif
`ifdef CORE_MDD
tc_io_tri_pad u_core_sel_0_i_pad (.pad(core_sel_0_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_core_sel[0]));
tc_io_tri_pad u_core_sel_1_i_pad (.pad(core_sel_1_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_core_sel[1]));
tc_io_tri_pad u_core_sel_2_i_pad (.pad(core_sel_2_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_core_sel[2]));
tc_io_tri_pad u_core_sel_3_i_pad (.pad(core_sel_3_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_core_sel[3]));
tc_io_tri_pad u_core_sel_4_i_pad (.pad(core_sel_4_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_core_sel[4]));
`endif
`ifdef IP_MDD
tc_io_tri_full_pad u_user_gpio_0_io_pad (.pad(user_gpio_0_io_pad), .c2p(u_user_gpio_if.do_o[0]), .c2p_en(u_user_gpio_if.oe_o[0]), .p2c(u_user_gpio_if.di_i[0]), .cs(u_user_gpio_if.cs_o[0]), .pu(u_user_gpio_if.pu_o[0]), .pd(u_user_gpio_if.pd_o[0]));
tc_io_tri_full_pad u_user_gpio_1_io_pad (.pad(user_gpio_1_io_pad), .c2p(u_user_gpio_if.do_o[1]), .c2p_en(u_user_gpio_if.oe_o[1]), .p2c(u_user_gpio_if.di_i[1]), .cs(u_user_gpio_if.cs_o[1]), .pu(u_user_gpio_if.pu_o[1]), .pd(u_user_gpio_if.pd_o[1]));
tc_io_tri_full_pad u_user_gpio_2_io_pad (.pad(user_gpio_2_io_pad), .c2p(u_user_gpio_if.do_o[2]), .c2p_en(u_user_gpio_if.oe_o[2]), .p2c(u_user_gpio_if.di_i[2]), .cs(u_user_gpio_if.cs_o[2]), .pu(u_user_gpio_if.pu_o[2]), .pd(u_user_gpio_if.pd_o[2]));
tc_io_tri_full_pad u_user_gpio_3_io_pad (.pad(user_gpio_3_io_pad), .c2p(u_user_gpio_if.do_o[3]), .c2p_en(u_user_gpio_if.oe_o[3]), .p2c(u_user_gpio_if.di_i[3]), .cs(u_user_gpio_if.cs_o[3]), .pu(u_user_gpio_if.pu_o[3]), .pd(u_user_gpio_if.pd_o[3]));
tc_io_tri_full_pad u_user_gpio_4_io_pad (.pad(user_gpio_4_io_pad), .c2p(u_user_gpio_if.do_o[4]), .c2p_en(u_user_gpio_if.oe_o[4]), .p2c(u_user_gpio_if.di_i[4]), .cs(u_user_gpio_if.cs_o[4]), .pu(u_user_gpio_if.pu_o[4]), .pd(u_user_gpio_if.pd_o[4]));
tc_io_tri_full_pad u_user_gpio_5_io_pad (.pad(user_gpio_5_io_pad), .c2p(u_user_gpio_if.do_o[5]), .c2p_en(u_user_gpio_if.oe_o[5]), .p2c(u_user_gpio_if.di_i[5]), .cs(u_user_gpio_if.cs_o[5]), .pu(u_user_gpio_if.pu_o[5]), .pd(u_user_gpio_if.pd_o[5]));
tc_io_tri_full_pad u_user_gpio_6_io_pad (.pad(user_gpio_6_io_pad), .c2p(u_user_gpio_if.do_o[6]), .c2p_en(u_user_gpio_if.oe_o[6]), .p2c(u_user_gpio_if.di_i[6]), .cs(u_user_gpio_if.cs_o[6]), .pu(u_user_gpio_if.pu_o[6]), .pd(u_user_gpio_if.pd_o[6]));
tc_io_tri_full_pad u_user_gpio_7_io_pad (.pad(user_gpio_7_io_pad), .c2p(u_user_gpio_if.do_o[7]), .c2p_en(u_user_gpio_if.oe_o[7]), .p2c(u_user_gpio_if.di_i[7]), .cs(u_user_gpio_if.cs_o[7]), .pu(u_user_gpio_if.pu_o[7]), .pd(u_user_gpio_if.pd_o[7]));
tc_io_tri_full_pad u_user_gpio_8_io_pad (.pad(user_gpio_8_io_pad), .c2p(u_user_gpio_if.do_o[8]), .c2p_en(u_user_gpio_if.oe_o[8]), .p2c(u_user_gpio_if.di_i[8]), .cs(u_user_gpio_if.cs_o[8]), .pu(u_user_gpio_if.pu_o[8]), .pd(u_user_gpio_if.pd_o[8]));
tc_io_tri_full_pad u_user_gpio_9_io_pad (.pad(user_gpio_9_io_pad), .c2p(u_user_gpio_if.do_o[9]), .c2p_en(u_user_gpio_if.oe_o[9]), .p2c(u_user_gpio_if.di_i[9]), .cs(u_user_gpio_if.cs_o[9]), .pu(u_user_gpio_if.pu_o[9]), .pd(u_user_gpio_if.pd_o[9]));
tc_io_tri_full_pad u_user_gpio_10_io_pad (.pad(user_gpio_10_io_pad), .c2p(u_user_gpio_if.do_o[10]), .c2p_en(u_user_gpio_if.oe_o[10]), .p2c(u_user_gpio_if.di_i[10]), .cs(u_user_gpio_if.cs_o[10]), .pu(u_user_gpio_if.pu_o[10]), .pd(u_user_gpio_if.pd_o[10]));
tc_io_tri_full_pad u_user_gpio_11_io_pad (.pad(user_gpio_11_io_pad), .c2p(u_user_gpio_if.do_o[11]), .c2p_en(u_user_gpio_if.oe_o[11]), .p2c(u_user_gpio_if.di_i[11]), .cs(u_user_gpio_if.cs_o[11]), .pu(u_user_gpio_if.pu_o[11]), .pd(u_user_gpio_if.pd_o[11]));
tc_io_tri_full_pad u_user_gpio_12_io_pad (.pad(user_gpio_12_io_pad), .c2p(u_user_gpio_if.do_o[12]), .c2p_en(u_user_gpio_if.oe_o[12]), .p2c(u_user_gpio_if.di_i[12]), .cs(u_user_gpio_if.cs_o[12]), .pu(u_user_gpio_if.pu_o[12]), .pd(u_user_gpio_if.pd_o[12]));
tc_io_tri_full_pad u_user_gpio_13_io_pad (.pad(user_gpio_13_io_pad), .c2p(u_user_gpio_if.do_o[13]), .c2p_en(u_user_gpio_if.oe_o[13]), .p2c(u_user_gpio_if.di_i[13]), .cs(u_user_gpio_if.cs_o[13]), .pu(u_user_gpio_if.pu_o[13]), .pd(u_user_gpio_if.pd_o[13]));
tc_io_tri_full_pad u_user_gpio_14_io_pad (.pad(user_gpio_14_io_pad), .c2p(u_user_gpio_if.do_o[14]), .c2p_en(u_user_gpio_if.oe_o[14]), .p2c(u_user_gpio_if.di_i[14]), .cs(u_user_gpio_if.cs_o[14]), .pu(u_user_gpio_if.pu_o[14]), .pd(u_user_gpio_if.pd_o[14]));
tc_io_tri_full_pad u_user_gpio_15_io_pad (.pad(user_gpio_15_io_pad), .c2p(u_user_gpio_if.do_o[15]), .c2p_en(u_user_gpio_if.oe_o[15]), .p2c(u_user_gpio_if.di_i[15]), .cs(u_user_gpio_if.cs_o[15]), .pu(u_user_gpio_if.pu_o[15]), .pd(u_user_gpio_if.pd_o[15]));
`endif
// gpio
tc_io_tri_full_pad u_gpio_0_io_pad (.pad(gpio_0_io_pad), .c2p(s_gpio_do[0]), .c2p_en(s_gpio_oe[0]), .p2c(s_gpio_di[0]), .cs(s_gpio_cs[0]), .pu(s_gpio_pu[0]), .pd(s_gpio_pd[0]));
tc_io_tri_full_pad u_gpio_1_io_pad (.pad(gpio_1_io_pad), .c2p(s_gpio_do[1]), .c2p_en(s_gpio_oe[1]), .p2c(s_gpio_di[1]), .cs(s_gpio_cs[1]), .pu(s_gpio_pu[1]), .pd(s_gpio_pd[1]));
tc_io_tri_full_pad u_gpio_2_io_pad (.pad(gpio_2_io_pad), .c2p(s_gpio_do[2]), .c2p_en(s_gpio_oe[2]), .p2c(s_gpio_di[2]), .cs(s_gpio_cs[2]), .pu(s_gpio_pu[2]), .pd(s_gpio_pd[2]));
tc_io_tri_full_pad u_gpio_3_io_pad (.pad(gpio_3_io_pad), .c2p(s_gpio_do[3]), .c2p_en(s_gpio_oe[3]), .p2c(s_gpio_di[3]), .cs(s_gpio_cs[3]), .pu(s_gpio_pu[3]), .pd(s_gpio_pd[3]));
tc_io_tri_full_pad u_gpio_4_io_pad (.pad(gpio_4_io_pad), .c2p(s_gpio_do[4]), .c2p_en(s_gpio_oe[4]), .p2c(s_gpio_di[4]), .cs(s_gpio_cs[4]), .pu(s_gpio_pu[4]), .pd(s_gpio_pd[4]));
tc_io_tri_full_pad u_gpio_5_io_pad (.pad(gpio_5_io_pad), .c2p(s_gpio_do[5]), .c2p_en(s_gpio_oe[5]), .p2c(s_gpio_di[5]), .cs(s_gpio_cs[5]), .pu(s_gpio_pu[5]), .pd(s_gpio_pd[5]));
tc_io_tri_full_pad u_gpio_6_io_pad (.pad(gpio_6_io_pad), .c2p(s_gpio_do[6]), .c2p_en(s_gpio_oe[6]), .p2c(s_gpio_di[6]), .cs(s_gpio_cs[6]), .pu(s_gpio_pu[6]), .pd(s_gpio_pd[6]));
tc_io_tri_full_pad u_gpio_7_io_pad (.pad(gpio_7_io_pad), .c2p(s_gpio_do[7]), .c2p_en(s_gpio_oe[7]), .p2c(s_gpio_di[7]), .cs(s_gpio_cs[7]), .pu(s_gpio_pu[7]), .pd(s_gpio_pd[7]));
tc_io_tri_full_pad u_gpio_8_io_pad (.pad(gpio_8_io_pad), .c2p(s_gpio_do[8]), .c2p_en(s_gpio_oe[8]), .p2c(s_gpio_di[8]), .cs(s_gpio_cs[8]), .pu(s_gpio_pu[8]), .pd(s_gpio_pd[8]));
tc_io_tri_full_pad u_gpio_9_io_pad (.pad(gpio_9_io_pad), .c2p(s_gpio_do[9]), .c2p_en(s_gpio_oe[9]), .p2c(s_gpio_di[9]), .cs(s_gpio_cs[9]), .pu(s_gpio_pu[9]), .pd(s_gpio_pd[9]));
tc_io_tri_full_pad u_gpio_10_io_pad (.pad(gpio_10_io_pad), .c2p(s_gpio_do[10]), .c2p_en(s_gpio_oe[10]), .p2c(s_gpio_di[10]), .cs(s_gpio_cs[10]), .pu(s_gpio_pu[10]), .pd(s_gpio_pd[10]));
tc_io_tri_full_pad u_gpio_11_io_pad (.pad(gpio_11_io_pad), .c2p(s_gpio_do[11]), .c2p_en(s_gpio_oe[11]), .p2c(s_gpio_di[11]), .cs(s_gpio_cs[11]), .pu(s_gpio_pu[11]), .pd(s_gpio_pd[11]));
tc_io_tri_full_pad u_gpio_12_io_pad (.pad(gpio_12_io_pad), .c2p(s_gpio_do[12]), .c2p_en(s_gpio_oe[12]), .p2c(s_gpio_di[12]), .cs(s_gpio_cs[12]), .pu(s_gpio_pu[12]), .pd(s_gpio_pd[12]));
tc_io_tri_full_pad u_gpio_13_io_pad (.pad(gpio_13_io_pad), .c2p(s_gpio_do[13]), .c2p_en(s_gpio_oe[13]), .p2c(s_gpio_di[13]), .cs(s_gpio_cs[13]), .pu(s_gpio_pu[13]), .pd(s_gpio_pd[13]));
tc_io_tri_full_pad u_gpio_14_io_pad (.pad(gpio_14_io_pad), .c2p(s_gpio_do[14]), .c2p_en(s_gpio_oe[14]), .p2c(s_gpio_di[14]), .cs(s_gpio_cs[14]), .pu(s_gpio_pu[14]), .pd(s_gpio_pd[14]));
tc_io_tri_full_pad u_gpio_15_io_pad (.pad(gpio_15_io_pad), .c2p(s_gpio_do[15]), .c2p_en(s_gpio_oe[15]), .p2c(s_gpio_di[15]), .cs(s_gpio_cs[15]), .pu(s_gpio_pu[15]), .pd(s_gpio_pd[15]));
tc_io_tri_full_pad u_gpio_16_io_pad (.pad(gpio_16_io_pad), .c2p(s_gpio_do[16]), .c2p_en(s_gpio_oe[16]), .p2c(s_gpio_di[16]), .cs(s_gpio_cs[16]), .pu(s_gpio_pu[16]), .pd(s_gpio_pd[16]));
tc_io_tri_full_pad u_gpio_17_io_pad (.pad(gpio_17_io_pad), .c2p(s_gpio_do[17]), .c2p_en(s_gpio_oe[17]), .p2c(s_gpio_di[17]), .cs(s_gpio_cs[17]), .pu(s_gpio_pu[17]), .pd(s_gpio_pd[17]));
tc_io_tri_full_pad u_gpio_18_io_pad (.pad(gpio_18_io_pad), .c2p(s_gpio_do[18]), .c2p_en(s_gpio_oe[18]), .p2c(s_gpio_di[18]), .cs(s_gpio_cs[18]), .pu(s_gpio_pu[18]), .pd(s_gpio_pd[18]));
tc_io_tri_full_pad u_gpio_19_io_pad (.pad(gpio_19_io_pad), .c2p(s_gpio_do[19]), .c2p_en(s_gpio_oe[19]), .p2c(s_gpio_di[19]), .cs(s_gpio_cs[19]), .pu(s_gpio_pu[19]), .pd(s_gpio_pd[19]));
tc_io_tri_full_pad u_gpio_20_io_pad (.pad(gpio_20_io_pad), .c2p(s_gpio_do[20]), .c2p_en(s_gpio_oe[20]), .p2c(s_gpio_di[20]), .cs(s_gpio_cs[20]), .pu(s_gpio_pu[20]), .pd(s_gpio_pd[20]));
tc_io_tri_full_pad u_gpio_21_io_pad (.pad(gpio_21_io_pad), .c2p(s_gpio_do[21]), .c2p_en(s_gpio_oe[21]), .p2c(s_gpio_di[21]), .cs(s_gpio_cs[21]), .pu(s_gpio_pu[21]), .pd(s_gpio_pd[21]));
tc_io_tri_full_pad u_gpio_22_io_pad (.pad(gpio_22_io_pad), .c2p(s_gpio_do[22]), .c2p_en(s_gpio_oe[22]), .p2c(s_gpio_di[22]), .cs(s_gpio_cs[22]), .pu(s_gpio_pu[22]), .pd(s_gpio_pd[22]));
tc_io_tri_full_pad u_gpio_23_io_pad (.pad(gpio_23_io_pad), .c2p(s_gpio_do[23]), .c2p_en(s_gpio_oe[23]), .p2c(s_gpio_di[23]), .cs(s_gpio_cs[23]), .pu(s_gpio_pu[23]), .pd(s_gpio_pd[23]));
tc_io_tri_full_pad u_gpio_24_io_pad (.pad(gpio_24_io_pad), .c2p(s_gpio_do[24]), .c2p_en(s_gpio_oe[24]), .p2c(s_gpio_di[24]), .cs(s_gpio_cs[24]), .pu(s_gpio_pu[24]), .pd(s_gpio_pd[24]));
tc_io_tri_full_pad u_gpio_25_io_pad (.pad(gpio_25_io_pad), .c2p(s_gpio_do[25]), .c2p_en(s_gpio_oe[25]), .p2c(s_gpio_di[25]), .cs(s_gpio_cs[25]), .pu(s_gpio_pu[25]), .pd(s_gpio_pd[25]));
tc_io_tri_full_pad u_gpio_26_io_pad (.pad(gpio_26_io_pad), .c2p(s_gpio_do[26]), .c2p_en(s_gpio_oe[26]), .p2c(s_gpio_di[26]), .cs(s_gpio_cs[26]), .pu(s_gpio_pu[26]), .pd(s_gpio_pd[26]));
tc_io_tri_full_pad u_gpio_27_io_pad (.pad(gpio_27_io_pad), .c2p(s_gpio_do[27]), .c2p_en(s_gpio_oe[27]), .p2c(s_gpio_di[27]), .cs(s_gpio_cs[27]), .pu(s_gpio_pu[27]), .pd(s_gpio_pd[27]));
tc_io_tri_full_pad u_gpio_28_io_pad (.pad(gpio_28_io_pad), .c2p(s_gpio_do[28]), .c2p_en(s_gpio_oe[28]), .p2c(s_gpio_di[28]), .cs(s_gpio_cs[28]), .pu(s_gpio_pu[28]), .pd(s_gpio_pd[28]));
tc_io_tri_full_pad u_gpio_29_io_pad (.pad(gpio_29_io_pad), .c2p(s_gpio_do[29]), .c2p_en(s_gpio_oe[29]), .p2c(s_gpio_di[29]), .cs(s_gpio_cs[29]), .pu(s_gpio_pu[29]), .pd(s_gpio_pd[29]));
tc_io_tri_full_pad u_gpio_30_io_pad (.pad(gpio_30_io_pad), .c2p(s_gpio_do[30]), .c2p_en(s_gpio_oe[30]), .p2c(s_gpio_di[30]), .cs(s_gpio_cs[30]), .pu(s_gpio_pu[30]), .pd(s_gpio_pd[30]));
tc_io_tri_full_pad u_gpio_31_io_pad (.pad(gpio_31_io_pad), .c2p(s_gpio_do[31]), .c2p_en(s_gpio_oe[31]), .p2c(s_gpio_di[31]), .cs(s_gpio_cs[31]), .pu(s_gpio_pu[31]), .pd(s_gpio_pd[31]));
// uart0
tc_io_tri_pad u_uart0_tx_o_pad (.pad(uart0_tx_o_pad), .c2p(u_uart0_if.tx_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_uart0_rx_i_pad (.pad(uart0_rx_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(u_uart0_if.rx_i));
// xpi
tc_io_tri_pad u_xpi_sck_o_pad (.pad(xpi_sck_o_pad), .c2p(u_xpi_if.sck_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_xpi_nss0_o_pad (.pad(xpi_nss0_o_pad), .c2p(u_xpi_if.nss_o[0]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_xpi_nss1_o_pad (.pad(xpi_nss1_o_pad), .c2p(u_xpi_if.nss_o[1]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_xpi_nss2_o_pad (.pad(xpi_nss2_o_pad), .c2p(u_xpi_if.nss_o[2]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_xpi_nss3_o_pad (.pad(xpi_nss3_o_pad), .c2p(u_xpi_if.nss_o[3]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_xpi_dat0_io_pad (.pad(xpi_dat0_io_pad), .c2p(u_xpi_if.io_do_o[0]), .c2p_en(u_xpi_if.io_oe_o[0]), .p2c(u_xpi_if.io_di_i[0]));
tc_io_tri_pad u_xpi_dat1_io_pad (.pad(xpi_dat1_io_pad), .c2p(u_xpi_if.io_do_o[1]), .c2p_en(u_xpi_if.io_oe_o[1]), .p2c(u_xpi_if.io_di_i[1]));
tc_io_tri_pad u_xpi_dat2_io_pad (.pad(xpi_dat2_io_pad), .c2p(u_xpi_if.io_do_o[2]), .c2p_en(u_xpi_if.io_oe_o[2]), .p2c(u_xpi_if.io_di_i[2]));
tc_io_tri_pad u_xpi_dat3_io_pad (.pad(xpi_dat3_io_pad), .c2p(u_xpi_if.io_do_o[3]), .c2p_en(u_xpi_if.io_oe_o[3]), .p2c(u_xpi_if.io_di_i[3]));
// sdram
tc_io_tri_pad u_sdram_clk_o_pad (.pad(sdram_clk_o_pad), .c2p(u_sdram_if.clk_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_cke_o_pad (.pad(sdram_cke_o_pad), .c2p(u_sdram_if.cke_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_cs_n_o_pad (.pad(sdram_cs_n_o_pad), .c2p(u_sdram_if.cs_n_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_ras_n_o_pad (.pad(sdram_ras_n_o_pad), .c2p(u_sdram_if.ras_n_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_cas_n_o_pad (.pad(sdram_cas_n_o_pad), .c2p(u_sdram_if.cas_n_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_we_n_o_pad (.pad(sdram_we_n_o_pad), .c2p(u_sdram_if.we_n_o), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_ba0_o_pad (.pad(sdram_ba0_o_pad), .c2p(u_sdram_if.ba_o[0]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_ba1_o_pad (.pad(sdram_ba1_o_pad), .c2p(u_sdram_if.ba_o[1]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr0_o_pad (.pad(sdram_addr0_o_pad), .c2p(u_sdram_if.addr_o[0]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr1_o_pad (.pad(sdram_addr1_o_pad), .c2p(u_sdram_if.addr_o[1]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr2_o_pad (.pad(sdram_addr2_o_pad), .c2p(u_sdram_if.addr_o[2]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr3_o_pad (.pad(sdram_addr3_o_pad), .c2p(u_sdram_if.addr_o[3]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr4_o_pad (.pad(sdram_addr4_o_pad), .c2p(u_sdram_if.addr_o[4]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr5_o_pad (.pad(sdram_addr5_o_pad), .c2p(u_sdram_if.addr_o[5]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr6_o_pad (.pad(sdram_addr6_o_pad), .c2p(u_sdram_if.addr_o[6]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr7_o_pad (.pad(sdram_addr7_o_pad), .c2p(u_sdram_if.addr_o[7]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr8_o_pad (.pad(sdram_addr8_o_pad), .c2p(u_sdram_if.addr_o[8]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr9_o_pad (.pad(sdram_addr9_o_pad), .c2p(u_sdram_if.addr_o[9]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr10_o_pad (.pad(sdram_addr10_o_pad), .c2p(u_sdram_if.addr_o[10]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr11_o_pad (.pad(sdram_addr11_o_pad), .c2p(u_sdram_if.addr_o[11]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_addr12_o_pad (.pad(sdram_addr12_o_pad), .c2p(u_sdram_if.addr_o[12]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_dqm0_o_pad (.pad(sdram_dqm0_o_pad), .c2p(u_sdram_if.dqm_o[0]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_dqm1_o_pad (.pad(sdram_dqm1_o_pad), .c2p(u_sdram_if.dqm_o[1]), .c2p_en(1'b1), .p2c());
tc_io_tri_pad u_sdram_dq0_io_pad (.pad(sdram_dq0_io_pad), .c2p(u_sdram_if.dq_o[0]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[0]));
tc_io_tri_pad u_sdram_dq1_io_pad (.pad(sdram_dq1_io_pad), .c2p(u_sdram_if.dq_o[1]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[1]));
tc_io_tri_pad u_sdram_dq2_io_pad (.pad(sdram_dq2_io_pad), .c2p(u_sdram_if.dq_o[2]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[2]));
tc_io_tri_pad u_sdram_dq3_io_pad (.pad(sdram_dq3_io_pad), .c2p(u_sdram_if.dq_o[3]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[3]));
tc_io_tri_pad u_sdram_dq4_io_pad (.pad(sdram_dq4_io_pad), .c2p(u_sdram_if.dq_o[4]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[4]));
tc_io_tri_pad u_sdram_dq5_io_pad (.pad(sdram_dq5_io_pad), .c2p(u_sdram_if.dq_o[5]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[5]));
tc_io_tri_pad u_sdram_dq6_io_pad (.pad(sdram_dq6_io_pad), .c2p(u_sdram_if.dq_o[6]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[6]));
tc_io_tri_pad u_sdram_dq7_io_pad (.pad(sdram_dq7_io_pad), .c2p(u_sdram_if.dq_o[7]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[7]));
tc_io_tri_pad u_sdram_dq8_io_pad (.pad(sdram_dq8_io_pad), .c2p(u_sdram_if.dq_o[8]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[8]));
tc_io_tri_pad u_sdram_dq9_io_pad (.pad(sdram_dq9_io_pad), .c2p(u_sdram_if.dq_o[9]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[9]));
tc_io_tri_pad u_sdram_dq10_io_pad (.pad(sdram_dq10_io_pad), .c2p(u_sdram_if.dq_o[10]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[10]));
tc_io_tri_pad u_sdram_dq11_io_pad (.pad(sdram_dq11_io_pad), .c2p(u_sdram_if.dq_o[11]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[11]));
tc_io_tri_pad u_sdram_dq12_io_pad (.pad(sdram_dq12_io_pad), .c2p(u_sdram_if.dq_o[12]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[12]));
tc_io_tri_pad u_sdram_dq13_io_pad (.pad(sdram_dq13_io_pad), .c2p(u_sdram_if.dq_o[13]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[13]));
tc_io_tri_pad u_sdram_dq14_io_pad (.pad(sdram_dq14_io_pad), .c2p(u_sdram_if.dq_o[14]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[14]));
tc_io_tri_pad u_sdram_dq15_io_pad (.pad(sdram_dq15_io_pad), .c2p(u_sdram_if.dq_o[15]), .c2p_en(u_sdram_if.oe_o), .p2c(u_sdram_if.dq_i[15]));
// verilog_format: on
// clk buffer & mux
rcu u_rcu (
rcu u_rcu (
.ext_clk_i (s_ext_clk),
.aud_clk_i (s_aud_clk),
.ext_rst_n_i (s_ext_rst_n),
@@ -329,12 +82,7 @@ module retrosoc_asic (
`ifdef HAVE_SRAM_IF
.ram (u_ram_if),
`endif
.gpio_oe_o (s_gpio_oe),
.gpio_cs_o (s_gpio_cs),
.gpio_pu_o (s_gpio_pu),
.gpio_pd_o (s_gpio_pd),
.gpio_do_o (s_gpio_do),
.gpio_di_i (s_gpio_di),
.gpio (u_gpio_if),
.uart0 (u_uart0_if),
.xpi (u_xpi_if),
.sdram (u_sdram_if)
+26 -4
View File
@@ -7,19 +7,40 @@ import hashlib
import json
import re
import sys
from datetime import datetime
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from scripts.dependency_lock import DEFAULT_LOCK, lock_digest, load_lock # noqa: E402
TIMESTAMP_FORMAT = "%Y-%m-%d-%H-%M"
TIMESTAMP_RE = re.compile(r"[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}")
def slug(value: str) -> str:
normalized = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
return normalized or "manual"
def variant_id(profile: str, values: list[str], lock: Path) -> str:
def normalize_timestamp(value: str | None) -> str:
if value is None:
return datetime.now().astimezone().strftime(TIMESTAMP_FORMAT)
if TIMESTAMP_RE.fullmatch(value) is None:
raise ValueError(f"timestamp must use {TIMESTAMP_FORMAT}")
try:
datetime.strptime(value, TIMESTAMP_FORMAT)
except ValueError as error:
raise ValueError(f"timestamp must use {TIMESTAMP_FORMAT}") from error
return value
def variant_id(
profile: str,
values: list[str],
lock: Path,
timestamp: str | None = None,
) -> str:
parsed: dict[str, str] = {}
for item in values:
name, separator, value = item.partition("=")
@@ -34,18 +55,19 @@ def variant_id(profile: str, values: list[str], lock: Path) -> str:
digest = hashlib.sha256(
json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
).hexdigest()[:12]
return f"{slug(profile)}-{digest}"
return f"{slug(profile)}-{normalize_timestamp(timestamp)}-{digest}"
def main() -> int:
parser = argparse.ArgumentParser(description="Generate a deterministic build variant ID")
parser = argparse.ArgumentParser(description="Generate a timestamped build variant ID")
parser.add_argument("--lock", type=Path, default=DEFAULT_LOCK)
parser.add_argument("--profile", default="manual")
parser.add_argument("--value", action="append", default=[])
parser.add_argument("--timestamp", help=f"creation time in {TIMESTAMP_FORMAT} format")
args = parser.parse_args()
load_lock(args.lock)
try:
print(variant_id(args.profile, args.value, args.lock))
print(variant_id(args.profile, args.value, args.lock, args.timestamp))
except ValueError as error:
parser.error(str(error))
return 0
+18 -4
View File
@@ -3,8 +3,10 @@
from __future__ import annotations
import argparse
import os
import subprocess
import sys
from datetime import datetime
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
@@ -37,14 +39,25 @@ PR_PROFILES = (
NIGHTLY_PROFILES = PR_PROFILES + ("configs/nightly/picorv32-rv32im-ihp130.mk",)
def run_command(command: list[str], root: Path, capture_output: bool) -> str:
def regression_environment() -> dict[str, str]:
environment = os.environ.copy()
environment.setdefault(
"BUILD_TIMESTAMP", datetime.now().astimezone().strftime("%Y-%m-%d-%H-%M")
)
return environment
def run_command(
command: list[str], root: Path, capture_output: bool, environment: dict[str, str]
) -> str:
if not capture_output:
subprocess.run(command, cwd=root, check=True)
subprocess.run(command, cwd=root, env=environment, check=True)
return ""
result = subprocess.run(
command,
cwd=root,
env=environment,
check=False,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
@@ -63,11 +76,12 @@ def main() -> int:
args = parser.parse_args()
commands = PR_COMMANDS if args.suite == "pr" else NIGHTLY_COMMANDS
profiles = PR_PROFILES if args.suite == "pr" else NIGHTLY_PROFILES
environment = regression_environment()
for profile, values in commands:
command = ["make", f"CONFIG={profile}", *values]
print("+ " + " ".join(command), flush=True)
if not args.dry_run:
output = run_command(command, args.root, "firmware" in values)
output = run_command(command, args.root, "firmware" in values, environment)
warnings = self_owned_warnings(args.root, output)
if warnings:
print("self-owned C compiler warnings:", flush=True)
@@ -82,7 +96,7 @@ def main() -> int:
]
print("+ " + " ".join(command), flush=True)
if not args.dry_run:
subprocess.run(command, cwd=args.root, check=True)
subprocess.run(command, cwd=args.root, env=environment, check=True)
return 0
+44
View File
@@ -0,0 +1,44 @@
`timescale 1ns / 1ps
module apb4_if_bridge_tb;
logic pclk = 1'b0;
logic presetn = 1'b0;
apb4_pure_if apb_pure ();
apb4_if apb_timed (
.pclk (pclk),
.presetn(presetn)
);
apb4_if_bridge u_apb4_if_bridge (
.apb_pure(apb_pure),
.timed (apb_timed)
);
initial begin
apb_pure.paddr = 32'h1234_5678;
apb_pure.pprot = 3'b101;
apb_pure.psel = 1'b1;
apb_pure.penable = 1'b1;
apb_pure.pwrite = 1'b1;
apb_pure.pwdata = 32'hCAFE_BABE;
apb_pure.pstrb = 4'b1101;
apb_timed.pready = 1'b1;
apb_timed.prdata = 32'hDEAD_BEEF;
apb_timed.pslverr = 1'b0;
#1;
if ({apb_timed.paddr, apb_timed.pprot, apb_timed.psel, apb_timed.penable,
apb_timed.pwrite, apb_timed.pwdata, apb_timed.pstrb} !==
{apb_pure.paddr, apb_pure.pprot, apb_pure.psel, apb_pure.penable,
apb_pure.pwrite, apb_pure.pwdata, apb_pure.pstrb}) begin
$fatal(1, "APB request fields did not cross the bridge");
end
if ({apb_pure.pready, apb_pure.prdata, apb_pure.pslverr} !==
{apb_timed.pready, apb_timed.prdata, apb_timed.pslverr}) begin
$fatal(1, "APB response fields did not cross the bridge");
end
$display("apb4 interface bridge test passed");
$finish;
end
endmodule
+149
View File
@@ -0,0 +1,149 @@
"""Tests for the canonical Mini SoC pin-map generator."""
from __future__ import annotations
import json
import re
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
GENERATOR = ROOT / "rtl/mini/pin_map/generate_pin_map.py"
PIN_MAP = ROOT / "rtl/mini/pin_map/pin_map.json"
FPGA_TOP = ROOT / "fpga/mini/retrosoc_top.sv"
FPGA_XDC = ROOT / "fpga/mini/starrysky_v2.xdc"
def generate(output_dir: Path) -> None:
subprocess.run(
[
sys.executable,
str(GENERATOR),
"--map",
str(PIN_MAP),
"--output-dir",
str(output_dir),
],
check=True,
)
def validate(map_path: Path) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(GENERATOR), "--map", str(map_path), "--check"],
text=True,
capture_output=True,
)
def test_pin_map_generates_asic_and_platform_bindings(tmp_path: Path) -> None:
generate(tmp_path)
ports = (tmp_path / "rtl/retrosoc_asic_ports.svh").read_text(encoding="utf-8")
pads = (tmp_path / "rtl/retrosoc_asic_pad_bindings.svh").read_text(encoding="utf-8")
fpga = (tmp_path / "rtl/retrosoc_asic_fpga_mini_bindings.svh").read_text(
encoding="utf-8"
)
testbench = (tmp_path / "rtl/retrosoc_asic_tb_bindings.svh").read_text(
encoding="utf-8"
)
assert "inout extclk_i_pad," in ports
assert "input xi_i_pad," in ports
assert "inout sdram_dq15_io_pad" in ports
assert "u_gpio_31_io_pad" in pads
assert "u_sdram_dq15_io_pad" in pads
assert ".gpio_30_io_pad(gpio_io30)" in fpga
assert ".gpio_15_io_pad()" in fpga
assert ".gpio_24_io_pad(s_psram_dat1)" in testbench
assert testbench.count(".gpio_24_io_pad(") == 1
def test_pin_map_rejects_duplicate_pads(tmp_path: Path) -> None:
document = json.loads(PIN_MAP.read_text(encoding="utf-8"))
document["pads"][0]["ports"].append(
{"name": "extclk_i_pad", "signal": "s_duplicate_clock"}
)
invalid_map = tmp_path / "duplicate.json"
invalid_map.write_text(json.dumps(document), encoding="utf-8")
result = validate(invalid_map)
assert result.returncode != 0
assert "pad names must be unique" in result.stderr
def test_pin_map_rejects_non_object_port_entry(tmp_path: Path) -> None:
document = json.loads(PIN_MAP.read_text(encoding="utf-8"))
document["pads"][0]["ports"].append("extclk_i_pad")
invalid_map = tmp_path / "invalid-port.json"
invalid_map.write_text(json.dumps(document), encoding="utf-8")
result = validate(invalid_map)
assert result.returncode != 0
assert "ports entries must be objects" in result.stderr
def test_pin_map_rejects_unknown_profile_pad(tmp_path: Path) -> None:
document = json.loads(PIN_MAP.read_text(encoding="utf-8"))
document["profiles"]["tb"]["bindings"]["unknown_pad"] = "s_unknown"
invalid_map = tmp_path / "unknown.json"
invalid_map.write_text(json.dumps(document), encoding="utf-8")
result = validate(invalid_map)
assert result.returncode != 0
assert "unknown pad" in result.stderr
def test_fpga_constraints_reference_declared_top_ports() -> None:
top_ports = set(re.findall(r"^\s*(?:input|output|inout)\s+([A-Za-z_][A-Za-z0-9_]*)", FPGA_TOP.read_text(encoding="utf-8"), re.MULTILINE))
xdc_ports = set(re.findall(r"\[get_ports\s+([A-Za-z_][A-Za-z0-9_]*)\]", FPGA_XDC.read_text(encoding="utf-8")))
assert xdc_ports
assert xdc_ports <= top_ports
def test_apb4_interface_bridge(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
sv2v = shutil.which("sv2v")
vvp = shutil.which("vvp")
if iverilog is None or sv2v is None or vvp is None:
return
source_list = tmp_path / "apb4_if_bridge.fl"
source_list.write_text(
"\n".join(
[
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_pure_if.sv"),
str(ROOT / "rtl/mini/top/apb4_if_bridge.sv"),
str(ROOT / "tests/rtl/apb4_if_bridge_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "apb4_if_bridge_tb.v"
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
"-f",
str(source_list),
"--output",
str(converted),
],
check=True,
)
simulation = tmp_path / "apb4_if_bridge_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "apb4_if_bridge_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "apb4 interface bridge test passed" in result.stdout
+24 -2
View File
@@ -25,6 +25,7 @@ from scripts.analyze_warnings import normalize # noqa: E402
from scripts.check_c_warnings import self_owned_warnings # noqa: E402
from scripts.dependency_lock import LockError, load_lock # noqa: E402
from scripts.install_toolchain import safe_extract # noqa: E402
from scripts.regress import regression_environment # noqa: E402
from scripts.setup_helpers import download_file, ensure_git_repo # noqa: E402
@@ -190,7 +191,7 @@ def test_make_dry_run_and_validation_do_not_write_filelists() -> None:
assert "Invalid SIMU='UNKNOWN'" in invalid.stderr
def test_dependency_lock_and_config_key_are_deterministic(tmp_path: Path) -> None:
def test_dependency_lock_and_config_key_include_a_fixed_timestamp(tmp_path: Path) -> None:
lock = load_lock(ROOT / "config/dependencies.lock.json")
assert lock["schema_version"] == 1
assert len(lock["sources"]["mpw"]["revision"]) == 40
@@ -202,6 +203,8 @@ def test_dependency_lock_and_config_key_are_deterministic(tmp_path: Path) -> Non
str(ROOT / "config/dependencies.lock.json"),
"--profile",
"unit",
"--timestamp",
"2026-07-21-10-39",
"--value",
"CORE=HAZARD3",
"--value",
@@ -210,7 +213,15 @@ def test_dependency_lock_and_config_key_are_deterministic(tmp_path: Path) -> Non
first = run(*command).stdout.strip()
second = run(*command).stdout.strip()
assert first == second
assert first.startswith("unit-")
assert re.fullmatch(r"unit-2026-07-21-10-39-[0-9a-f]{12}", first)
invalid_timestamp = subprocess.run(
[*command, "--timestamp", "2026-07-21-10-99"],
text=True,
capture_output=True,
)
assert invalid_timestamp.returncode != 0
assert "timestamp must use %Y-%m-%d-%H-%M" in invalid_timestamp.stderr
broken = tmp_path / "broken.json"
broken.write_text('{"schema_version": 1}\n', encoding="utf-8")
@@ -222,6 +233,17 @@ def test_dependency_lock_and_config_key_are_deterministic(tmp_path: Path) -> Non
raise AssertionError("invalid dependency lock was accepted")
def test_regression_runner_uses_one_build_timestamp(monkeypatch) -> None:
monkeypatch.setenv("BUILD_TIMESTAMP", "2026-07-21-10-39")
assert regression_environment()["BUILD_TIMESTAMP"] == "2026-07-21-10-39"
monkeypatch.delenv("BUILD_TIMESTAMP")
assert re.fullmatch(
r"[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}",
regression_environment()["BUILD_TIMESTAMP"],
)
def test_run_flow_writes_structured_result(tmp_path: Path) -> None:
log = tmp_path / "flow.log"
result = tmp_path / "result.json"