// retroDE_ps2 — tb_ee_fetch_stub // // Milestone B integration test: ee_fetch_stub → ee_memory_map_stub → // bios_rom_stub. Verifies reset vector, BIOS-window fetches against the // synthetic fixture, unmapped access handling, and trace emission on all // three stubs. // // Plan ref: docs/stub_module_plan.md (Initial testbench plan). `timescale 1ns/1ps module tb_ee_fetch_stub; logic clk; logic rst_n; logic enable; // --- clock --- initial clk = 1'b0; always #5 clk = ~clk; // 100 MHz sim clock // ------------------------------------------------------------------ // DUTs: EE fetch → memory map → BIOS ROM // ------------------------------------------------------------------ // EE <-> memory map logic ee_rd_en; logic [31:0] ee_rd_addr; logic [31:0] ee_rd_data; logic ee_rd_valid; // TB-driven write channel into the map, used to exercise the UNMAPPED // path without disturbing the ee_fetch_stub → bios chain. In Wave 1 no // writable region exists, so any write lands as UNMAPPED. logic tb_wr_en; logic [31:0] tb_wr_addr; logic [31:0] tb_wr_data; logic [3:0] tb_wr_be; // Memory map <-> BIOS ROM logic bios_rd_en; logic [21:0] bios_rd_addr; logic [31:0] bios_rd_data; logic bios_rd_valid; // Trace ports per stub logic ee_ev_valid; trace_pkg::subsys_e ee_ev_subsys; trace_pkg::event_e ee_ev_event; logic [63:0] ee_ev_arg0, ee_ev_arg1, ee_ev_arg2, ee_ev_arg3; logic [31:0] ee_ev_flags; logic mem_ev_valid; trace_pkg::subsys_e mem_ev_subsys; trace_pkg::event_e mem_ev_event; logic [63:0] mem_ev_arg0, mem_ev_arg1, mem_ev_arg2, mem_ev_arg3; logic [31:0] mem_ev_flags; logic bios_ev_valid; trace_pkg::subsys_e bios_ev_subsys; trace_pkg::event_e bios_ev_event; logic [63:0] bios_ev_arg0, bios_ev_arg1, bios_ev_arg2, bios_ev_arg3; logic [31:0] bios_ev_flags; ee_fetch_stub u_ee ( .clk(clk), .rst_n(rst_n), .enable(enable), .rd_en(ee_rd_en), .rd_addr(ee_rd_addr), .rd_data(ee_rd_data), .rd_valid(ee_rd_valid), .ev_valid(ee_ev_valid), .ev_subsys(ee_ev_subsys), .ev_event(ee_ev_event), .ev_arg0(ee_ev_arg0), .ev_arg1(ee_ev_arg1), .ev_arg2(ee_ev_arg2), .ev_arg3(ee_ev_arg3), .ev_flags(ee_ev_flags) ); // Wave 2.7 added DMAC + RAM ports on the map. Not exercised by this TB — // tie inputs to inactive values, leave outputs unconnected. logic [127:0] tb_dmac_rd_data_sink; logic tb_dmac_rd_valid_sink; logic tb_ram_rd_en_sink; logic [24:0] tb_ram_rd_addr_sink; ee_memory_map_stub u_map ( .clk(clk), .rst_n(rst_n), .ee_rd_en(ee_rd_en), .ee_rd_addr(ee_rd_addr), .ee_rd_data(ee_rd_data), .ee_rd_valid(ee_rd_valid), .ee_wr_en(tb_wr_en), .ee_wr_addr(tb_wr_addr), .ee_wr_data(tb_wr_data), .ee_wr_be(tb_wr_be), .dmac_rd_en(1'b0), .dmac_rd_addr(32'd0), .dmac_rd_data(tb_dmac_rd_data_sink), .dmac_rd_valid(tb_dmac_rd_valid_sink), .bios_rd_en(bios_rd_en), .bios_rd_addr(bios_rd_addr), .bios_rd_data(bios_rd_data), .bios_rd_valid(bios_rd_valid), .ram_rd_en(tb_ram_rd_en_sink), .ram_rd_addr(tb_ram_rd_addr_sink), .ram_rd_data(128'd0), .ram_rd_valid(1'b0), .bridge_wr_en(1'b0), .bridge_wr_addr(32'd0), .bridge_wr_data(128'd0), .bridge_wr_be(16'd0), .bridge_master_id(8'd0), .ram_wr_en(), .ram_wr_addr(), .ram_wr_data(), .ram_wr_be(), .ram_master_id(), .ee_dmac_ch2_wr_en(), .ee_dmac_ch2_wr_addr(), .ee_dmac_ch2_wr_data(), .ee_dmac_ch2_rd_en(), .ee_dmac_ch2_rd_addr(), .ee_dmac_ch2_rd_data(32'd0), .ee_dmac_ch2_rd_valid(1'b0), .ee_intc_wr_en(), .ee_intc_wr_addr(), .ee_intc_wr_data(), .ee_intc_rd_en(), .ee_intc_rd_addr(), .ee_intc_rd_data(32'd0), .ee_intc_rd_valid(1'b0), .ee_misc_mmio_wr_en(), .ee_misc_mmio_wr_addr(), .ee_misc_mmio_wr_data(), .ee_misc_mmio_wr_be(), .ee_misc_mmio_rd_en(), .ee_misc_mmio_rd_addr(), .ee_misc_mmio_rd_data(32'd0), .ee_misc_mmio_rd_valid(1'b0), .ee_biu_wr_en(), .ee_biu_wr_addr(), .ee_biu_wr_data(), .ee_biu_wr_be(), .ee_biu_rd_en(), .ee_biu_rd_addr(), .ee_biu_rd_data(32'd0), .ee_biu_rd_valid(1'b0), .ev_valid(mem_ev_valid), .ev_subsys(mem_ev_subsys), .ev_event(mem_ev_event), .ev_arg0(mem_ev_arg0), .ev_arg1(mem_ev_arg1), .ev_arg2(mem_ev_arg2), .ev_arg3(mem_ev_arg3), .ev_flags(mem_ev_flags) ); bios_rom_stub u_bios ( .clk(clk), .rst_n(rst_n), .rd_en(bios_rd_en), .rd_addr(bios_rd_addr), .rd_data(bios_rd_data), .rd_valid(bios_rd_valid), .ev_valid(bios_ev_valid), .ev_subsys(bios_ev_subsys), .ev_event(bios_ev_event), .ev_arg0(bios_ev_arg0), .ev_arg1(bios_ev_arg1), .ev_arg2(bios_ev_arg2), .ev_arg3(bios_ev_arg3), .ev_flags(bios_ev_flags) ); // ------------------------------------------------------------------ // Trace sinks (one per stub) // ------------------------------------------------------------------ trace_sink_stub #(.FILENAME("ee_fetch.trace"), .SINK_LABEL("ee")) u_trace_ee ( .clk(clk), .rst_n(rst_n), .ev_valid(ee_ev_valid), .ev_subsys(ee_ev_subsys), .ev_event(ee_ev_event), .ev_arg0(ee_ev_arg0), .ev_arg1(ee_ev_arg1), .ev_arg2(ee_ev_arg2), .ev_arg3(ee_ev_arg3), .ev_flags(ee_ev_flags) ); trace_sink_stub #(.FILENAME("ee_mem.trace"), .SINK_LABEL("mem")) u_trace_mem ( .clk(clk), .rst_n(rst_n), .ev_valid(mem_ev_valid), .ev_subsys(mem_ev_subsys), .ev_event(mem_ev_event), .ev_arg0(mem_ev_arg0), .ev_arg1(mem_ev_arg1), .ev_arg2(mem_ev_arg2), .ev_arg3(mem_ev_arg3), .ev_flags(mem_ev_flags) ); trace_sink_stub #(.FILENAME("ee_bios.trace"), .SINK_LABEL("bios")) u_trace_bios ( .clk(clk), .rst_n(rst_n), .ev_valid(bios_ev_valid), .ev_subsys(bios_ev_subsys), .ev_event(bios_ev_event), .ev_arg0(bios_ev_arg0), .ev_arg1(bios_ev_arg1), .ev_arg2(bios_ev_arg2), .ev_arg3(bios_ev_arg3), .ev_flags(bios_ev_flags) ); // ------------------------------------------------------------------ // Checkers // ------------------------------------------------------------------ int ifetch_count; int unmapped_count; int errors; initial begin ifetch_count = 0; unmapped_count = 0; errors = 0; end // Count IFETCHes observed on the EE trace bus and verify each response // matches the synthetic NOP-sled fixture: data == 0x00000000 (MIPS NOP). // See sim/golden/trace_compare_spec.md for why the fixture is NOPs. wire [31:0] obs_addr = ee_ev_arg0[31:0]; wire [31:0] obs_data = ee_ev_arg1[31:0]; wire [31:0] obs_expected = 32'h00000000; always_ff @(posedge clk) begin if (rst_n && ee_ev_valid && ee_ev_event == trace_pkg::EV_IFETCH) begin ifetch_count <= ifetch_count + 1; if (obs_data !== obs_expected) begin $error("[tb_ee_fetch_stub] IFETCH mismatch: addr=0x%08h data=0x%08h expected=0x%08h", obs_addr, obs_data, obs_expected); errors <= errors + 1; end end if (rst_n && mem_ev_valid && mem_ev_event == trace_pkg::EV_UNMAPPED) begin unmapped_count <= unmapped_count + 1; end end // ------------------------------------------------------------------ // Stimulus // ------------------------------------------------------------------ initial begin rst_n = 1'b0; enable = 1'b0; tb_wr_en = 1'b0; tb_wr_addr = 32'd0; tb_wr_data = 32'd0; tb_wr_be = 4'd0; repeat (4) @(posedge clk); rst_n = 1'b1; // Phase 1: let ee_fetch run for a window of cycles. enable = 1'b1; repeat (32) @(posedge clk); enable = 1'b0; repeat (4) @(posedge clk); // Phase 2: drive a write to an unmapped region. Wave 1 has no // writable backing, so this must trace as MEM UNMAPPED with // flags bit 0 (write) set. @(negedge clk); tb_wr_en = 1'b1; tb_wr_addr = 32'h1000_0000; tb_wr_data = 32'hDEAD_BEEF; tb_wr_be = 4'hF; @(negedge clk); tb_wr_en = 1'b0; tb_wr_addr = 32'd0; tb_wr_data = 32'd0; tb_wr_be = 4'd0; repeat (4) @(posedge clk); // ------------------------------------------------------------------ // Summary // ------------------------------------------------------------------ $display("[tb_ee_fetch_stub] ifetch_count=%0d unmapped_count=%0d errors=%0d", ifetch_count, unmapped_count, errors); if (ifetch_count < 20) $error("[tb_ee_fetch_stub] expected at least 20 IFETCHes, got %0d", ifetch_count); if (unmapped_count < 1) $error("[tb_ee_fetch_stub] expected at least 1 UNMAPPED, got %0d", unmapped_count); if (errors == 0 && ifetch_count >= 20 && unmapped_count >= 1) $display("[tb_ee_fetch_stub] PASS"); else $display("[tb_ee_fetch_stub] FAIL"); $finish; end initial begin #100000; $error("[tb_ee_fetch_stub] timeout"); $finish; end endmodule : tb_ee_fetch_stub