Add generic IMU fusion and PMOD IRQ verification

This commit is contained in:
2026-07-14 11:03:13 +03:00
parent e77651dac3
commit dd6569c025
35 changed files with 2680 additions and 70 deletions
+27 -6
View File
@@ -47,6 +47,9 @@ APP_FLASH_HEX ?= $(FLASH_DIR)/$(SIM_APP).flash.hex
BOOTLOADER_IMG ?= $(SOC_OUT_DIR)/software/bootloader/bootloader.img
GPS_DEBUG ?= 1
GPS_DEBUG_LEVEL ?= 4
BSP_UART_CLOCK_HZ ?= 100000000
BSP_UART_BAUDRATE ?= 115200
BSP_CLINT_TIMEBASE_HZ ?= 1000000
RTL_FILELIST := $(FILELIST_DIR)/asic_rtl.f
TB_FILELIST := $(FILELIST_DIR)/asic_tb.f
SIM_DPI := $(OUT_DIR)/dpi/libsimjtag.so
@@ -58,6 +61,10 @@ ASIC_PLL_MODEL := $(ASIC_SIM_DIR)/tb/models/clock/asic_pll_model.sv
CHISEL_SRCS := $(shell find $(SOC_SCALA_DIR) -type f -name '*.scala' 2>/dev/null)
APP_SW_DIR := $(SOC_SW_DIR)/$(SIM_APP)
APP_SW_SRCS := $(wildcard $(APP_SW_DIR)/*)
SIM_APP_MAKE_ARGS :=
ifeq ($(SIM_APP),pmod_irq_test)
SIM_APP_MAKE_ARGS += PMOD_IRQ_TEST_QUIET=1 BSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ) BSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)
endif
BOOTLOADER_SW_SRCS := $(wildcard $(SOC_SW_DIR)/bootloader/*)
MAKE_FLASH_IMAGE := $(SOC_SW_DIR)/tools/make_flash_image.py
OBJCOPY := $(CROSS)objcopy
@@ -66,8 +73,9 @@ READELF := $(CROSS)readelf
VLOG_FLAGS ?= +define+PRINTF_COND=0
SIM_VLOG_FLAGS ?= +define+PRINTF_COND=0 +define+RANDOMIZE_REG_INIT +define+RANDOMIZE_MEM_INIT +define+RANDOM=0 +define+INIT_RANDOM_PROLOG_
GUI_VOPTARGS ?= +acc
SIM_PLUSARGS ?=
.PHONY: help all software chisel rtl sim-rtl filelist vlog-soc vlog-tb dpi sim sim-gui sanity clean
.PHONY: help all software chisel rtl sim-rtl filelist vlog-soc vlog-tb dpi sim sim-gui sim-pmod-irq sim-pmod-irq-rtl sanity clean FORCE
help:
@printf '%s\n' \
@@ -80,6 +88,8 @@ help:
' make vlog-soc Compile synthesis-style SoC RTL with Questa vlog' \
' make vlog-tb Compile simulation RTL, models, SimJTAG, and TB' \
' make sim Run UART/SPI flash sanity simulation' \
' make sim-pmod-irq Run PMOD IRQ square-wave/PLIC/ISR simulation' \
' make sim-pmod-irq-rtl Run fast PMOD IRQ square-wave/PLIC simulation' \
' make sim GUI=1 Open Questa/ModelSim GUI, load wave.do, run 0 ns' \
' make sim-gui Alias for make sim GUI=1' \
' make clean Remove generated ASIC outputs'
@@ -88,12 +98,16 @@ all: rtl vlog-tb
software: $(BOOTLOADER_IMG) $(APP_FLASH_HEX)
$(BOOTLOADER_IMG): $(BOOTLOADER_SW_SRCS)
$(MAKE) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(SIM_APP)" APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" bootloader
$(BOOTLOADER_IMG): FORCE $(BOOTLOADER_SW_SRCS)
$(MAKE) -C "$(SOC_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" APP="$(SIM_APP)" \
APP_FLASH_OFFSET="$(APP_FLASH_OFFSET)" \
BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" \
BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" \
BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" bootloader
$(APP_ELF): $(APP_SW_SRCS)
test -d "$(APP_SW_DIR)"
$(MAKE) -C "$(APP_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(APP_BUILD_DIR)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" all
$(MAKE) -C "$(APP_SW_DIR)" TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(APP_BUILD_DIR)" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" $(SIM_APP_MAKE_ARGS) all
$(APP_FLASH_BIN): $(APP_ELF)
mkdir -p "$(FLASH_DIR)"
@@ -122,7 +136,7 @@ $(FIRRTL_DIR)/VCU118RocketSystem.fir: $(BOOTLOADER_IMG) $(CHISEL_SRCS)
rtl: $(ASIC_TOP) $(RTL_FILELIST)
$(ASIC_TOP): $(FIRRTL_DIR)/VCU118RocketSystem.fir
$(ASIC_TOP): $(FIRRTL_DIR)/VCU118RocketSystem.fir $(TOOLS_DIR)/gen_asic_wrapper.py
cd "$(REPO_DIR)"
rm -rf "$(VERILOG_DIR)"
mkdir -p "$(VERILOG_DIR)" "$(OUT_DIR)/generated"
@@ -141,7 +155,7 @@ $(ASIC_TOP): $(FIRRTL_DIR)/VCU118RocketSystem.fir
sim-rtl: $(SIM_ASIC_TOP) $(TB_FILELIST)
$(SIM_ASIC_TOP): $(FIRRTL_DIR)/VCU118RocketSystem.fir
$(SIM_ASIC_TOP): $(FIRRTL_DIR)/VCU118RocketSystem.fir $(TOOLS_DIR)/gen_asic_wrapper.py
cd "$(REPO_DIR)"
rm -rf "$(SIM_VERILOG_DIR)"
mkdir -p "$(SIM_VERILOG_DIR)" "$(OUT_DIR)/generated"
@@ -223,6 +237,7 @@ sim sanity: vlog-tb $(SIM_DPI)
else
"$(VSIM)" -c -suppress 3009 -lib "$(ASIC_DIR)/work" -sv_lib "$(OUT_DIR)/dpi/libsimjtag" asic_rocket_tb \
+flash_hex="$(APP_FLASH_HEX)" \
$(SIM_PLUSARGS) \
-do "run -all; quit -f" | tee "$(LOG_DIR)/vsim_sanity.log"
grep -q "ASIC sanity PASS" "$(LOG_DIR)/vsim_sanity.log"
fi
@@ -230,6 +245,12 @@ sim sanity: vlog-tb $(SIM_DPI)
sim-gui:
$(MAKE) sim GUI=1
sim-pmod-irq:
$(MAKE) sim SIM_APP=pmod_irq_test
sim-pmod-irq-rtl:
$(MAKE) sim SIM_APP=pmod_irq_test SIM_PLUSARGS=+pmod_irq_rtl_only
clean:
rm -rf "$(OUT_DIR)" "$(FIRRTL_DIR)" "$(VERILOG_DIR)" "$(SIM_VERILOG_DIR)"
+40
View File
@@ -15,11 +15,51 @@ make -C targets/asic/rocket sim-rtl
make -C targets/asic/rocket vlog-soc
make -C targets/asic/rocket vlog-tb
make -C targets/asic/rocket sim
make -C targets/asic/rocket sim-pmod-irq
make -C targets/asic/rocket sim-pmod-irq-rtl
make -C targets/asic/rocket sim GUI=1
```
The default simulation app is `hello_uart`.
The ASIC Makefile always checks the bootloader build configuration before
hardware generation. This prevents a previously built Genesys2 image (50 MHz
UART and a different flash offset) from being silently embedded in the ASIC
BootROM; the ASIC defaults are 100 MHz, 115200 baud, and flash offset
`0x06000000`.
`sim-pmod-irq` drives the ASIC top-level `pmod_irq` input with four
asynchronous square-wave periods, checks that TLPLIC source 10 becomes pending
(architectural device ID 11), and boots the standalone `pmod_irq_test`
firmware. PASS therefore requires both the RTL pending bit and a successful CPU
PLIC interrupt/ISR return; a pin toggle alone is not accepted.
`sim-pmod-irq-rtl` applies the same four asynchronous periods but finishes as
soon as all four input rising edges and the PLIC device-11 pending state have
been observed. It skips the slow bootloader/SPI-flash/firmware phase and is the
fast regression for the ASIC input-to-PLIC hardware route. It does not claim to
test the C interrupt handler; use `sim-pmod-irq` for that end-to-end check.
## PMOD IRQ ASIC simulation result
Verified on 2026-07-14 with QuestaSim 2021.2_1:
```text
ASIC PMOD IRQ: PLIC device 11 pending observed
UART: Flash JEDEC ID: 0x0020bb21
UART: Load: flash 0x06000040 -> mem 0x80000000, size 0x00000908
UART: CRC ok, jumping 0x80000000
C main returned 0
ASIC PMOD IRQ PASS: rises=4 pending_seen=1
ASIC sanity PASS
Errors: 0
```
The fast RTL-only regression also passed at simulation time 1455 ns with four
rising edges and PLIC device 11 pending. The full test completed at simulation
time 50,972,035 ns. In `pmod_irq_test`, return code zero is emitted only after
the expected device-11 ISR increments its interrupt counter.
`make -C targets/asic/rocket sim GUI=1` opens the Questa/ModelSim graphical simulator,
loads `asic_rocket_tb` with `-voptargs="+acc"`, sources
`hardware/sim/asic/rocket/wave.do`, sets `onfinish stop`, and runs only `0 ns`
@@ -83,6 +83,8 @@ def main():
value = "1'b0"
elif name == "gps_sample_counter":
value = "32'd0"
elif name == "pmod_irq":
value = "pmod_irq"
elif name == "resetctrl_hartIsInReset_0":
value = "core_reset"
elif name == "debug_systemjtag_jtag_TCK":
@@ -116,6 +118,7 @@ module asic_rocket_top (
input wire board_reset,
input wire gps_rf_clk,
input wire [3:0] gps_rf_data,
input wire pmod_irq,
input wire uart_rxd,
output wire uart_txd,
output wire spi_sck,
@@ -218,7 +218,10 @@ def main():
value = const_for(width)
assigns.append(f" assign {name} = {value};")
port_map = ",\n".join(f" .{name}({name})" for _, _, name in ports)
port_map = ",\n".join(
f" .{name}({'pmod_irq_sync[2]' if name == 'pmod_irq' else name})"
for _, _, name in ports
)
led_debug = []
for candidate in ["debug_ndreset", "debug_dmactive", "debug_clockeddmi_dmi_req_ready"]:
@@ -361,10 +364,25 @@ def main():
"""
pmod_irq_top_ports = ""
pmod_irq_block = ""
if "pmod_irq" in port_by_name:
pmod_irq_top_ports = """\
input wire pmod_irq,
"""
pmod_irq_block = """\
// JB1 is asynchronous to the 50 MHz Rocket fabric. Keep this as three
// physical flip-flops: ASYNC_REG guides placement for metastability MTBF,
// and SHREG_EXTRACT prevents Vivado from collapsing stages into an SRL.
(* ASYNC_REG = "TRUE", SHREG_EXTRACT = "NO" *)
reg [2:0] pmod_irq_sync = 3'b000;
always @(posedge fabric_clk) begin
if (fabric_reset) begin
pmod_irq_sync <= 3'b000;
end else begin
pmod_irq_sync <= {pmod_irq_sync[1:0], pmod_irq};
end
end
"""
pps_top_ports = ""
if port_by_name.get("gps_pps") == ("output", ""):
@@ -788,6 +806,7 @@ module genesys2_rocket_top (
{bscan_block}
{startup_block}
{pmod_spi_block}
{pmod_irq_block}
{chr(10).join(assigns)}
assign led = {{