Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions hw/top_chip/dv/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,15 @@ Because simulating the CPU boot ROM process is slow, we load the software binary
## SW-to-DV Communication

To facilitate interactions between the Software and the DV environment, we utilize the **`sim_sram_axi`** module.
This is a special hardware block inserted only during simulation that intercepts AXI traffic.

For more details, see: [sim_sram_axi/README.md](./sim_sram_axi/README.md)

### Mechanism

1. **Interception:** The module "swallows" traffic destined for a specific Simulation Address Range (`SW_DV_START_ADDR`).
Traffic outside this range is transparently forwarded to the AXI Crossbar.
1. **Dedicated crossbar port:** The SW-DV window (`0x2002_0000`, 256 bytes) is a first-class device on the main AXI crossbar inside `top_chip_system`.
The crossbar routes all accesses to this range out via the `sw_dv_req_o`/`sw_dv_resp_i` port pair, keeping it completely separate from the rest-of-chip bus.
In simulation, `tb.sv` connects `sim_sram_axi_sink` to this port as a plain AXI slave.
On FPGA, `chip_mocha_genesys2` connects the same port to its hardware ID logic.
2. **Binding:** In `tb.sv`, we `bind` verification interfaces (`sw_test_status_if` and `sw_logger_if`) to this module.

### Use Cases
Expand Down
8 changes: 6 additions & 2 deletions hw/top_chip/dv/env/top_chip_dv_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment thread
martin-velay marked this conversation as resolved.

// File includes
`include "mem_clear_util.sv"
Expand Down
2 changes: 2 additions & 0 deletions hw/top_chip/dv/sim_sram_axi/sim_sram_axi_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
74 changes: 25 additions & 49 deletions hw/top_chip/dv/sim_sram_axi/sim_sram_axi_sink.sv
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,14 @@ module sim_sram_axi_sink #(
input logic clk_i,
input logic rst_ni,

// Interface from CVA6 CPU
input top_pkg::axi_req_t cpu_req_i,
output top_pkg::axi_resp_t cpu_resp_o,

// Interface to AXI Crossbar
output top_pkg::axi_req_t xbar_req_o,
input top_pkg::axi_resp_t xbar_resp_i
// AXI slave port: receives only SW-DV window traffic from the crossbar
input top_pkg::axi_req_t axi_req_i,
output top_pkg::axi_resp_t axi_resp_o
);

import top_pkg::*;
import cva6_config_pkg::*;

// Internal AXI signals for the intercepted path
axi_req_t sim_req;
axi_resp_t sim_resp;

logic aw_select;
logic ar_select;

// Selection Logic
assign aw_select = (cpu_req_i.aw.addr >= u_sim_sram_if.start_addr) &&
(cpu_req_i.aw.addr < u_sim_sram_if.start_addr + u_sim_sram_if.sw_dv_size);
assign ar_select = (cpu_req_i.ar.addr >= u_sim_sram_if.start_addr) &&
(cpu_req_i.ar.addr < u_sim_sram_if.start_addr + u_sim_sram_if.sw_dv_size);

// AXI Demux: index 0 = System Bus, index 1 = Sim Sink
axi_demux_simple #(
.AxiIdWidth (AxiIdWidth ),
.AtopSupport (1'b0 ),
.axi_req_t (axi_req_t ),
.axi_resp_t (axi_resp_t ),
.NoMstPorts (2 ),
.MaxTrans (8 )
) i_axi_demux (
.clk_i,
.rst_ni,
.test_i (1'b0 ),
.slv_req_i (cpu_req_i ),
.slv_aw_select_i (aw_select ),
.slv_ar_select_i (ar_select ),
.slv_resp_o (cpu_resp_o ),
.mst_reqs_o ({sim_req, xbar_req_o} ),
.mst_resps_i ({sim_resp, xbar_resp_i})
);

// AXI Protocol conversion to memory interface
logic mem_req;
logic mem_req_d;
Expand All @@ -68,6 +31,19 @@ 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.
// axi_to_mem aligns addresses to AxiDataWidth/8 bytes, so compare against the
// 8-byte aligned hw_id_addr (clearing the lower 3 bits for a 64-bit bus).
logic hw_id_sel;
assign hw_id_sel = (mem_addr[31:0] == {u_sim_sram_if.hw_id_addr[31:3], 3'b000});

// 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 ),
Expand All @@ -79,8 +55,8 @@ module sim_sram_axi_sink #(
.clk_i (clk_i ),
.rst_ni (rst_ni ),
.busy_o ( ), // Not used
.axi_req_i (sim_req ),
.axi_resp_o (sim_resp ),
.axi_req_i (axi_req_i ),
.axi_resp_o (axi_resp_o ),
.mem_req_o (mem_req ),
.mem_gnt_i (1'b1 ), // ALWAYS GRANT: Sim SRAM is never busy
.mem_addr_o (mem_addr ),
Expand All @@ -102,9 +78,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
Expand Down Expand Up @@ -138,14 +114,14 @@ 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.
// hw_id at byte offset 4 occupies the upper 32 bits of the 64-bit AXI word [63:32].
assign mem_rdata = hw_id_sel_d ? {u_sim_sram_if.hw_id, {(AxiDataWidth-32){1'b0}}} : '0;
end : gen_no_sram

// Simulation SRAM Interface Instance
sim_sram_axi_if u_sim_sram_if (.clk_i, .rst_ni);
assign u_sim_sram_if.req = sim_req;
assign u_sim_sram_if.resp = sim_resp;
assign u_sim_sram_if.req = axi_req_i;
assign u_sim_sram_if.resp = axi_resp_o;

endmodule : sim_sram_axi_sink
51 changes: 16 additions & 35 deletions hw/top_chip/dv/tb/tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -60,6 +62,10 @@ module tb;
top_pkg::axi_dram_req_t dram_req;
top_pkg::axi_dram_resp_t dram_resp;

// ------ SW-DV window ------
top_pkg::axi_req_t sw_dv_req;
top_pkg::axi_resp_t sw_dv_resp;

dram_wrapper_sim u_dram_wrapper (
// Clock and reset.
.clk_i (dut.clkmgr_clocks.clk_main_infra),
Expand Down Expand Up @@ -133,6 +139,9 @@ module tb;
// DRAM.
.dram_req_o (dram_req ),
.dram_resp_i (dram_resp ),
// SW-DV window AXI.
.sw_dv_req_o (sw_dv_req ),
.sw_dv_resp_i (sw_dv_resp ),
// Rest of chip AXI tie-off.
.rest_of_chip_req_o ( ),
.rest_of_chip_resp_i ('0 ),
Expand All @@ -150,44 +159,14 @@ module tb;
assign (strong0, weak1) scl = (scl_en_o) ? scl_o : 1'b1;
assign (strong0, weak1) sda = (sda_en_o) ? sda_o : 1'b1;

// Signals to connect the sink
logic sim_sram_clk;
logic sim_sram_rst;
top_pkg::axi_req_t sim_sram_cpu_req;
top_pkg::axi_resp_t sim_sram_cpu_resp;
top_pkg::axi_req_t sim_sram_xbar_req;
top_pkg::axi_resp_t sim_sram_xbar_resp;

// CVA6 and Xbar uses clk_main_infra from clock manager and their request and response ports are
// interfaced in sim_sram_axi_sink module. Thus, use the same clock and reset as them to stay in
// sync.
assign sim_sram_clk = dut.clkmgr_clocks.clk_main_infra;
assign sim_sram_rst = dut.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel];

// Instantiate the AXI sink to intercept the AXI traffic within the simulation memory range
// to provide a dedicated channel for SW-to-DV communication.
// SW-DV sink: receives only SW-DV window traffic from the crossbar.
sim_sram_axi_sink u_sim_sram (
.clk_i (sim_sram_clk ),
.rst_ni (sim_sram_rst ),
.cpu_req_i (sim_sram_cpu_req ),
.cpu_resp_o (sim_sram_cpu_resp ),
.xbar_req_o (sim_sram_xbar_req ),
.xbar_resp_i (sim_sram_xbar_resp )
.clk_i (dut.clkmgr_clocks.clk_main_infra ),
.rst_ni (dut.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]),
.axi_req_i (sw_dv_req ),
.axi_resp_o (sw_dv_resp )
);

// Capture inputs FROM the DUT (Monitoring)
assign sim_sram_cpu_req = dut.cva6_to_sim_req;
assign sim_sram_xbar_resp = dut.xbar_host_resp[top_pkg::CVA6];

// Force outputs INTO the DUT (Overriding)
// We break the direct connection inside the RTL using forces
initial begin
// Ensure we wait for build/elaboration phases if necessary,
// though force on static hierarchy works at time 0.
force dut.xbar_host_req[top_pkg::CVA6] = sim_sram_xbar_req;
force dut.sim_to_cva6_resp = sim_sram_cpu_resp;
end

// ------ Memory backdoor accesses ------
if (prim_pkg::PrimTechName == "Generic") begin : gen_mem_bkdr_utils
initial begin
Expand Down Expand Up @@ -271,6 +250,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;

Expand Down
18 changes: 18 additions & 0 deletions hw/top_chip/dv/top_chip_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@
run_opts: ["+ChipMemSRAM_image_file={run_dir}/timer_interrupt_test_cheri_sram.vmem",
"+ChipMemROM_image_file={run_dir}/bootrom_scrambled.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_scrambled.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_scrambled.vmem"]
}
{
name: test_framework_exception_test
uvm_test_seq: top_chip_dv_base_vseq
Expand Down Expand Up @@ -346,6 +360,8 @@
"rv_timer_smoke_cheri",
"rv_timer_irq",
"rv_timer_irq_cheri",
"test_framework_test",
"test_framework_test_cheri",
Comment thread
martin-velay marked this conversation as resolved.
"test_framework_exception_test",
"test_framework_exception_test_cheri",
"spi_device_smoke",
Expand Down Expand Up @@ -398,6 +414,8 @@
{
name: test_framework
tests: [
"test_framework_test",
"test_framework_test_cheri",
"test_framework_exception_test",
"test_framework_exception_test_cheri"
]
Expand Down
42 changes: 20 additions & 22 deletions hw/top_chip/dv/verilator/top_chip_verilator.sv
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ module top_chip_verilator (
.dram_req_o (dram_req),
.dram_resp_i (dram_resp),

.sw_dv_req_o (sw_dv_req ),
.sw_dv_resp_i (sw_dv_resp),

.rest_of_chip_req_o ( ), // Rest of chip AXI tie-off
.rest_of_chip_resp_i ('0),

Expand Down Expand Up @@ -187,35 +190,28 @@ 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;
top_pkg::axi_resp_t sim_sram_cpu_resp;
top_pkg::axi_req_t sim_sram_xbar_req;
top_pkg::axi_resp_t sim_sram_xbar_resp;
// SW-DV window AXI signals: routed directly from the main crossbar via the dedicated port.
top_pkg::axi_req_t sw_dv_req;
top_pkg::axi_resp_t sw_dv_resp;

// Detect SW test termination.
// SW-DV sink: receives only SW-DV window traffic from the crossbar.
sim_sram_axi_sink u_sim_sram (
.clk_i (`DUT.clkmgr_clocks.clk_main_infra),
.rst_ni (`DUT.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]),
.cpu_req_i (sim_sram_cpu_req ),
.cpu_resp_o (sim_sram_cpu_resp ),
.xbar_req_o (sim_sram_xbar_req ),
.xbar_resp_i (sim_sram_xbar_resp )
.clk_i (`DUT.clkmgr_clocks.clk_main_infra ),
.rst_ni (`DUT.rstmgr_resets.rst_main_n[rstmgr_pkg::DomainMainSel]),
.axi_req_i (sw_dv_req ),
.axi_resp_o (sw_dv_resp )
);

// Connect the sim SRAM directly at CVA6 AXI interface
assign `DUT.sim_to_cva6_resp = sim_sram_cpu_resp;
// Drive the request back into the DUT's Crossbar
assign `DUT.xbar_host_req[top_pkg::CVA6] = sim_sram_xbar_req;

// Capture inputs FROM the DUT (Monitoring)
assign sim_sram_cpu_req = `DUT.cva6_to_sim_req;
assign sim_sram_xbar_resp = `DUT.xbar_host_resp[top_pkg::CVA6];

// Instantiate the SW test status interface & connect signals from sim_sram_if instance
// instantiated inside sim_sram. Bind would have worked nicely here, but Verilator segfaults
// when trace is enabled (#3951).
Expand All @@ -228,10 +224,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

Expand Down
Loading