ec82764bef
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>
179 lines
5.9 KiB
Systemverilog
179 lines
5.9 KiB
Systemverilog
// retroDE_ps2 — tb_ee_biu_mmio
|
|
//
|
|
// Chapter 9 targeted TB for ee_biu_mmio_stub. Same semantic shape
|
|
// as tb_ee_bootstrap_mmio (latched register file, per-byte write
|
|
// latching, 1-cycle read latency) but a separate module and a
|
|
// narrower 4 KiB address space. Verifies:
|
|
//
|
|
// 1) Reset-init-to-zero for probed offsets.
|
|
// 2) Write-then-read round-trip returns written value.
|
|
// 3) Distinct offsets don't collide.
|
|
// 4) Per-lane byte-enable preservation (SB-through-window, SH-
|
|
// through-window, and be=0 as no-op). These matter for the
|
|
// same reason as chapter 8 — the EE's sub-word store
|
|
// opcodes (SB/SH) can target this window.
|
|
//
|
|
// Targets the concrete offset the real BIOS touches: 0x130 (maps
|
|
// to word index 0x4C inside the 4 KiB window). That specific
|
|
// offset gets its own case, so if someone later narrows the
|
|
// decode and accidentally drops that offset, this TB catches it.
|
|
|
|
`timescale 1ns/1ps
|
|
|
|
module tb_ee_biu_mmio;
|
|
|
|
logic clk;
|
|
logic rst_n;
|
|
|
|
initial clk = 1'b0;
|
|
always #5 clk = ~clk;
|
|
|
|
// DUT ports
|
|
logic reg_wr_en;
|
|
logic [11:0] reg_wr_addr;
|
|
logic [31:0] reg_wr_data;
|
|
logic [3:0] reg_wr_be;
|
|
logic reg_rd_en;
|
|
logic [11:0] reg_rd_addr;
|
|
logic [31:0] reg_rd_data;
|
|
logic reg_rd_valid;
|
|
|
|
logic ev_valid;
|
|
trace_pkg::subsys_e ev_subsys;
|
|
trace_pkg::event_e ev_event;
|
|
logic [63:0] ev_arg0, ev_arg1, ev_arg2, ev_arg3;
|
|
logic [31:0] ev_flags;
|
|
|
|
ee_biu_mmio_stub dut (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.reg_wr_en(reg_wr_en), .reg_wr_addr(reg_wr_addr),
|
|
.reg_wr_data(reg_wr_data), .reg_wr_be(reg_wr_be),
|
|
.reg_rd_en(reg_rd_en), .reg_rd_addr(reg_rd_addr),
|
|
.reg_rd_data(reg_rd_data), .reg_rd_valid(reg_rd_valid),
|
|
.ev_valid(ev_valid), .ev_subsys(ev_subsys), .ev_event(ev_event),
|
|
.ev_arg0(ev_arg0), .ev_arg1(ev_arg1),
|
|
.ev_arg2(ev_arg2), .ev_arg3(ev_arg3),
|
|
.ev_flags(ev_flags)
|
|
);
|
|
|
|
int errors = 0;
|
|
|
|
task automatic do_write_be(input logic [11:0] addr,
|
|
input logic [31:0] data,
|
|
input logic [3:0] be);
|
|
@(negedge clk);
|
|
reg_wr_en = 1'b1;
|
|
reg_wr_addr = addr;
|
|
reg_wr_data = data;
|
|
reg_wr_be = be;
|
|
@(negedge clk);
|
|
reg_wr_en = 1'b0;
|
|
reg_wr_addr = 12'd0;
|
|
reg_wr_data = 32'd0;
|
|
reg_wr_be = 4'b0000;
|
|
endtask
|
|
|
|
task automatic do_write(input logic [11:0] addr, input logic [31:0] data);
|
|
do_write_be(addr, data, 4'b1111);
|
|
endtask
|
|
|
|
task automatic do_read(input logic [11:0] addr,
|
|
output logic [31:0] data_out);
|
|
@(negedge clk);
|
|
reg_rd_en = 1'b1;
|
|
reg_rd_addr = addr;
|
|
@(negedge clk);
|
|
reg_rd_en = 1'b0;
|
|
reg_rd_addr = 12'd0;
|
|
@(posedge clk);
|
|
data_out = reg_rd_data;
|
|
endtask
|
|
|
|
task automatic check(input string tag,
|
|
input logic [31:0] got,
|
|
input logic [31:0] exp);
|
|
if (got !== exp) begin
|
|
$display("[tb_ee_biu_mmio] FAIL %s got=0x%08h exp=0x%08h",
|
|
tag, got, exp);
|
|
errors++;
|
|
end else begin
|
|
$display("[tb_ee_biu_mmio] ok %s = 0x%08h", tag, got);
|
|
end
|
|
endtask
|
|
|
|
logic [31:0] rd0;
|
|
|
|
initial begin
|
|
rst_n = 1'b0;
|
|
reg_wr_en = 1'b0;
|
|
reg_wr_addr = 12'd0;
|
|
reg_wr_data = 32'd0;
|
|
reg_wr_be = 4'b0000;
|
|
reg_rd_en = 1'b0;
|
|
reg_rd_addr = 12'd0;
|
|
|
|
repeat (4) @(posedge clk);
|
|
rst_n = 1'b1;
|
|
@(posedge clk);
|
|
|
|
// 1) Reset-init: every probed offset reads 0.
|
|
do_read(12'h000, rd0); check("reset_read_0x000", rd0, 32'd0);
|
|
do_read(12'h130, rd0); check("reset_read_0x130_bios_touches_here",
|
|
rd0, 32'd0);
|
|
do_read(12'hFFC, rd0); check("reset_read_0xFFC", rd0, 32'd0);
|
|
|
|
// 2) Write-then-read at the BIOS-touched offset. Mirrors the
|
|
// real observed write pattern (cache-control config values).
|
|
do_write(12'h130, 32'h3202_000F);
|
|
do_read (12'h130, rd0); check("bios_0x130_writeread",
|
|
rd0, 32'h3202_000F);
|
|
|
|
// 3) Distinct offsets.
|
|
do_write(12'h000, 32'hAAAA_AAAA);
|
|
do_write(12'h140, 32'hBBBB_BBBB);
|
|
do_write(12'hFFC, 32'hCCCC_CCCC);
|
|
do_read (12'h000, rd0); check("distinct_0x000", rd0, 32'hAAAA_AAAA);
|
|
do_read (12'h140, rd0); check("distinct_0x140", rd0, 32'hBBBB_BBBB);
|
|
do_read (12'hFFC, rd0); check("distinct_0xFFC", rd0, 32'hCCCC_CCCC);
|
|
do_read (12'h130, rd0); check("prior_wr_preserved",
|
|
rd0, 32'h3202_000F);
|
|
|
|
// 4) Per-byte enables (SB).
|
|
do_write(12'h200, 32'h1122_3344);
|
|
do_write_be(12'h200, 32'h0000_00AA, 4'b0001);
|
|
do_read(12'h200, rd0); check("sb_lane0", rd0, 32'h1122_33AA);
|
|
|
|
do_write(12'h204, 32'h1122_3344);
|
|
do_write_be(12'h204, 32'hDD00_0000, 4'b1000);
|
|
do_read(12'h204, rd0); check("sb_lane3", rd0, 32'hDD22_3344);
|
|
|
|
// 5) Halfword enables (SH).
|
|
do_write(12'h300, 32'h1122_3344);
|
|
do_write_be(12'h300, 32'h0000_AABB, 4'b0011);
|
|
do_read(12'h300, rd0); check("sh_low", rd0, 32'h1122_AABB);
|
|
|
|
do_write(12'h304, 32'h1122_3344);
|
|
do_write_be(12'h304, 32'hCCDD_0000, 4'b1100);
|
|
do_read(12'h304, rd0); check("sh_high", rd0, 32'hCCDD_3344);
|
|
|
|
// 6) Zero-be no-op.
|
|
do_write(12'h400, 32'hDEAD_BEEF);
|
|
do_write_be(12'h400, 32'hFFFF_FFFF, 4'b0000);
|
|
do_read(12'h400, rd0); check("be_zero_noop", rd0, 32'hDEAD_BEEF);
|
|
|
|
if (errors == 0)
|
|
$display("[tb_ee_biu_mmio] PASS");
|
|
else
|
|
$display("[tb_ee_biu_mmio] FAIL errors=%0d", errors);
|
|
|
|
$finish;
|
|
end
|
|
|
|
initial begin
|
|
#5_000_000;
|
|
$display("[tb_ee_biu_mmio] TIMEOUT");
|
|
$finish;
|
|
end
|
|
|
|
endmodule : tb_ee_biu_mmio
|