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>
195 lines
6.4 KiB
Systemverilog
195 lines
6.4 KiB
Systemverilog
// retroDE_ps2 — tb_iop_ram_stub
|
|
//
|
|
// Unit test for iop_ram_stub. Mirrors the style of other primitive tests
|
|
// (bios_rom_stub / ee_ram_stub) — drive reads and writes from the TB,
|
|
// verify round-trip data, check trace emission and region/master tagging.
|
|
//
|
|
// Scenarios:
|
|
// 1. Post-reset read returns zero (zero-init)
|
|
// 2. Byte-wide writes with partial byte enables
|
|
// 3. Word-wide writes
|
|
// 4. Read-back matches write pattern
|
|
// 5. Trace events tagged as SUBSYS_IOP with region=IOP_RAM and
|
|
// caller-provided master_id
|
|
|
|
`timescale 1ns/1ps
|
|
|
|
module tb_iop_ram_stub;
|
|
|
|
localparam int SIZE_BYTES = 4 * 1024;
|
|
localparam int ADDR_W = $clog2(SIZE_BYTES);
|
|
|
|
logic clk;
|
|
logic rst_n;
|
|
|
|
initial clk = 1'b0;
|
|
always #5 clk = ~clk;
|
|
|
|
logic rd_en;
|
|
logic [ADDR_W-1:0] rd_addr;
|
|
logic [31:0] rd_data;
|
|
logic rd_valid;
|
|
|
|
logic wr_en;
|
|
logic [ADDR_W-1:0] wr_addr;
|
|
logic [31:0] wr_data;
|
|
logic [3:0] wr_be;
|
|
|
|
logic [7:0] master_id;
|
|
|
|
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;
|
|
|
|
iop_ram_stub #(.SIZE_BYTES(SIZE_BYTES)) u_iop_ram (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.rd_en(rd_en), .rd_addr(rd_addr),
|
|
.rd_data(rd_data), .rd_valid(rd_valid),
|
|
.wr_en(wr_en), .wr_addr(wr_addr),
|
|
.wr_data(wr_data), .wr_be(wr_be),
|
|
.master_id(master_id),
|
|
.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)
|
|
);
|
|
|
|
trace_sink_stub #(.FILENAME("iop_ram.trace"), .SINK_LABEL("iop_ram"))
|
|
u_trace (.clk(clk), .rst_n(rst_n),
|
|
.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));
|
|
|
|
// ------------------------------------------------------------------
|
|
// Counters
|
|
// ------------------------------------------------------------------
|
|
|
|
int iop_reads;
|
|
int iop_writes;
|
|
int iop_region_hits;
|
|
int errors;
|
|
|
|
initial begin
|
|
iop_reads = 0;
|
|
iop_writes = 0;
|
|
iop_region_hits = 0;
|
|
errors = 0;
|
|
end
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (rst_n && ev_valid && ev_subsys == trace_pkg::SUBSYS_IOP) begin
|
|
if (ev_event == trace_pkg::EV_READ) iop_reads <= iop_reads + 1;
|
|
if (ev_event == trace_pkg::EV_WRITE) iop_writes <= iop_writes + 1;
|
|
if (ev_arg3[7:0] == 8'd2) iop_region_hits <= iop_region_hits + 1;
|
|
end
|
|
end
|
|
|
|
// ------------------------------------------------------------------
|
|
// Helpers
|
|
// ------------------------------------------------------------------
|
|
|
|
task automatic do_write(input logic [ADDR_W-1:0] addr,
|
|
input logic [31:0] data,
|
|
input logic [3:0] be);
|
|
@(negedge clk);
|
|
wr_en = 1'b1;
|
|
wr_addr = addr;
|
|
wr_data = data;
|
|
wr_be = be;
|
|
@(negedge clk);
|
|
wr_en = 1'b0;
|
|
wr_addr = '0;
|
|
wr_data = 32'd0;
|
|
wr_be = 4'd0;
|
|
endtask
|
|
|
|
task automatic do_read_expect(input logic [ADDR_W-1:0] addr,
|
|
input logic [31:0] expected,
|
|
input string label);
|
|
@(negedge clk);
|
|
rd_en = 1'b1;
|
|
rd_addr = addr;
|
|
@(negedge clk);
|
|
rd_en = 1'b0;
|
|
rd_addr = '0;
|
|
if (rd_data !== expected || rd_valid !== 1'b1) begin
|
|
$error("[tb_iop_ram_stub] read %s: got 0x%08h valid=%0b expected 0x%08h",
|
|
label, rd_data, rd_valid, expected);
|
|
errors = errors + 1;
|
|
end
|
|
endtask
|
|
|
|
// ------------------------------------------------------------------
|
|
// Stimulus
|
|
// ------------------------------------------------------------------
|
|
|
|
logic [31:0] before_read;
|
|
|
|
initial begin
|
|
rst_n = 1'b0;
|
|
rd_en = 1'b0;
|
|
rd_addr = '0;
|
|
wr_en = 1'b0;
|
|
wr_addr = '0;
|
|
wr_data = 32'd0;
|
|
wr_be = 4'd0;
|
|
master_id = 8'd0;
|
|
|
|
repeat (4) @(posedge clk);
|
|
rst_n = 1'b1;
|
|
repeat (2) @(posedge clk);
|
|
|
|
// 1. Zero-init check
|
|
do_read_expect({ADDR_W{1'b0}}, 32'h0000_0000, "addr 0x0 after reset");
|
|
|
|
// 2. Word-wide write + read-back
|
|
master_id = 8'd0; // TB direct
|
|
do_write({ADDR_W{1'b0}}, 32'hCAFE_BABE, 4'b1111);
|
|
do_read_expect({ADDR_W{1'b0}}, 32'hCAFE_BABE, "word write round-trip");
|
|
|
|
// 3. Partial byte-enable write: preserve upper half, overwrite lower
|
|
// (start from known word value, write only be=0x3 with new data)
|
|
do_write({ADDR_W{1'b0}}, 32'h1234_0000, 4'b0011);
|
|
do_read_expect({ADDR_W{1'b0}}, 32'hCAFE_0000, "partial byte-enable low");
|
|
|
|
// 4. Non-zero master_id — IOP CPU hypothetical
|
|
master_id = 8'd2;
|
|
do_write(ADDR_W'(32'h0010), 32'hDEAD_BEEF, 4'b1111);
|
|
do_read_expect(ADDR_W'(32'h0010), 32'hDEAD_BEEF, "IOP-tagged write");
|
|
|
|
// 5. Address-distinct read — confirm storage independence
|
|
do_read_expect(ADDR_W'(32'h0020), 32'h0000_0000, "untouched slot");
|
|
|
|
repeat (4) @(posedge clk);
|
|
|
|
// ------------------------------------------------------------------
|
|
$display("[tb_iop_ram_stub] iop_reads=%0d iop_writes=%0d iop_region_hits=%0d errors=%0d",
|
|
iop_reads, iop_writes, iop_region_hits, errors);
|
|
|
|
if (iop_reads < 4) $error("expected >= 4 IOP read events, got %0d", iop_reads);
|
|
if (iop_writes < 3) $error("expected >= 3 IOP write events, got %0d", iop_writes);
|
|
if (iop_region_hits != iop_reads + iop_writes)
|
|
$error("region tag inconsistent: reads+writes=%0d region_hits=%0d",
|
|
iop_reads + iop_writes, iop_region_hits);
|
|
|
|
if (errors == 0 && iop_reads >= 4 && iop_writes >= 3 &&
|
|
iop_region_hits == iop_reads + iop_writes)
|
|
$display("[tb_iop_ram_stub] PASS");
|
|
else
|
|
$display("[tb_iop_ram_stub] FAIL");
|
|
|
|
$finish;
|
|
end
|
|
|
|
initial begin
|
|
#200000;
|
|
$error("[tb_iop_ram_stub] timeout");
|
|
$finish;
|
|
end
|
|
|
|
endmodule : tb_iop_ram_stub
|