From e15cb1b1023ccf4fd6bdb003dff551c679e18c5c Mon Sep 17 00:00:00 2001 From: martin-velay Date: Tue, 26 May 2026 17:39:53 +0200 Subject: [PATCH 1/4] [dv] Add support for HW_ID for SW - Related to issue #423 - This commit adds support for a HW_ID register that can be used by SW DV tests to identify the hardware they are running on. This is useful for SW DV tests that need to run on multiple hardware platforms and need a way to differentiate between them. - Add framework C test Signed-off-by: martin-velay --- hw/top_chip/dv/env/top_chip_dv_env_pkg.sv | 8 ++++++-- .../dv/sim_sram_axi/sim_sram_axi_if.sv | 2 ++ .../dv/sim_sram_axi/sim_sram_axi_sink.sv | 20 ++++++++++++++----- hw/top_chip/dv/tb/tb.sv | 4 ++++ hw/top_chip/dv/top_chip_sim_cfg.hjson | 18 +++++++++++++++++ .../dv/verilator/top_chip_verilator.sv | 10 +++++++++- 6 files changed, 54 insertions(+), 8 deletions(-) diff --git a/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv b/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv index e65aaab3d..49599f470 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv +++ b/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv @@ -41,11 +41,15 @@ package top_chip_dv_env_pkg; // 50 MHz Peripheral clock parameter int unsigned PeriClkFreq = 50_000_000; - // SW DV special write locations for test status and logging will always fit in 32-bits + // SW-DV special locations for test status, logging, and platform identification. + // These are intercepted by sim_sram_axi_sink before the AXI crossbar. parameter bit [31:0] SW_DV_START_ADDR = 'h2002_0000; parameter bit [31:0] SW_DV_SIZE = 'h0000_0100; // 256 bytes reserved for SW DV parameter bit [31:0] SW_DV_TEST_STATUS_ADDR = SW_DV_START_ADDR + 'h00; - parameter bit [31:0] SW_DV_LOG_ADDR = SW_DV_START_ADDR + 'h04; + parameter bit [31:0] SW_DV_HW_ID_ADDR = SW_DV_START_ADDR + 'h04; + parameter bit [31:0] SW_DV_LOG_ADDR = SW_DV_START_ADDR + 'h08; + + parameter bit [31:0] SW_DV_HW_ID = 32'h0000_002A; // File includes `include "mem_clear_util.sv" diff --git a/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_if.sv b/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_if.sv index 8ee38a068..f1d263759 100644 --- a/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_if.sv +++ b/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_if.sv @@ -15,6 +15,8 @@ interface sim_sram_axi_if ( // Control signals set by the Testbench logic [31:0] start_addr; logic [31:0] sw_dv_size; + logic [31:0] hw_id_addr; + logic [31:0] hw_id; // Monitor signals driven by the Sink axi_req_t req; diff --git a/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_sink.sv b/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_sink.sv index a5bd9f49e..cf4deaadc 100644 --- a/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_sink.sv +++ b/hw/top_chip/dv/sim_sram_axi/sim_sram_axi_sink.sv @@ -68,6 +68,17 @@ module sim_sram_axi_sink #( logic [top_pkg::AxiDataWidth-1:0] mem_rdata; logic [top_pkg::AxiStrbWidth-1:0] mem_be; + // True when the access targets the read-only HW_ID register. + logic hw_id_sel; + assign hw_id_sel = (mem_addr[31:0] == u_sim_sram_if.hw_id_addr); + + // Insert one cycle delay to align with mem_req_d + logic hw_id_sel_d; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) hw_id_sel_d <= 1'b0; + else hw_id_sel_d <= mem_req && !mem_we && hw_id_sel; + end + axi_to_mem #( .axi_req_t (top_pkg::axi_req_t ), .axi_resp_t (top_pkg::axi_resp_t ), @@ -102,9 +113,9 @@ module sim_sram_axi_sink #( end end : delayed_mem_req - // Assert Error if ErrOnRead is set and a read occurs + // Assert Error if ErrOnRead is set and a read occurs to a non-HW_ID address. if (ErrOnRead) begin : gen_err_on_read - `ASSERT(ErrOnRead_A, mem_req |-> mem_we, clk_i, !rst_ni) + `ASSERT(ErrOnRead_A, (mem_req && !hw_id_sel) |-> mem_we, clk_i, !rst_ni) end : gen_err_on_read // Conditional SRAM Instantiation @@ -138,9 +149,8 @@ module sim_sram_axi_sink #( ); end : gen_sram else begin : gen_no_sram - // If no SRAM, return 0s on read. - // Handshaking is handled by the common logic and axi_to_mem. - assign mem_rdata = '0; + // If no SRAM, return hw_id for RO register reads, 0 otherwise. + assign mem_rdata = hw_id_sel_d ? {{(AxiDataWidth-32){1'b0}}, u_sim_sram_if.hw_id} : '0; end : gen_no_sram // Simulation SRAM Interface Instance diff --git a/hw/top_chip/dv/tb/tb.sv b/hw/top_chip/dv/tb/tb.sv index 6a8967dab..dbb42d5eb 100644 --- a/hw/top_chip/dv/tb/tb.sv +++ b/hw/top_chip/dv/tb/tb.sv @@ -15,6 +15,8 @@ module tb; import top_chip_dv_env_pkg::SW_DV_START_ADDR; import top_chip_dv_env_pkg::SW_DV_TEST_STATUS_ADDR; import top_chip_dv_env_pkg::SW_DV_LOG_ADDR; + import top_chip_dv_env_pkg::SW_DV_HW_ID_ADDR; + import top_chip_dv_env_pkg::SW_DV_HW_ID; // Macro includes `include "uvm_macros.svh" @@ -247,6 +249,8 @@ module tb; // Set base of SW DV special write locations `SIM_SRAM_IF.start_addr = SW_DV_START_ADDR; `SIM_SRAM_IF.sw_dv_size = SW_DV_SIZE; + `SIM_SRAM_IF.hw_id = SW_DV_HW_ID; + `SIM_SRAM_IF.hw_id_addr = SW_DV_HW_ID_ADDR; `SIM_SRAM_IF.u_sw_test_status_if.sw_test_status_addr = SW_DV_TEST_STATUS_ADDR; `SIM_SRAM_IF.u_sw_logger_if.sw_log_addr = SW_DV_LOG_ADDR; diff --git a/hw/top_chip/dv/top_chip_sim_cfg.hjson b/hw/top_chip/dv/top_chip_sim_cfg.hjson index 115ab003a..ff0ad9fca 100644 --- a/hw/top_chip/dv/top_chip_sim_cfg.hjson +++ b/hw/top_chip/dv/top_chip_sim_cfg.hjson @@ -103,6 +103,20 @@ run_opts: ["+ChipMemSRAM_image_file={run_dir}/timer_interrupt_test_cheri_sram.vmem", "+ChipMemROM_image_file={run_dir}/bootrom.vmem"] } + { + name: test_framework_test + uvm_test_seq: top_chip_dv_base_vseq + sw_images: ["test_framework_test_vanilla_sram:5" "bootrom:5"] + run_opts: ["+ChipMemSRAM_image_file={run_dir}/test_framework_test_vanilla_sram.vmem", + "+ChipMemROM_image_file={run_dir}/bootrom.vmem"] + } + { + name: test_framework_test_cheri + uvm_test_seq: top_chip_dv_base_vseq + sw_images: ["test_framework_test_cheri_sram:5" "bootrom:5"] + run_opts: ["+ChipMemSRAM_image_file={run_dir}/test_framework_test_cheri_sram.vmem", + "+ChipMemROM_image_file={run_dir}/bootrom.vmem"] + } { name: test_framework_exception_test uvm_test_seq: top_chip_dv_base_vseq @@ -339,6 +353,8 @@ "rv_timer_smoke_cheri", "rv_timer_irq", "rv_timer_irq_cheri", + "test_framework_test", + "test_framework_test_cheri", "test_framework_exception_test", "test_framework_exception_test_cheri", "spi_device_smoke", @@ -389,6 +405,8 @@ { name: test_framework tests: [ + "test_framework_test", + "test_framework_test_cheri", "test_framework_exception_test", "test_framework_exception_test_cheri" ] diff --git a/hw/top_chip/dv/verilator/top_chip_verilator.sv b/hw/top_chip/dv/verilator/top_chip_verilator.sv index e5c1928bf..9e64bfdcd 100644 --- a/hw/top_chip/dv/verilator/top_chip_verilator.sv +++ b/hw/top_chip/dv/verilator/top_chip_verilator.sv @@ -187,9 +187,15 @@ module top_chip_verilator ( `define DUT u_top_chip_system `define SIM_SRAM_IF u_sim_sram.u_sim_sram_if + // Special addresses for SW-DV communication localparam bit [31:0] VERILATOR_SW_DV_START_ADDR = 'h2002_0000; localparam bit [31:0] VERILATOR_SW_DV_SIZE = 'h0000_0100; // 256 bytes reserved localparam bit [31:0] VERILATOR_SW_DV_TEST_STATUS_ADDR = VERILATOR_SW_DV_START_ADDR + 'h00; + localparam bit [31:0] VERILATOR_SW_DV_HW_ID_ADDR = VERILATOR_SW_DV_START_ADDR + 'h04; + + // Specific ID for SW-DV to identify that it's running on Verilator. This can be used by + // SW to adapt its behavior when running on Verilator vs other simulators or real hardware. + localparam bit [31:0] VERILATOR_HW_ID = 32'h0000_001A; // Signals to connect the sink top_pkg::axi_req_t sim_sram_cpu_req; @@ -228,10 +234,12 @@ module top_chip_verilator ( .data (`SIM_SRAM_IF.req.w.data[15:0] ) // Test status is 16-bits wide ); - // Set the start address and the size of the simulation SRAM + // Set special SW-DV registers initial begin `SIM_SRAM_IF.start_addr = VERILATOR_SW_DV_START_ADDR; `SIM_SRAM_IF.sw_dv_size = VERILATOR_SW_DV_SIZE; + `SIM_SRAM_IF.hw_id_addr = VERILATOR_SW_DV_HW_ID_ADDR; + `SIM_SRAM_IF.hw_id = VERILATOR_HW_ID; u_sw_test_status_if.sw_test_status_addr = VERILATOR_SW_DV_TEST_STATUS_ADDR; end From 21eb916a116b7e3d0b0d3de89242624d340a8f7d Mon Sep 17 00:00:00 2001 From: martin-velay Date: Wed, 3 Jun 2026 11:18:37 +0200 Subject: [PATCH 2/4] [fpga] Expose HW_ID register - Extend RestOfChipBase/Length in top_pkg to encompass the SW-DV window (0x2002_0000), routing it through the rest_of_chip port without touching top_chip_system. - Add a second device to the rest-of-chip crossbar in chip_mocha_genesys2 backed by axi_to_mem; reads to offset +0x04 return the Genesys2 platform identifier (0x0000_000A), enabling SW tests to detect the platform at runtime consistently with the sim infrastructure. Signed-off-by: martin-velay --- hw/top_chip/rtl/chip_mocha_genesys2.sv | 52 +++++++++++++++++++++++++- hw/top_chip/rtl/top_pkg.sv | 15 +++++--- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/hw/top_chip/rtl/chip_mocha_genesys2.sv b/hw/top_chip/rtl/chip_mocha_genesys2.sv index e877a2ba8..a933daef6 100644 --- a/hw/top_chip/rtl/chip_mocha_genesys2.sv +++ b/hw/top_chip/rtl/chip_mocha_genesys2.sv @@ -76,6 +76,7 @@ module chip_mocha_genesys2 #( ); // Local parameters localparam int unsigned InitialResetCycles = 4; + localparam bit [31:0] FpgaHwId = 32'h0000_000A; // FpgaGenesys2 // Rest of chip AXI crossbar configuration localparam axi_pkg::xbar_cfg_t xbar_cfg = '{ @@ -97,7 +98,8 @@ module chip_mocha_genesys2 #( // Rest of chip AXI crossbar address mapping axi_pkg::xbar_rule_64_t [xbar_cfg.NoAddrRules-1:0] addr_map; assign addr_map = '{ - '{ idx: top_pkg::Ethernet, start_addr: top_pkg::EthernetBase, end_addr: top_pkg::EthernetBase + top_pkg::EthernetLength } + '{ idx: top_pkg::SwDvWindowDevIdx, start_addr: top_pkg::SwDvWindowBase, end_addr: top_pkg::SwDvWindowBase + top_pkg::SwDvWindowLength }, + '{ idx: top_pkg::Ethernet, start_addr: top_pkg::EthernetBase, end_addr: top_pkg::EthernetBase + top_pkg::EthernetLength } }; // Internal clock signals @@ -155,6 +157,14 @@ module chip_mocha_genesys2 #( // Ethernet interrupt line logic ethernet_irq; + // SW-DV window AXI subordinate memory interface acting as a sink + logic hw_id_mem_req; + logic hw_id_mem_req_q; + logic hw_id_mem_we; + logic [top_pkg::AxiAddrWidth-1:0] hw_id_mem_addr; + logic [top_pkg::AxiDataWidth-1:0] hw_id_mem_rdata; + logic hw_id_sel_q; + // Clock generation clkgen_xil7series u_clk_gen ( .clk_200m_i (clk_200m), @@ -562,4 +572,44 @@ module chip_mocha_genesys2 #( .eth_rgmii_mdc_o (eth_mdc) ); + // SW-DV window: read-only HW_ID register. + // Uses the same axi_to_mem + 1-cycle loopback pattern as sim_sram_axi_sink. + // Writes are accepted and discarded. Reads return FpgaHwId at offset +0x08, 0 elsewhere. + axi_to_mem #( + .axi_req_t (top_pkg::axi_req_t ), + .axi_resp_t (top_pkg::axi_resp_t ), + .DataWidth (top_pkg::AxiDataWidth), + .AddrWidth (top_pkg::AxiAddrWidth), + .IdWidth (top_pkg::AxiIdWidth ), + .NumBanks (1 ) + ) u_hw_id_axi_to_mem ( + .clk_i (u_top_chip_system.clkmgr_clocks.clk_main_infra ), + .rst_ni (u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]), + .busy_o ( ), + .axi_req_i (xbar_device_req [top_pkg::SwDvWindowDevIdx] ), + .axi_resp_o (xbar_device_resp[top_pkg::SwDvWindowDevIdx] ), + .mem_req_o (hw_id_mem_req ), + .mem_gnt_i (1'b1 ), + .mem_addr_o (hw_id_mem_addr ), + .mem_wdata_o ( ), // Ignored: RO register + .mem_strb_o ( ), // Ignored: RO register + .mem_atop_o ( ), // Not used + .mem_we_o (hw_id_mem_we ), + .mem_rvalid_i (hw_id_mem_req_q ), + .mem_rdata_i (hw_id_mem_rdata ) + ); + + always_ff @(posedge u_top_chip_system.clkmgr_clocks.clk_main_infra + or negedge u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]) begin + if (!u_top_chip_system.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]) begin + hw_id_mem_req_q <= 1'b0; + hw_id_sel_q <= 1'b0; + end else begin + hw_id_mem_req_q <= hw_id_mem_req; + hw_id_sel_q <= hw_id_mem_req && !hw_id_mem_we && (hw_id_mem_addr[7:0] == 8'h04); + end + end + + assign hw_id_mem_rdata = hw_id_sel_q ? {{(top_pkg::AxiDataWidth-32){1'b0}}, FpgaHwId} : '0; + endmodule diff --git a/hw/top_chip/rtl/top_pkg.sv b/hw/top_chip/rtl/top_pkg.sv index 85425fc22..c476cf85c 100644 --- a/hw/top_chip/rtl/top_pkg.sv +++ b/hw/top_chip/rtl/top_pkg.sv @@ -40,7 +40,7 @@ package top_pkg; SRAMBase = 64'h1000_0000, DebugMemBase = 64'h2000_0000, MailboxBase = 64'h2001_0000, - RestOfChipBase = 64'h3000_0000, + RestOfChipBase = 64'h2002_0000, TlCrossbarBase = 64'h4000_0000, DRAMBase = 64'h8000_0000 } axi_addr_start_t; @@ -50,7 +50,7 @@ package top_pkg; localparam longint unsigned SRAMLength = 64'h0002_0000; localparam longint unsigned DebugMemLength = 64'h0000_1000; localparam longint unsigned MailboxLength = 64'h0001_0000; - localparam longint unsigned RestOfChipLength = 64'h0000_8000; + localparam longint unsigned RestOfChipLength = 64'h0FFE_8000; // 0x2002_0000 to 0x3000_7FFF localparam longint unsigned TlCrossbarLength = 64'h1000_0000; localparam longint unsigned DRAMPhysicalLength = 64'h4000_0000; @@ -64,7 +64,7 @@ package top_pkg; // Rest of chip AXI crossbar parameters localparam int RestOfChipAxiXbarHosts = 1; - localparam int RestOfChipAxiXbarDevices = 1; + localparam int RestOfChipAxiXbarDevices = 2; // Rest of chip AXI crossbar hosts and devices typedef enum int unsigned { @@ -72,15 +72,18 @@ package top_pkg; } rest_of_chip_axi_hosts_t; typedef enum int unsigned { - Ethernet = 0 + Ethernet = 0, + SwDvWindowDevIdx = 1 } rest_of_chip_axi_devices_t; typedef enum longint unsigned { - EthernetBase = 64'h3000_0000 + EthernetBase = 64'h3000_0000, + SwDvWindowBase = 64'h2002_0000 } rest_of_chip_axi_addr_start_t; // Memory lengths - localparam longint unsigned EthernetLength = 64'h0000_8000; + localparam longint unsigned EthernetLength = 64'h0000_8000; + localparam longint unsigned SwDvWindowLength = 64'h0000_0100; // Memory address masks localparam longint unsigned EthernetMask = EthernetLength - 1; From 7fcbaec61e7672f55399d0b90668af15626c6e54 Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Mon, 8 Jun 2026 11:20:12 +0100 Subject: [PATCH 3/4] sw: create DV register layout in HAL, adding `hw_id` Co-authored-by: martin-velay Signed-off-by: Alice Ziuziakowska --- sw/device/lib/hal/dv.h | 47 +++++++++++++++++++++++++++++ sw/device/lib/hal/mocha.c | 9 +++--- sw/device/lib/hal/mocha.h | 4 +-- sw/device/lib/test_framework/main.c | 16 ++++------ 4 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 sw/device/lib/hal/dv.h diff --git a/sw/device/lib/hal/dv.h b/sw/device/lib/hal/dv.h new file mode 100644 index 000000000..61315f443 --- /dev/null +++ b/sw/device/lib/hal/dv.h @@ -0,0 +1,47 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Design Verification (DV) register window. + +#pragma once + +#include + +/* These values are written to the test_status register of the DV window + * throughout a test to indicate test progression and outcome. */ +enum dv_test_status : uint32_t { + /* Test code has begun. */ + dv_test_status_in_test = 0x4354u, + /* The test has passed. */ + dv_test_status_passed = 0x900du, + /* The test has failed. */ + dv_test_status_failed = 0xbaadu, +}; + +/* These values are provided by the DV window from the hw_id register to + * indicate the current test platform. */ +enum dv_hwid : uint32_t { + /* Running on the Genesys2 FPGA. */ + dv_hwid_fpga_genesys2 = 0xau, + /* Running in a Verilator simulation. */ + dv_hwid_sim_verilator = 0x1au, + /* Running in a UVM simulation. */ + dv_hwid_sim_uvm = 0x2au, +}; + +typedef volatile struct [[gnu::aligned(4)]] dv_window_memory_layout { + /* test_status (0x0) */ + uint32_t test_status; + + /* hw_id (0x4) */ + const uint32_t hw_id; + + const uint8_t __reserved0[0x100 - 0x08]; +} *dv_window_t; + + +_Static_assert(__builtin_offsetof(struct dv_window_memory_layout, test_status) == 0x0ul, + "incorrect register test_status offset"); +_Static_assert(__builtin_offsetof(struct dv_window_memory_layout, hw_id) == 0x4ul, + "incorrect register hw_id offset"); diff --git a/sw/device/lib/hal/mocha.c b/sw/device/lib/hal/mocha.c index 46a9d583d..7fb82ec17 100644 --- a/sw/device/lib/hal/mocha.c +++ b/sw/device/lib/hal/mocha.c @@ -13,7 +13,7 @@ static const uintptr_t rom_base = 0x80000ul; static const uintptr_t mailbox_base = 0x20010000ul; -static const uintptr_t dv_test_status_base = 0x20020000ul; +static const uintptr_t dv_window_base = 0x20020000ul; static const uintptr_t ethernet_base = 0x30000000ul; static const uintptr_t gpio_base = 0x40000000ul; static const uintptr_t clkmgr_base = 0x40020000ul; @@ -193,11 +193,12 @@ void *mocha_system_dram(void) #endif /* defined(__riscv_zcherihybrid) */ } -void *mocha_system_dv_test_status(void) +dv_window_t mocha_system_dv_window(void) { #if defined(__riscv_zcherihybrid) - return create_mmio_capability(dv_test_status_base, 0x100u); + return ( + dv_window_t)create_mmio_capability(dv_window_base, sizeof(struct dv_window_memory_layout)); #else /* !defined(__riscv_zcherihybrid) */ - return (void *)dv_test_status_base; + return (dv_window_t)dv_window_base; #endif /* defined(__riscv_zcherihybrid) */ } diff --git a/sw/device/lib/hal/mocha.h b/sw/device/lib/hal/mocha.h index be8f33ffa..2ff9c21d9 100644 --- a/sw/device/lib/hal/mocha.h +++ b/sw/device/lib/hal/mocha.h @@ -7,6 +7,7 @@ #pragma once #include "hal/clkmgr.h" +#include "hal/dv.h" #include "hal/entropy_src.h" #include "hal/ethernet.h" #include "hal/gpio.h" @@ -50,5 +51,4 @@ timer_t mocha_system_timer(void); spi_host_t mocha_system_spi_host(void); plic_t mocha_system_plic(void); void *mocha_system_dram(void); - -void *mocha_system_dv_test_status(void); +dv_window_t mocha_system_dv_window(void); diff --git a/sw/device/lib/test_framework/main.c b/sw/device/lib/test_framework/main.c index 53c28fa27..6b8c0f065 100644 --- a/sw/device/lib/test_framework/main.c +++ b/sw/device/lib/test_framework/main.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "boot/trap.h" +#include "hal/dv.h" #include "hal/hart.h" #include "hal/mmio.h" #include "hal/mocha.h" @@ -12,12 +13,6 @@ #include #include -enum test_status { - TEST_STATUS_IN_TEST = 0x4354u, - TEST_STATUS_PASSED = 0x900du, - TEST_STATUS_FAILED = 0xbaadu, -}; - /* magic byte string to terminate the verilator simulation */ static const char magic[] = "\xd8\xaf\xfb\xa0\xc7\xe1\xa9\xd7"; @@ -53,11 +48,11 @@ test_exception_handler(struct trap_registers *registers, struct trap_context *co [[noreturn]] void test_exit(bool success) { uart_t console = mocha_system_uart(); - void *dv_test_status = mocha_system_dv_test_status(); + dv_window_t dv_window = mocha_system_dv_window(); uart_puts(console, "TEST RESULT: "); uart_puts(console, success ? "PASSED" : "FAILED"); - DEV_WRITE(dv_test_status, success ? TEST_STATUS_PASSED : TEST_STATUS_FAILED); + DEV_WRITE(&dv_window->test_status, success ? dv_test_status_passed : dv_test_status_failed); uart_putchar(console, '\n'); uart_puts(console, "Safe to exit simulator."); @@ -75,12 +70,13 @@ test_exception_handler(struct trap_registers *registers, struct trap_context *co [[noreturn]] void main(void) { uart_t console = mocha_system_uart(); - void *dv_test_status = mocha_system_dv_test_status(); + dv_window_t dv_window = mocha_system_dv_window(); uart_init(console); // Flush the uart uart_wait_for(console, uart_status_txidle); - DEV_WRITE(dv_test_status, TEST_STATUS_IN_TEST); + + DEV_WRITE(&dv_window->test_status, dv_test_status_in_test); bool result = test_main(console); // Flush the uart From 4c81bf7ab443c5db7ee27cb818af23594cbb48c3 Mon Sep 17 00:00:00 2001 From: martin-velay Date: Thu, 4 Jun 2026 11:32:32 +0200 Subject: [PATCH 4/4] [sw] Add HW_ID platform check Update the test framework smoketest to read the HW_ID register, validate it against known values, and fail on an unrecognised ID. Co-authored-by: Alice Ziuziakowska Signed-off-by: martin-velay --- sw/device/tests/test_framework/smoketest.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sw/device/tests/test_framework/smoketest.c b/sw/device/tests/test_framework/smoketest.c index 48b4fe7ae..3aafb7da2 100644 --- a/sw/device/tests/test_framework/smoketest.c +++ b/sw/device/tests/test_framework/smoketest.c @@ -2,11 +2,32 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +#include "hal/dv.h" +#include "hal/mocha.h" #include "hal/uart.h" #include bool test_main(uart_t console) { + dv_window_t dv_window = mocha_system_dv_window(); + uint32_t hwid = DEV_READ(&dv_window->hw_id); + uart_puts(console, "Test framework smoketest\n"); + + switch (hwid) { + case dv_hwid_fpga_genesys2: + uart_puts(console, "Platform: Genesys2 FPGA\n"); + break; + case dv_hwid_sim_verilator: + uart_puts(console, "Platform: Verilator Simulation\n"); + break; + case dv_hwid_sim_uvm: + uart_puts(console, "Platform: UVM Simulation\n"); + break; + default: + uart_puts(console, "Unknown Hardware ID\n"); + return false; + } + return true; }