// retroDE_ps2 — tb_top_psmct32_sh3_zarb (Ch357 — SHARED-LPDDR arbitration integration sim, randomized backpressure) // // Codex pre-fit gate 1: "Shared-LPDDR integration sim with randomized backpressure. Arbitration is part of Ch357, not // just wiring." This routes gs_lpddr_zc_emit's THREE AXI streams through the REAL de25 arbiters onto ONE shared LPDDR: // * color writes (c_*) -> gs_lpddr_wr_arb port s0 (FB-writer, priority) // * Z writes (z_aw/w/b) -> gs_lpddr_wr_arb port s2 (repurposed tile-Z-flush port) // * Z reads (z_ar/r) -> gs_lpddr_rd_arb port s0 // During render only color/Z traffic is active (scanout/texture idle, per gate 2). One behavioral LPDDR serves BOTH the // merged write channel (m_aw/w/b) and the read channel (m_ar/r) with RANDOM backpressure on every channel. Replays the // raster fragment trace (zsched_frags.txt) + an independent clamp16 scoreboard; asserts final color+Z == scoreboard, // suppression, per-epoch ordered drain, disjoint ranges, no deadlock. This proves the arbitration under contention before // wiring the de25 top. Strong-reject primary fixture, FB 256x210. `timescale 1ns/1ps module tb_top_psmct32_sh3_zarb; localparam int FB_PXW=256, FB_H=210; localparam int NPX=FB_PXW*FB_H; localparam [31:0] COLBASE=32'h0000_0000, ZBASE=32'h0014_0000, TEXBASE=32'h0020_0000; localparam int MEMBEATS=(TEXBASE>>5); // one array up to the texture base (0x200000/32 = 65536 beats) logic gs_clk=0; always #5 gs_clk=~gs_clk; logic axi_clk=0; always #2 axi_clk=~axi_clk; logic gs_rst_n, axi_rst_n; int errors; initial errors=0; logic enable, clear_start, clear_done, frame_drained; logic g_valid, g_ready; logic [11:0] g_x, g_y; logic [15:0] g_zq; logic g_zmsk, g_ztest, g_scene; logic [31:0] g_color; // zc_emit Z AXI logic [31:0] z_araddr; logic [7:0] z_arlen; logic [2:0] z_arsize; logic [1:0] z_arburst; logic z_arvalid, z_arready; logic [255:0] z_rdata; logic [1:0] z_rresp; logic z_rlast, z_rvalid, z_rready; logic [31:0] z_awaddr; logic [7:0] z_awlen; logic [2:0] z_awsize; logic [1:0] z_awburst; logic z_awvalid, z_awready; logic [255:0] z_wdata; logic [31:0] z_wstrb; logic z_wlast, z_wvalid, z_wready; logic z_bvalid, z_bready; logic [1:0] z_bresp; // zc_emit Color AXI logic [31:0] c_awaddr; logic [7:0] c_awlen; logic [2:0] c_awsize; logic [1:0] c_awburst; logic c_awvalid, c_awready; logic [255:0] c_wdata; logic [31:0] c_wstrb; logic c_wlast, c_wvalid, c_wready; logic c_bvalid, c_bready; logic [1:0] c_bresp; logic [31:0] z_beats_read, z_beats_written, c_beats_written, col_ovf, bresp_err; logic idle; gs_lpddr_zc_emit #(.COLBASE(COLBASE), .ZBASE(ZBASE), .FB_PXW(FB_PXW), .FB_H(FB_H), .REQ_DEPTH(32), .COL_DEPTH(64)) dut ( .gs_clk(gs_clk), .gs_rst_n(gs_rst_n), .enable(enable), .g_valid(g_valid), .g_ready(g_ready), .g_x(g_x), .g_y(g_y), .g_zq(g_zq), .g_zmsk(g_zmsk), .g_ztest(g_ztest), .g_ztst(2'd2), .g_color(g_color), .g_be(4'hF), .g_scene(g_scene), .axi_clk(axi_clk), .axi_rst_n(axi_rst_n), .clear_start(clear_start), .clear_done(clear_done), .frame_drained(frame_drained), .z_araddr(z_araddr), .z_arlen(z_arlen), .z_arsize(z_arsize), .z_arburst(z_arburst), .z_arvalid(z_arvalid), .z_arready(z_arready), .z_rdata(z_rdata), .z_rresp(z_rresp), .z_rlast(z_rlast), .z_rvalid(z_rvalid), .z_rready(z_rready), .z_awaddr(z_awaddr), .z_awlen(z_awlen), .z_awsize(z_awsize), .z_awburst(z_awburst), .z_awvalid(z_awvalid), .z_awready(z_awready), .z_wdata(z_wdata), .z_wstrb(z_wstrb), .z_wlast(z_wlast), .z_wvalid(z_wvalid), .z_wready(z_wready), .z_bvalid(z_bvalid), .z_bready(z_bready), .z_bresp(z_bresp), .c_awaddr(c_awaddr), .c_awlen(c_awlen), .c_awsize(c_awsize), .c_awburst(c_awburst), .c_awvalid(c_awvalid), .c_awready(c_awready), .c_wdata(c_wdata), .c_wstrb(c_wstrb), .c_wlast(c_wlast), .c_wvalid(c_wvalid), .c_wready(c_wready), .c_bvalid(c_bvalid), .c_bready(c_bready), .c_bresp(c_bresp), .z_beats_read(z_beats_read), .z_beats_written(z_beats_written), .c_beats_written(c_beats_written), .col_ovf(col_ovf), .bresp_err(bresp_err), .idle(idle) ); // ---- write arbiter: s0 = color, s2 = Z, s1/s3 inert ; master -> shared LPDDR write ---- logic [29:0] m_awaddr; logic [1:0] m_awburst; logic [6:0] m_awid; logic [7:0] m_awlen; logic [2:0] m_awsize; logic m_awvalid, m_awready; logic [255:0] m_wdata; logic [31:0] m_wstrb; logic m_wlast, m_wvalid, m_wready; logic m_bvalid, m_bready; logic [1:0] m_bresp; gs_lpddr_wr_arb u_wr_arb ( .clk(axi_clk), .rst_n(axi_rst_n), .s0_awaddr(c_awaddr[29:0]), .s0_awburst(c_awburst), .s0_awid(7'd0), .s0_awlen(c_awlen), .s0_awsize(c_awsize), .s0_awvalid(c_awvalid), .s0_awready(c_awready), .s0_wdata(c_wdata), .s0_wstrb(c_wstrb), .s0_wlast(c_wlast), .s0_wvalid(c_wvalid), .s0_wready(c_wready), .s0_bresp(c_bresp), .s0_bvalid(c_bvalid), .s0_bready(c_bready), .s1_awaddr(30'd0), .s1_awburst(2'b01), .s1_awid(7'd1), .s1_awlen(8'd0), .s1_awsize(3'b101), .s1_awvalid(1'b0), .s1_awready(), .s1_wdata(256'd0), .s1_wstrb(32'd0), .s1_wlast(1'b0), .s1_wvalid(1'b0), .s1_wready(), .s1_bresp(), .s1_bvalid(), .s1_bready(1'b0), .s2_awaddr(z_awaddr[29:0]), .s2_awburst(z_awburst), .s2_awid(7'd2), .s2_awlen(z_awlen), .s2_awsize(z_awsize), .s2_awvalid(z_awvalid), .s2_awready(z_awready), .s2_wdata(z_wdata), .s2_wstrb(z_wstrb), .s2_wlast(z_wlast), .s2_wvalid(z_wvalid), .s2_wready(z_wready), .s2_bresp(z_bresp), .s2_bvalid(z_bvalid), .s2_bready(z_bready), .s3_awaddr(30'd0), .s3_awburst(2'b01), .s3_awid(7'd3), .s3_awlen(8'd0), .s3_awsize(3'b101), .s3_awvalid(1'b0), .s3_awready(), .s3_wdata(256'd0), .s3_wstrb(32'd0), .s3_wlast(1'b0), .s3_wvalid(1'b0), .s3_wready(), .s3_bresp(), .s3_bvalid(), .s3_bready(1'b0), .m_awaddr(m_awaddr), .m_awburst(m_awburst), .m_awid(m_awid), .m_awlen(m_awlen), .m_awsize(m_awsize), .m_awvalid(m_awvalid), .m_awready(m_awready), .m_wdata(m_wdata), .m_wstrb(m_wstrb), .m_wlast(m_wlast), .m_wvalid(m_wvalid), .m_wready(m_wready), .m_bvalid(m_bvalid), .m_bready(m_bready), .m_bresp(m_bresp) ); // ---- read arbiter: s0 = Z read ; s1/s2/s3 inert (scanout/tex idle during render) ; master -> shared LPDDR read ---- logic [29:0] m_araddr; logic [1:0] m_arburst; logic [6:0] m_arid; logic [7:0] m_arlen; logic [2:0] m_arsize; logic m_arvalid, m_arready; logic [255:0] m_rdata; logic [1:0] m_rresp; logic m_rlast, m_rvalid, m_rready; gs_lpddr_rd_arb u_rd_arb ( .clk(axi_clk), .rst_n(axi_rst_n), .s0_araddr(z_araddr[29:0]), .s0_arburst(z_arburst), .s0_arid(7'd0), .s0_arlen(z_arlen), .s0_arsize(z_arsize), .s0_arvalid(z_arvalid), .s0_arready(z_arready), .s0_rdata(z_rdata), .s0_rresp(z_rresp), .s0_rlast(z_rlast), .s0_rvalid(z_rvalid), .s0_rready(z_rready), .s1_araddr(30'd0), .s1_arburst(2'b01), .s1_arid(7'd1), .s1_arlen(8'd0), .s1_arsize(3'b101), .s1_arvalid(1'b0), .s1_arready(), .s1_rdata(), .s1_rresp(), .s1_rlast(), .s1_rvalid(), .s1_rready(1'b0), .s2_araddr(30'd0), .s2_arburst(2'b01), .s2_arid(7'd2), .s2_arlen(8'd0), .s2_arsize(3'b101), .s2_arvalid(1'b0), .s2_arready(), .s2_rdata(), .s2_rresp(), .s2_rlast(), .s2_rvalid(), .s2_rready(1'b0), .s3_araddr(30'd0), .s3_arburst(2'b01), .s3_arid(7'd3), .s3_arlen(8'd0), .s3_arsize(3'b101), .s3_arvalid(1'b0), .s3_arready(), .s3_rdata(), .s3_rresp(), .s3_rlast(), .s3_rvalid(), .s3_rready(1'b0), .m_araddr(m_araddr), .m_arburst(m_arburst), .m_arid(m_arid), .m_arlen(m_arlen), .m_arsize(m_arsize), .m_arvalid(m_arvalid), .m_arready(m_arready), .m_rdata(m_rdata), .m_rresp(m_rresp), .m_rlast(m_rlast), .m_rvalid(m_rvalid), .m_rready(m_rready) ); logic [15:0] lf=16'hF00D; always_ff @(posedge axi_clk) lf<={lf[14:0], lf[15]^lf[13]^lf[12]^lf[10]}; // ---- ONE shared behavioral LPDDR (write + read channels), address-decoded, random backpressure ---- logic [255:0] shmem [0:MEMBEATS-1]; logic [29:0] wa; logic [255:0] wd; logic [31:0] ws; logic aw_s, w_s; logic [3:0] bd; logic bp; logic [29:0] ra; logic rp; logic [3:0] rd_dly; always_ff @(posedge axi_clk or negedge axi_rst_n) begin if(!axi_rst_n) begin m_awready<=0; m_wready<=0; m_bvalid<=0; m_bresp<=0; aw_s<=0; w_s<=0; bp<=0; bd<=0; m_arready<=0; m_rvalid<=0; m_rlast<=0; m_rresp<=0; m_rdata<=0; rp<=0; rd_dly<=0; end else begin // write channel m_awready<=(!aw_s)?lf[0]:1'b0; m_wready<=(!w_s)?lf[1]:1'b0; if(m_awvalid&&m_awready) begin wa<=m_awaddr; aw_s<=1; m_awready<=0; end if(m_wvalid&&m_wready) begin wd<=m_wdata; ws<=m_wstrb; w_s<=1; m_wready<=0; end if(aw_s&&w_s&&!bp&&!m_bvalid) begin for(int b=0;b<32;b++) if(ws[b]) shmem[wa>>5][b*8+:8]<=wd[b*8+:8]; bp<=1; bd<={1'b0,lf[4:2]}; end if(bp&&!m_bvalid) begin if(bd==0) begin m_bvalid<=1;m_bresp<=0;bp<=0;aw_s<=0;w_s<=0; end else bd<=bd-1; end if(m_bvalid&&m_bready) m_bvalid<=0; // read channel m_arready<=(!rp&&!m_rvalid)?lf[8]:1'b0; if(m_arvalid&&m_arready) begin ra<=m_araddr; rp<=1; rd_dly<={1'b0,lf[7:5]}; m_arready<=0; end if(rp&&!m_rvalid) begin if(rd_dly==0) begin m_rdata<=shmem[ra>>5]; m_rresp<=0; m_rvalid<=1; m_rlast<=1; rp<=0; end else rd_dly<=rd_dly-1; end if(m_rvalid&&m_rready) begin m_rvalid<=0; m_rlast<=0; end end end // disjoint-range monitors on the MERGED master streams always_ff @(posedge axi_clk) if(axi_rst_n) begin if(m_awvalid) begin if(!((m_awaddr<30'(COLBASE+18288*32)) || (m_awaddr>=30'(ZBASE) && m_awaddr<30'(ZBASE+13440*32)))) begin $error("[zarb] merged AW %h not in color/Z range",m_awaddr); errors++; end end if(m_arvalid && (m_araddr<30'(ZBASE) || m_araddr>=30'(ZBASE+13440*32))) begin $error("[zarb] merged AR %h not in Z range",m_araddr); errors++; end end // ---- scoreboard + trace feed (same clamp16 persistent-Z model as the ROP gate) ---- logic [15:0] sb_z [0:NPX-1]; logic [31:0] sb_col [0:NPX-1]; logic sb_seen [0:NPX-1]; function automatic logic [15:0] cl16(input logic [31:0] z); cl16=(|z[31:16])?16'hFFFF:z[15:0]; endfunction int nfed; task automatic feed_frag(input int ep, input int x, input int y, input int z, input logic [31:0] col); int o; logic [15:0] zq; logic pass; @(negedge gs_clk); g_valid<=1; g_scene<=0; g_x<=x[11:0]; g_y<=y[11:0]; g_zq<=cl16(z); g_zmsk<=0; g_ztest<=1; g_color<=col; @(posedge gs_clk); while(!(g_valid && g_ready)) @(posedge gs_clk); @(negedge gs_clk); g_valid<=0; o=y*FB_PXW+x; zq=cl16(z); pass=(zq>=sb_z[o]); if(pass) begin sb_col[o]=col; sb_seen[o]=1; sb_z[o]=zq; end nfed++; if(lf[7]) repeat(1+lf[1:0]) @(posedge gs_clk); endtask task automatic send_marker(); @(negedge gs_clk); g_valid<=1; g_scene<=1; @(posedge gs_clk); while(!(g_valid && g_ready)) @(posedge gs_clk); @(negedge gs_clk); g_valid<=0; g_scene<=0; endtask int fh, r, ep, x, y, z, cep, drains; logic [31:0] col; initial begin errors=0; enable=0; clear_start=0; g_valid=0; g_scene=0; g_x=0; g_y=0; g_zq=0; g_zmsk=0; g_ztest=1; g_color=0; nfed=0; drains=0; for(int i=0;i>5; zl=o&15; zs=shmem[zb][zl*16+:16]; if(zs!==sb_z[o]) begin if(errors<12)$error("[zarb] Z px%0d=%04x exp %04x",o,zs,sb_z[o]);errors++; end end for(int o=0;o>3][(o[2:0])*32+:32]; // COLBASE=0 if(sb_seen[o]) begin if(cs!==sb_col[o]) begin if(errors<12)$error("[zarb] COLOR px%0d=%08x exp %08x",o,cs,sb_col[o]);errors++; end end else begin if(cs!==32'd0) begin if(errors<12)$error("[zarb] px%0d never-passed color=%08x (suppress)",o,cs);errors++; end end end if(col_ovf!==0) begin $error("[zarb] col_ovf=%0d",col_ovf);errors++; end if(bresp_err!==0)begin $error("[zarb] bresp_err=%0d",bresp_err);errors++; end $display("[zarb] fed=%0d drains=%0d z_wr=%0d c_wr=%0d col_ovf=%0d bresp_err=%0d errors=%0d (COL 0x%0h..0x%0h, Z 0x%0h..0x%0h)", nfed, drains, z_beats_written, c_beats_written, col_ovf, bresp_err, errors, COLBASE, COLBASE+18288*32, ZBASE, ZBASE+13440*32); if(errors==0) $display("[tb_top_psmct32_sh3_zarb] PASS"); else $display("[tb_top_psmct32_sh3_zarb] FAIL"); $finish; end initial begin #500000000; $error("[tb_top_psmct32_sh3_zarb] TIMEOUT"); $finish; end endmodule : tb_top_psmct32_sh3_zarb