Files
retroDE_ps2/sim/tb/top/tb_top_psmct32_texalpha_demo.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

129 lines
6.7 KiB
Systemverilog

// retroDE_ps2 — tb_top_psmct32_texalpha_demo (Ch344)
//
// TOP-LEVEL TEXTURED + source-over ALPHA SPRITE demo, end-to-end through the BRAM BOARD VARIANT
// (top_psmct32_raster_demo_bram) with SPRITE_TEX_ALPHA=1 — the integration the de25 board top fits,
// driving gs_stub through the REGISTERED read2 wrapper (the model the unit TB now matches).
//
// EE bootlet (bios_texalpha.mem) + GIF payload (payload_texalpha.mem):
// U1 -> upload an 8x8 checkerboard-ALPHA texture (opaque-white / fully-transparent).
// U2 -> opaque BG SPRITE (ABE=0), solid blue, full 64x64.
// U3 -> textured-alpha SPRITE (PRIM SPRITE+TME+ABE, source-over) over screen (16,16)-(48,48).
//
// Per pixel of the overlay: As = TEXEL alpha. Opaque texel (A=0x80) -> Cv = Cs (the gray texel,
// identity MODULATE by a white tint); transparent texel (A=0) -> Cv = Cd (the blue BG shows through).
//
// Verification (PCRTC scanout RGB — what a board wires to the video PHY):
// - the BORDER (outside the overlay rect) is the pure blue BG.
// - EVERY overlay pixel is EITHER gray (0xC0,0xC0,0xC0) OR blue BG — nothing else (binary alpha,
// no garbage), and BOTH appear in quantity (the checkerboard + per-texel alpha both rendered).
`timescale 1ns/1ps
module tb_top_psmct32_texalpha_demo;
localparam int H_ACTIVE = 64, V_ACTIVE = 64;
localparam int SX0 = 16, SY0 = 16, SX1 = 48, SY1 = 48; // overlay sprite rect
logic clk, rst_n;
initial clk = 1'b0;
always #5 clk = ~clk;
logic core_go;
logic [7:0] r, g, b;
logic hsync, vsync, de;
logic core_halt, dma_done_seen, frame_seen, raster_overflow;
logic frame_toggle, dma_done_toggle;
top_psmct32_raster_demo_bram #(
.H_ACTIVE(H_ACTIVE), .V_ACTIVE(V_ACTIVE),
.VRAM_BYTES(32*1024), .PSMCT32_SWIZZLE(1'b0),
.SPRITE_TEX_ALPHA(1'b1)
) dut (
.clk(clk), .rst_n(rst_n), .core_go(core_go),
.r(r), .g(g), .b(b), .hsync(hsync), .vsync(vsync), .de(de),
.core_halt(core_halt), .dma_done_seen(dma_done_seen),
.frame_seen(frame_seen), .raster_overflow(raster_overflow),
.frame_toggle(frame_toggle), .dma_done_toggle(dma_done_toggle),
.joy_a_pressed_i(1'b0), .joy_b_pressed_i(1'b0)
);
// expected colors
localparam logic [7:0] BG_R=8'h00, BG_G=8'h00, BG_B=8'hC0; // blue BG
localparam logic [7:0] GR_R=8'hC0, GR_G=8'hC0, GR_B=8'hC0; // opaque-texel gray
logic [7:0] cap_r[0:V_ACTIVE-1][0:H_ACTIVE-1], cap_g[0:V_ACTIVE-1][0:H_ACTIVE-1], cap_b[0:V_ACTIVE-1][0:H_ACTIVE-1];
logic cap_de[0:V_ACTIVE-1][0:H_ACTIVE-1];
bit capture_armed;
initial begin
for (int y=0;y<V_ACTIVE;y++) for (int x=0;x<H_ACTIVE;x++) begin cap_r[y][x]=0;cap_g[y][x]=0;cap_b[y][x]=0;cap_de[y][x]=0; end
capture_armed=1'b0;
end
logic [31:0] hcnt_d, vcnt_d;
always_ff @(posedge clk) begin
if (!rst_n) begin hcnt_d<=0; vcnt_d<=0; end
else begin hcnt_d<=32'(dut.u_pcrtc.hcnt); vcnt_d<=32'(dut.u_pcrtc.vcnt); end
end
always_ff @(posedge clk)
if (rst_n && capture_armed && de && (vcnt_d<V_ACTIVE) && (hcnt_d<H_ACTIVE)) begin
cap_r[vcnt_d][hcnt_d]<=r; cap_g[vcnt_d][hcnt_d]<=g; cap_b[vcnt_d][hcnt_d]<=b; cap_de[vcnt_d][hcnt_d]<=1'b1; end
function automatic bit in_sprite(input int x, input int y);
in_sprite = (x>=SX0) && (x<SX1) && (y>=SY0) && (y<SY1);
endfunction
function automatic bit is_bg (input int x, input int y); is_bg = (cap_b[y][x]==BG_B)&&(cap_g[y][x]==BG_G)&&(cap_r[y][x]==BG_R); endfunction
function automatic bit is_gray(input int x, input int y); is_gray= (cap_b[y][x]==GR_B)&&(cap_g[y][x]==GR_G)&&(cap_r[y][x]==GR_R); endfunction
int errors, border_ok, spr_gray, spr_bg, spr_bad;
initial begin errors=0; border_ok=0; spr_gray=0; spr_bg=0; spr_bad=0; end
initial begin
rst_n=1'b0; core_go=1'b0;
repeat(4) @(posedge clk); rst_n=1'b1; repeat(8) @(posedge clk);
@(negedge clk); core_go=1'b1; @(negedge clk); core_go=1'b0;
wait (core_halt==1'b1); repeat(4) @(posedge clk);
wait (dma_done_seen==1'b1); repeat(10) @(posedge clk);
if (dut.xfer_busy==1'b1) wait (dut.xfer_busy==1'b0);
if (dut.u_gs.raster_active==1'b1) wait (dut.u_gs.raster_active==1'b0);
repeat(10) @(posedge clk);
@(posedge dut.u_pcrtc.end_of_frame); @(posedge clk); capture_armed=1'b1;
@(posedge dut.u_pcrtc.end_of_frame); @(posedge clk); capture_armed=1'b0;
for (int y=0;y<V_ACTIVE;y++) begin
for (int x=0;x<H_ACTIVE;x++) begin
if (!cap_de[y][x]) begin
if (errors<8) $error("[texalpha] (%0d,%0d) DE never asserted", x, y); errors++;
end else if (in_sprite(x,y)) begin
if (is_gray(x,y)) spr_gray++;
else if (is_bg(x,y)) spr_bg++;
else begin
spr_bad++;
if (errors<12) $error("[texalpha] overlay (%0d,%0d)=(%02x,%02x,%02x) is neither gray nor BG",
x, y, cap_b[y][x], cap_g[y][x], cap_r[y][x]);
errors++;
end
end else begin
// border: pure BG
if (is_bg(x,y)) border_ok++;
else begin
if (errors<12) $error("[texalpha] border (%0d,%0d)=(%02x,%02x,%02x) not BG blue",
x, y, cap_b[y][x], cap_g[y][x], cap_r[y][x]);
errors++;
end
end
end
end
// The checkerboard + per-texel alpha must BOTH render (gray opaque checks AND BG-through checks).
if (spr_gray < 64) begin $error("[texalpha] too few opaque (gray) overlay px (%0d) — texel/blend dead", spr_gray); errors++; end
if (spr_bg < 64) begin $error("[texalpha] too few transparent overlay px (%0d) — texel ALPHA not honored", spr_bg); errors++; end
if (spr_bad != 0) begin $error("[texalpha] %0d overlay px were neither gray nor BG", spr_bad); errors++; end
if (raster_overflow) begin $error("[texalpha] raster_overflow set"); errors++; end
$display("[tb_top_psmct32_texalpha_demo] border_ok=%0d overlay gray=%0d bg=%0d bad=%0d emits=%0d errors=%0d",
border_ok, spr_gray, spr_bg, spr_bad, dut.u_gs.raster_pixel_emit_count, errors);
if (errors==0) begin $display("[tb_top_psmct32_texalpha_demo] PASS"); $finish; end
else $fatal(1, "[tb_top_psmct32_texalpha_demo] FAIL (%0d errors)", errors);
end
initial begin #30000000; $error("[tb_top_psmct32_texalpha_demo] TIMEOUT"); $finish; end
endmodule : tb_top_psmct32_texalpha_demo