Files
retroDE_ps2/sim/tb/ee/tb_ee_fetch_stub.sv
T
thejayman77 ec82764bef Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression
(272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps,
and all dump-derived textures/traces) is excluded via .gitignore and stays local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 20:10:50 -04:00

257 lines
9.6 KiB
Systemverilog

// 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