Add generic IMU fusion and PMOD IRQ verification
This commit is contained in:
@@ -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)"
|
||||
|
||||
|
||||
@@ -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 = {{
|
||||
|
||||
Reference in New Issue
Block a user