Snapshot: fog implementation + fidelity tooling baseline (pre bilinear-clamp fix)
Per-vertex GS fog end-to-end (gs_stub emit incl. persp_emit5, gs_prim_list_feeder XYZ2->XYZF2 on PRIM.FGE, gs_make_sh3_scheduler_fixture.py F/FGE packing), new fog TBs, fidelity attribution tooling. Functional baseline before removing the dead bilinear lerp8 clamps (Codex: 161-node comb loop -> -0.042ns setup fail). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -365,6 +365,10 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
// bridge into an unreadable state — only the design domain
|
||||
// downstream of `core_rst_n` is held.
|
||||
wire bridge_core_reset_req;
|
||||
// Declared before every design-domain consumer. The runtime CLUT CDC is
|
||||
// instantiated above the reset synchronizer, so an inline declaration at
|
||||
// the assignment site would create an implicit, undriven early net.
|
||||
wire core_rst_n;
|
||||
|
||||
// ---- Ch229 tile broadcast (bridge CLOCK2_50 → tile_ram_cdc) ----
|
||||
// Driven by `u_hps_bridge` inside USE_QSYS_TOP; tied safe (zero +
|
||||
@@ -413,6 +417,35 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
wire feeder_stg_we_pulse_w = fdr_we_sync[2] ^ fdr_we_sync[1]; // 1 design_clk pulse per commit
|
||||
wire feeder_go_pulse_w = fdr_go_sync[2] ^ fdr_go_sync[1]; // 1 design_clk pulse per retrigger
|
||||
|
||||
// Ch367 -- runtime CLUT residency. The bridge writes a small palette
|
||||
// bank at CLOCK2_50; one commit toggle starts the bounded design-clock
|
||||
// copy into the existing CLUT writer port.
|
||||
wire [7:0] clut_stage_waddr_w;
|
||||
wire [31:0] clut_stage_wdata_w;
|
||||
wire clut_stage_we_w, clut_commit_tgl_w;
|
||||
wire [31:0] clut_expected_crc_w;
|
||||
wire runtime_clut_wr_en_w, runtime_clut_busy_w, runtime_clut_done_tgl_w;
|
||||
wire [7:0] runtime_clut_wr_idx_w;
|
||||
wire [31:0] runtime_clut_wr_data_w, runtime_clut_crc_w;
|
||||
|
||||
clut_stage_cdc u_runtime_clut (
|
||||
.bclk (CLOCK2_50),
|
||||
.breset_n (~ninit_done),
|
||||
.b_we (clut_stage_we_w),
|
||||
.b_waddr (clut_stage_waddr_w),
|
||||
.b_wdata (clut_stage_wdata_w),
|
||||
.b_commit_tgl (clut_commit_tgl_w),
|
||||
.b_expected_crc(clut_expected_crc_w),
|
||||
.dclk (design_clk),
|
||||
.dreset_n (core_rst_n),
|
||||
.clut_wr_en (runtime_clut_wr_en_w),
|
||||
.clut_wr_idx (runtime_clut_wr_idx_w),
|
||||
.clut_wr_data (runtime_clut_wr_data_w),
|
||||
.busy (runtime_clut_busy_w),
|
||||
.done_tgl (runtime_clut_done_tgl_w),
|
||||
.crc (runtime_clut_crc_w)
|
||||
);
|
||||
|
||||
// ---- Ch248 platform DS2 wired controller --------------------------
|
||||
// The shared `ds2_controller` runs on sys_clk (= CLOCK2_50 = 50 MHz),
|
||||
// drives CLK/CMD/ATTN to the controller, samples DATA, and surfaces
|
||||
@@ -502,7 +535,39 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
// Ch327a — line-buffer scanout geometry (the SCALABLE display path: O(width) BRAM, not
|
||||
// O(width*height) like the frame-cache). For the Ch326 PSMCT32 spill FB: 128 px * 4 B =
|
||||
// 512 B/row = 16 beats. (Default = the Ch321 128x128 PSMCT16 demo: 256 B/row = 8 beats.)
|
||||
`ifdef GS_TILE_SPILL
|
||||
`ifdef GS_SH3_LPDDR_FB
|
||||
`ifdef GS_SH3_LPDDR_FB_Z
|
||||
`ifdef GS_SH3_LPDDR_FB_640
|
||||
localparam int SCANOUT_LB_STRIDE = 2560; // Ch358 — persistent-Z at NATIVE 640 px * 4 B PSMCT32 (FBW=10)
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 80; // 2560 / 32
|
||||
localparam int SCANOUT_LB_NROWS = 480; // Ch358 — native 640x480, size 0x12C000, 38400 beats/frame
|
||||
`else
|
||||
localparam int SCANOUT_LB_STRIDE = 1024; // Ch357 — persistent-Z strong-reject fixture: 256 px * 4 B PSMCT32
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 32; // 1024 / 32
|
||||
localparam int SCANOUT_LB_NROWS = 210; // Ch357 — strong-reject primary (256x210), 6720 beats/frame
|
||||
`endif
|
||||
`elsif GS_SH3_LPDDR_FB_640
|
||||
localparam int SCANOUT_LB_STRIDE = 2560; // Ch357 — NATIVE 640 px * 4 B PSMCT32 (FBW=10)
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 80; // 2560 / 32
|
||||
localparam int SCANOUT_LB_NROWS = 480; // Ch357 — native 640x480, size 0x12C000, 38400 beats/frame
|
||||
`elsif GS_SH3_LPDDR_FB_SCHED
|
||||
localparam int SCANOUT_LB_STRIDE = 1536; // Ch356 — 384 px * 4 B PSMCT32 (FBW=6, N-texture scheduler union)
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 48; // 1536 / 32
|
||||
localparam int SCANOUT_LB_NROWS = 381; // Ch356 — 3-epoch union bbox (384x381), 18288 beats/frame
|
||||
`elsif GS_SH3_LPDDR_FB_MULTITEX
|
||||
localparam int SCANOUT_LB_STRIDE = 1280; // Ch355 — 320 px * 4 B PSMCT32 (FBW=5, multi-texture A+B union)
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 40; // 1280 / 32
|
||||
localparam int SCANOUT_LB_NROWS = 381; // Ch355 — A+B union bbox (320x381)
|
||||
`elsif GS_SH3_LPDDR_FB_MULTI
|
||||
localparam int SCANOUT_LB_STRIDE = 1024; // 256 px * 4 B PSMCT32
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 32;
|
||||
localparam int SCANOUT_LB_NROWS = 338; // Ch354 — multi-draw union bbox (256x338)
|
||||
`else
|
||||
localparam int SCANOUT_LB_STRIDE = 1024; // Ch353 — 256 px * 4 B PSMCT32
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 32; // 1024 / 32
|
||||
localparam int SCANOUT_LB_NROWS = 334; // Ch353 — single SH3 draw bounding box (256x334)
|
||||
`endif
|
||||
`elsif GS_TILE_SPILL
|
||||
localparam int SCANOUT_LB_STRIDE = 1024; // Ch327b — 256 px * 4 B PSMCT32
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 32; // 1024 / 32
|
||||
localparam int SCANOUT_LB_NROWS = 256;
|
||||
@@ -510,6 +575,26 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
localparam int SCANOUT_LB_STRIDE = 256;
|
||||
localparam int SCANOUT_LB_ROW_BEATS = 8;
|
||||
localparam int SCANOUT_LB_NROWS = 128;
|
||||
`endif
|
||||
// Ch418 — full-frame SH3 profiles preserve the dump's 512-pixel
|
||||
// FBW=8 source geometry while presenting it across the board's
|
||||
// 640-pixel VGA/HDMI active line. Other profiles remain 1:1.
|
||||
`ifdef GS_SH3_LPDDR_FB_640
|
||||
localparam bit SCANOUT_LB_H_STRETCH_5_TO_4 = 1'b1;
|
||||
localparam int SCANOUT_LB_V_SOURCE_START = 32;
|
||||
localparam bit SCANOUT_LB_V_STRETCH_15_TO_14 = 1'b1;
|
||||
localparam bit SCANOUT_LB_V_LINEAR_FILTER = 1'b0;
|
||||
localparam bit SCANOUT_LB_H_LINEAR_FILTER = 1'b0;
|
||||
localparam bit SCANOUT_LB_BINOMIAL_3X3_FILTER = 1'b1;
|
||||
localparam int SCANOUT_LB_H_SOURCE_PIXELS = 512;
|
||||
`else
|
||||
localparam bit SCANOUT_LB_H_STRETCH_5_TO_4 = 1'b0;
|
||||
localparam int SCANOUT_LB_V_SOURCE_START = 0;
|
||||
localparam bit SCANOUT_LB_V_STRETCH_15_TO_14 = 1'b0;
|
||||
localparam bit SCANOUT_LB_V_LINEAR_FILTER = 1'b0;
|
||||
localparam bit SCANOUT_LB_H_LINEAR_FILTER = 1'b0;
|
||||
localparam bit SCANOUT_LB_BINOMIAL_3X3_FILTER = 1'b0;
|
||||
localparam int SCANOUT_LB_H_SOURCE_PIXELS = 0;
|
||||
`endif
|
||||
// Initialize at declaration so iverilog doesn't bring up the
|
||||
// sim with an X on hps_reset_sync[1] — that X would AND into
|
||||
@@ -529,7 +614,7 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
end
|
||||
wire hps_core_reset = hps_reset_sync[1];
|
||||
|
||||
wire core_rst_n = rst_sync[1] & ~hps_core_reset;
|
||||
assign core_rst_n = rst_sync[1] & ~hps_core_reset;
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// core_go pulse — wait GO_DELAY cycles after core_rst_n
|
||||
@@ -592,6 +677,7 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
wire demo_flush_emit;
|
||||
wire [31:0] demo_flush_addr;
|
||||
wire [15:0] demo_flush_pix16;
|
||||
wire [3:0] demo_flush_be;
|
||||
wire [5:0] demo_flush_psm;
|
||||
wire [31:0] demo_vram_raddr; // Ch320 — PCRTC scanout VRAM byte address
|
||||
wire demo_pix_window; // Ch320 — high inside the displayed frame window
|
||||
@@ -622,6 +708,86 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
wire [31:0] demo_tile_reload_color; // reloaded color for raddr (1-cyc)
|
||||
wire [31:0] demo_tile_reload_z; // reloaded Z for raddr (1-cyc)
|
||||
wire [2:0] demo_tile_phase; // Ch323 diag — current tile phase (event-counter source)
|
||||
// Ch357 — persistent-Z ROP fragment stream (perspective path). u_demo emits per-fragment
|
||||
// {x,y,z} aligned to the flush color; gs_lpddr_zc_emit (under GS_SH3_LPDDR_FB_Z) does the
|
||||
// PSMZ16S clamp16 read/compare/update and emits color ONLY on Z-pass. Inert otherwise.
|
||||
wire [11:0] demo_flush_x;
|
||||
wire [11:0] demo_flush_y;
|
||||
wire [31:0] demo_flush_z;
|
||||
wire demo_flush_abe;
|
||||
wire [16:0] demo_flush_alpha;
|
||||
wire demo_flush_ztest;
|
||||
wire [1:0] demo_flush_ztst;
|
||||
wire demo_flush_zmsk;
|
||||
|
||||
// ============================ Ch353 render epoch (GS_SH3_LPDDR_FB) ============================
|
||||
// Codex round 5: with FEEDER_AUTOSTART=0 the boot setup ITSELF transitions into C_READY, so a flush gated on a
|
||||
// feeder_ready RISE alone would enqueue a FALSE end-of-scene EOF at setup — which would assert frame_drained the
|
||||
// instant the host later arms the writer. Gate the flush on an in-flight render instead:
|
||||
// sh3_render_inflight = set by an ACCEPTED host GO (feeder_go pulse WHILE ready)
|
||||
// sh3_fb_flush = sh3_render_inflight && feeder_ready RISE (render+drain complete) -> ONE EOF per render
|
||||
// sh3_render_inflight = cleared when the flush is issued
|
||||
// The writer's ordered drain ack (sh3_frame_drained, EMIF domain) then HARD-gates the scanout (no timeout).
|
||||
// Proven end-to-end by tb_top_psmct32_sh3_lpddr_fb_seq. Inert (flush tied 0) for every other profile.
|
||||
`ifdef GS_SH3_LPDDR_FB
|
||||
wire sh3_frame_drained; // driven by u_lpddr_axi .frame_drained (EMIF/axi domain)
|
||||
logic sh3_fb_flush, sh3_render_inflight, sh3_ready_q;
|
||||
wire sh3_ready_rise = feeder_ready_w && !sh3_ready_q;
|
||||
always_ff @(posedge design_clk or negedge core_rst_n) begin
|
||||
if (!core_rst_n) begin sh3_fb_flush<=1'b0; sh3_render_inflight<=1'b0; sh3_ready_q<=1'b0; end
|
||||
else begin
|
||||
sh3_ready_q <= feeder_ready_w;
|
||||
sh3_fb_flush <= 1'b0;
|
||||
if (feeder_go_pulse_w && feeder_ready_w) sh3_render_inflight <= 1'b1; // accepted GO opens the epoch
|
||||
if (sh3_render_inflight && sh3_ready_rise) begin
|
||||
sh3_fb_flush <= 1'b1; // exactly one EOF per render
|
||||
sh3_render_inflight <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
`else
|
||||
wire sh3_fb_flush = 1'b0;
|
||||
wire sh3_frame_drained = 1'b0; // non-SH3 profiles: tie off (fed to the bridge diagnostic, unused there)
|
||||
`endif
|
||||
`ifdef GS_SH3_LPDDR_FB_Z
|
||||
// ---- Ch357 persistent-Z ROP feed (design_clk) ----
|
||||
// The raster flush is the fragment producer; sh3_fb_flush (proven one-per-render ordered
|
||||
// scene-completion marker) rides the SAME request FIFO as the end-of-scene marker. clamp16 is
|
||||
// the vendored PCSX2 PSMZ16S source-Z saturation: min(z, 0xFFFF).
|
||||
wire [15:0] zc_g_zq_w = (|demo_flush_z[31:16]) ? 16'hFFFF : demo_flush_z[15:0];
|
||||
wire zc_frag_v = demo_flush_emit && (demo_flush_psm == 6'h00); // PSMCT32 raster fragment
|
||||
wire zc_g_valid = zc_frag_v || sh3_fb_flush;
|
||||
wire zc_g_scene = sh3_fb_flush; // ordered end-of-scene marker
|
||||
wire [11:0] zc_g_x = demo_flush_x;
|
||||
wire [11:0] zc_g_y = demo_flush_y;
|
||||
wire [15:0] zc_g_zq = zc_g_zq_w;
|
||||
wire zc_g_zmsk = demo_flush_zmsk;
|
||||
wire zc_g_ztest = demo_flush_ztest;
|
||||
wire [1:0] zc_g_ztst = demo_flush_ztst;
|
||||
wire [31:0] zc_g_color = demo_flush_color32;
|
||||
wire [16:0] zc_g_alpha = demo_flush_alpha;
|
||||
wire [3:0] zc_g_be = demo_flush_be;
|
||||
wire zc_g_ready; // driven by zc_emit
|
||||
// Fragment-drop guard: the request async FIFO SILENTLY drops when g_ready is low and the raster
|
||||
// cannot stall. Count every dropped request; the bridge snapshots this (0x0EC) + a sticky-nonzero bit
|
||||
// (0x02C[8]) so the HOST proves zero drops per scene (fail-closed), not just the randomized sim.
|
||||
reg [31:0] zc_g_drops_q;
|
||||
always_ff @(posedge design_clk or negedge core_rst_n) begin
|
||||
if (!core_rst_n) zc_g_drops_q <= 32'd0;
|
||||
else if (zc_g_valid && !zc_g_ready) zc_g_drops_q <= zc_g_drops_q + 32'd1;
|
||||
end
|
||||
wire [31:0] zc_g_drops = zc_g_drops_q;
|
||||
// Z-cache invalidate once at the initial host ARM (after the host preclears color+Z, before GO 1).
|
||||
// arm rises exactly once per session; the pulse invalidates gs_lpddr_z_rmw's write-back line so Z
|
||||
// then persists across every scheduler epoch (only clear_start invalidates; scene markers keep it).
|
||||
wire zc_clear_done;
|
||||
reg arm_e1, arm_e2, arm_e3;
|
||||
always_ff @(posedge emif_clk or negedge emif_reset_n) begin
|
||||
if (!emif_reset_n) begin arm_e1<=1'b0; arm_e2<=1'b0; arm_e3<=1'b0; end
|
||||
else begin arm_e1<=lpddr_arm_w; arm_e2<=arm_e1; arm_e3<=arm_e2; end
|
||||
end
|
||||
wire zc_clear_start = arm_e2 && !arm_e3; // emif-domain rising edge of arm
|
||||
`endif
|
||||
// Ch352 (Codex guardrail #1) — LPDDR texture-cache geometry as PROFILE PARAMETERS, not hardcoded over the
|
||||
// Ch322 tritex demo. SH3 real-draw crop: full 512x512 PSMT8 (262 KiB) in LPDDR, sampled at TBP=1024
|
||||
// (0x40000). Every other GS_LPDDR_TEX profile keeps the tritex 8x8 (2 KiB) geometry.
|
||||
@@ -629,6 +795,10 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
localparam int TEXC_VRAM_BASE = 32'h0004_0000; // crop TEX_VRAM_BASE = NEW_TBP(1024)*256
|
||||
localparam int TEXC_BYTES = 262144; // 512x512 PSMT8
|
||||
localparam int TEXC_NBEATS = 8192; // 262144 / 32 (single-beat 32 B reads)
|
||||
`elsif GS_SH3_LPDDR_FB
|
||||
localparam int TEXC_VRAM_BASE = 32'h0004_0000; // Ch353 — same 512x512 PSMT8 texture as the crop profile
|
||||
localparam int TEXC_BYTES = 262144;
|
||||
localparam int TEXC_NBEATS = 8192;
|
||||
`else
|
||||
localparam int TEXC_VRAM_BASE = 2048; // Ch322 tritex 8x8 PSMCT32
|
||||
localparam int TEXC_BYTES = 2048;
|
||||
@@ -642,12 +812,24 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
// this build path. Removing it retires the Ch159+ critical
|
||||
// path and frees the timing budget for a faster clock.
|
||||
.STRIP_HW_DIVIDER (1'b1),
|
||||
// Ch352 — SEQUENTIAL gradient divider (registered iterations, no combinational cone). This REPLACES the
|
||||
// combinational divide + the multicycle/false_path SDC approaches, which all made the Quartus fitter
|
||||
// grind on the divider cone for hours. The sequential divider closes timing with NO SDC exception.
|
||||
// Bit-exact to `/` (tb_gs_grad_divider) so the SH3 oracle stays 96.2%. GRAD_DIV_CYCLES below is ignored.
|
||||
.GRAD_SEQ_DIVIDER (1'b1),
|
||||
.GRAD_DIV_CYCLES (4),
|
||||
// Ch357 (Codex) — SEQUENTIAL gradient divider (registered iterations, NO combinational cone), now the board
|
||||
// default. The Ch352 seq-divider "prep trap" (>18 min, never reached Place) was caused by the combinational
|
||||
// signed `/` remaining UNCONDITIONALLY in the RTL alongside the sequential divider — Quartus inferred BOTH,
|
||||
// and the giant LPM divide cone is what ground Place/Prep for hours (twice: the SDC multicycle on the ~1157-
|
||||
// source combinational cone, then the numerator-register variant, both ground). Ch357 makes the two dividers
|
||||
// MUTUALLY EXCLUSIVE via generate (gs_stub g_combdiv/g_no_combdiv): at GRAD_SEQ_DIVIDER=1 the combinational `/`
|
||||
// does not exist in the netlist at all, so there is no divider cone and NO gradient SDC exception is applied.
|
||||
// Ch357 FINAL (Codex, 2026-07-05, after the isolation experiment ROUTED): keep the registered-numerator
|
||||
// COMBINATIONAL divide (grad_num_sel_q/grad_det_q -> grad_result_q). Ch417 widens the divide from 56/32 to
|
||||
// 64/35 bits, so use GRAD_DIV_CYCLES=5: design_clk = 40 ns (25 MHz) gives a 200 ns functional window instead
|
||||
// of relying on the old 160 ns window measured against the former 108 ns routed cone. The setup=5/hold=4
|
||||
// multicycle is applied STA-ONLY in the SDC (never
|
||||
// during quartus_fit), so the fitter keeps its known-CONVERGENT "hopeless single-cycle" behavior (places in
|
||||
// seconds) while final quartus_sta fail-closes at the 200 ns window. SEQUENTIAL divider (=1) is NOT used — it
|
||||
// traps this Agilex fitter even with the combinational `/` generate-stripped. Bit-exact to `/`; SH3 oracle
|
||||
// unchanged (tb_gs_grad_divider + the persp board-path equivalence 252/252).
|
||||
.GRAD_SEQ_DIVIDER (1'b0),
|
||||
.GRAD_DIV_CYCLES (5),
|
||||
// Ch163 — strip the PCRTC magnification divider. The demo
|
||||
// locks MAGH=MAGV=0 so the divisor is constant 1 and the
|
||||
// `hwin_rel / hmag_factor` / `vwin_rel / vmag_factor` math
|
||||
@@ -901,6 +1083,52 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.CLUT_CSM1_ENABLE (1'b1),
|
||||
.FEEDER_ENABLE (1'b1),
|
||||
.FEEDER_STG_WORDS (768) // 68 clipped tris -> ~655 staging words
|
||||
`elsif GS_SH3_LPDDR_FB
|
||||
// Ch353 — the SH3 real draw on an LPDDR-ONLY direct PSMCT32 framebuffer (the FULL 256x334 bounding box, NOT
|
||||
// the Ch352 256x120 BRAM crop). Same feeder-driven SH3 config as GS_SH3_REAL_DRAW_DEMO (real CSM1 CLUT +
|
||||
// Ch351 widened perspective + GS_LPDDR_TEX cache, GRAD_SEQ_DIVIDER=0 from the shared prefix = the known-
|
||||
// fitting combinational divide), but: FB_LPDDR_ONLY suppresses the BRAM raster mirror (the flush stream
|
||||
// drives the PSMCT32 LPDDR writer instead of BRAM), and FEEDER_AUTOSTART=0 so boot setup reaches C_READY
|
||||
// WITHOUT a render — the host arms the writer THEN pulses GO (0x0E8), and the render-epoch flush emits exactly
|
||||
// one EOF -> one frame_drained, which HARD-gates the line-buffer scanout (no timeout). VRAM stays 128 KiB /
|
||||
// CBP=480 (Codex option A — the known-fitting Ch352 config; the CLUT->CBP0 BRAM-shrink is deferred). Proven
|
||||
// end-to-end by tb_top_psmct32_sh3_lpddr_fb_seq (the mandatory fit gate). GS_LPDDR4B_FB + GS_LPDDR_TEX must
|
||||
// ALSO be defined (the build profile sets all three).
|
||||
.VRAM_BYTES (128 * 1024),
|
||||
.RAM_SIZE_BYTES (32 * 1024),
|
||||
.VRAM_ENABLE_READ2 (1'b0),
|
||||
.PSMCT32_SWIZZLE (1'b0),
|
||||
.COMBINED_TAZ (1'b0),
|
||||
.TILE_LOCAL (1'b0),
|
||||
.TILE_COLS (1),
|
||||
.TILE_ROWS (1),
|
||||
.TILE_MULTIPRIM (1'b0),
|
||||
.TILE_PRIM_COUNT (1),
|
||||
.TILE_FIFO_DEPTH (8),
|
||||
.BIN_BUFFER_ENABLE (1'b0),
|
||||
.HEARTBEAT_SPLICE_ENABLE (1'b0),
|
||||
.PERSPECTIVE_CORRECT(1'b1),
|
||||
.SUBPIXEL_XY (1'b1), // Ch416 — preserve native XYZ 12.4 and sample pixel centers
|
||||
.PERSP_RECIP_IDX_BITS(11),
|
||||
.BILINEAR_ENABLE (1'b1),
|
||||
.PALETTE_BILINEAR (1'b1),
|
||||
.CLUT_CSM1_ENABLE (1'b1),
|
||||
.FEEDER_ENABLE (1'b1),
|
||||
`ifdef GS_SH3_LPDDR_FB_Z
|
||||
.FEEDER_STG_WORDS (2048), // Ch402 — character draws split into staging-safe single-draw epochs
|
||||
`elsif GS_SH3_LPDDR_FB_640
|
||||
.FEEDER_STG_WORDS (2048), // Ch357 — native 640x480, same runtime-staged per-epoch list (619 words)
|
||||
`elsif GS_SH3_LPDDR_FB_SCHED
|
||||
.FEEDER_STG_WORDS (2048), // Ch356 — runtime-staged per-epoch list (68 tris / 619 words) + headroom
|
||||
`elsif GS_SH3_LPDDR_FB_MULTITEX
|
||||
.FEEDER_STG_WORDS (2048), // Ch355 — runtime-staged per-scene list (68 tris / 619 words) + headroom
|
||||
`elsif GS_SH3_LPDDR_FB_MULTI
|
||||
.FEEDER_STG_WORDS (2048), // Ch354 — 3-draw combined list = 204 tris / 1843 words (Codex-approved)
|
||||
`else
|
||||
.FEEDER_STG_WORDS (768), // Ch353 — single draw = 68 tris / ~655 words
|
||||
`endif
|
||||
.FEEDER_AUTOSTART (1'b0), // Ch353 — no boot render; host arms writer then GOes
|
||||
.FB_LPDDR_ONLY (1'b1) // Ch353 — flush -> LPDDR writer, no BRAM FB mirror
|
||||
`elsif GS_TILE_LATE_DEMO
|
||||
// Ch316 — LEADING-EMPTY-TILE traversal fix. ONE prim, ONLY in the LAST tile
|
||||
// t15 of the 4x4 grid; tiles t0..t14 are empty and precede it. Proves the
|
||||
@@ -1282,6 +1510,7 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.flush_emit_o (demo_flush_emit),
|
||||
.flush_addr_o (demo_flush_addr),
|
||||
.flush_pix16_o(demo_flush_pix16),
|
||||
.flush_be_o (demo_flush_be),
|
||||
.flush_psm_o (demo_flush_psm),
|
||||
.vram_read_addr_o(demo_vram_raddr), // Ch320 — PCRTC scanout addr for LPDDR4B scanout
|
||||
.pix_window_o (demo_pix_window), // Ch320 — displayed-frame window gate
|
||||
@@ -1293,6 +1522,15 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.tex_cache_ready_i(demo_tex_cache_ready),
|
||||
.tex_cache_hits_o(demo_tex_cache_hits),
|
||||
.tex_bram_hits_o (demo_tex_bram_hits),
|
||||
// Ch357 — persistent-Z ROP fragment coords + Z (perspective path), aligned to the flush color.
|
||||
.flush_x_o (demo_flush_x),
|
||||
.flush_y_o (demo_flush_y),
|
||||
.flush_z_o (demo_flush_z),
|
||||
.flush_abe_o (demo_flush_abe),
|
||||
.flush_alpha_o (demo_flush_alpha),
|
||||
.flush_ztest_o (demo_flush_ztest),
|
||||
.flush_ztst_o (demo_flush_ztst),
|
||||
.flush_zmsk_o (demo_flush_zmsk),
|
||||
// Ch323 — tile color+Z spill/reload (inert outputs when TILE_SPILL_ENABLE=0).
|
||||
.flush_color32_o (demo_flush_color32),
|
||||
.z_flush_emit_o (demo_z_flush_emit),
|
||||
@@ -1317,7 +1555,11 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.feeder_go_i (feeder_go_pulse_w),
|
||||
.feeder_ready_o (feeder_ready_w),
|
||||
.feeder_records_o (feeder_records_w),
|
||||
.feeder_waits_o (feeder_waits_w)
|
||||
.feeder_waits_o (feeder_waits_w),
|
||||
.runtime_clut_wr_en_i (runtime_clut_wr_en_w),
|
||||
.runtime_clut_wr_idx_i (runtime_clut_wr_idx_w),
|
||||
.runtime_clut_wr_data_i(runtime_clut_wr_data_w),
|
||||
.runtime_clut_busy_i (runtime_clut_busy_w)
|
||||
);
|
||||
`ifndef GS_LPDDR_TEX
|
||||
// Ch322 — no texture cache: the texel tap returns BRAM (bram-top mux constant-folds
|
||||
@@ -1592,8 +1834,21 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
end
|
||||
end
|
||||
wire video_src_eff = video_src_dclk;
|
||||
`ifdef GS_SH3_LPDDR_FB
|
||||
// Ch353 — HARD frame_drained gate (Codex round 5, NO timeout): blank BLACK until the ordered drain ack, THEN the
|
||||
// line-buffer scanout serves the LPDDR FB. frame_ready_emif gates the EMIF prefetch enable; frame_ready_r (design)
|
||||
// gates the HDMI source mux so unfilled line buffers can never show before the frame is drained. Failure (no ack)
|
||||
// stays black forever — no timeout fallback (a partial FB is exactly the bug this handshake prevents).
|
||||
logic [2:0] sh3_frd_dsync;
|
||||
always_ff @(posedge design_clk or posedge async_rst_assert) begin
|
||||
if (async_rst_assert) sh3_frd_dsync <= 3'd0; else sh3_frd_dsync <= {sh3_frd_dsync[1:0], sh3_frame_drained};
|
||||
end
|
||||
wire frame_ready_r = sh3_frd_dsync[2];
|
||||
wire frame_ready_emif = sh3_frame_drained;
|
||||
`else
|
||||
wire frame_ready_r = 1'b1; // other profiles: BRAM mirror is a stable fallback, no gate
|
||||
wire frame_ready_emif = 1'b1;
|
||||
`endif
|
||||
// emif-domain coherent bundled capture (LPDDR scanout enable + reader routing below).
|
||||
logic [2:0] commit_e_sync; logic video_src_emif, scanout_lb_emif;
|
||||
always_ff @(posedge emif_clk or negedge emif_reset_n) begin
|
||||
@@ -2052,7 +2307,10 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
// Ch324 Brick 3 — LPDDR scanout config: the spill profile scans the 64x64 PSMCT32 color
|
||||
// FB straight out of LPDDR at COLOR_SPILL_BASE (PCRTC addresses it BRAM-relative so
|
||||
// VRAM_BASE stays 0). Other LPDDR profiles keep the FB-at-0 PSMCT16 mirror.
|
||||
`ifdef GS_TILE_SPILL
|
||||
`ifdef GS_SH3_LPDDR_FB
|
||||
localparam [29:0] SCANOUT_FB_BASE = 30'd0; // Ch353 — FB at LPDDR base 0 (host sets 0x01C=0)
|
||||
localparam bit SCANOUT_PSMCT32 = 1'b1; // full-frame PSMCT32
|
||||
`elsif GS_TILE_SPILL
|
||||
localparam [29:0] SCANOUT_FB_BASE = COLOR_SPILL_BASE;
|
||||
localparam bit SCANOUT_PSMCT32 = 1'b1;
|
||||
`else
|
||||
@@ -2072,11 +2330,90 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
wire [7:0] fbw_awlen; wire [2:0] fbw_awsize; wire fbw_awvalid, fbw_awready;
|
||||
wire [255:0] fbw_wdata; wire [31:0] fbw_wstrb; wire fbw_wlast, fbw_wvalid, fbw_wready;
|
||||
wire [1:0] fbw_bresp; wire fbw_bvalid, fbw_bready;
|
||||
gs_lpddr_axi_master #(.FIFO_DEPTH(16)) u_lpddr_axi (
|
||||
`ifdef GS_SH3_LPDDR_FB_Z
|
||||
// ================= Ch357 — persistent-Z emit (gs_lpddr_zc_emit) =================
|
||||
// Replaces the plain color writer with a Z-then-color emitter: Z RMW (read/clamp16-compare/
|
||||
// update) FIRST, color enqueued ONLY on pass. Three AXI streams, routed onto the shared LPDDR
|
||||
// through the SAME de25 arbiters proven in tb_top_psmct32_sh3_zarb:
|
||||
// * color writes (c_*) -> fbw_* == gs_lpddr_wr_arb s0 (FB-writer, priority)
|
||||
// * Z writes (zw_*) -> gs_lpddr_wr_arb s2 (repurposed spill port; inert in this profile)
|
||||
// * Z reads (zr_*) -> gs_lpddr_rd_arb s3 (reload port; inert in this profile)
|
||||
// Fixture geometry: 256x210 strong-reject (Ch357) or NATIVE 640x480 (Ch358, +GS_SH3_LPDDR_FB_640).
|
||||
// Z base 0x140000 (disjoint from color: 640x480x4=0x12C000 < 0x140000; and tex: Z top 0x1D6000 < 0x200000).
|
||||
`ifdef GS_SH3_LPDDR_FB_640
|
||||
localparam int ZFB_PXW = 640, ZFB_H = 480;
|
||||
`else
|
||||
localparam int ZFB_PXW = 256, ZFB_H = 210;
|
||||
`endif
|
||||
wire [31:0] zw_awaddr; wire [7:0] zw_awlen; wire [2:0] zw_awsize; wire [1:0] zw_awburst;
|
||||
wire zw_awvalid, zw_awready;
|
||||
wire [255:0] zw_wdata; wire [31:0] zw_wstrb; wire zw_wlast, zw_wvalid, zw_wready;
|
||||
wire zw_bvalid, zw_bready; wire [1:0] zw_bresp;
|
||||
wire [31:0] zr_araddr; wire [7:0] zr_arlen; wire [2:0] zr_arsize; wire [1:0] zr_arburst;
|
||||
wire zr_arvalid, zr_arready;
|
||||
wire [255:0] zr_rdata; wire [1:0] zr_rresp; wire zr_rlast, zr_rvalid, zr_rready;
|
||||
wire [31:0] dr_araddr; wire [7:0] dr_arlen; wire [2:0] dr_arsize; wire [1:0] dr_arburst;
|
||||
wire dr_arvalid, dr_arready;
|
||||
wire [255:0] dr_rdata; wire [1:0] dr_rresp; wire dr_rlast, dr_rvalid, dr_rready;
|
||||
wire [31:0] c_awaddr; wire [7:0] c_awlen; wire [2:0] c_awsize; wire [1:0] c_awburst;
|
||||
wire c_awvalid;
|
||||
wire [255:0] c_wdata; wire [31:0] c_wstrb; wire c_wlast, c_wvalid;
|
||||
wire c_bready;
|
||||
// Request-FIFO sizing history: Ch368's adjacent-frame runtime-CLUT test needed 3610 entries (4096 passed;
|
||||
// 2048 clipped). The much larger Ch439 f52 production replay peaks at 6115 entries, establishing the 8192
|
||||
// production size below. zc_g_drops remains the fail-closed hardware guard.
|
||||
// (History: Ch357's tb_top_psmct32_sh3_zint showed a depth-64 request FIFO drops a small transient burst
|
||||
// (2 frags) when the Z-RMW stalls on a run of cache-line misses while the raster — which cannot honor
|
||||
// g_ready — keeps emitting; 256 sufficed for the zsched/zs640 scenes.)
|
||||
gs_lpddr_zc_emit #(.COLBASE(32'h0000_0000), .ZBASE(32'h0014_0000),
|
||||
// Ch439: the complete 311-epoch f52 replay peaks at 6,115
|
||||
// queued requests. 8K retains 2,077 entries (34%) of
|
||||
// measured headroom while halving the deep 93-bit FIFO's
|
||||
// M20K/address-tree footprint at 310 MHz.
|
||||
.FB_PXW(ZFB_PXW), .FB_H(ZFB_H), .REQ_DEPTH(8192), .COL_DEPTH(128)) u_zc_emit (
|
||||
.gs_clk(design_clk), .gs_rst_n(core_rst_n), .enable(1'b1),
|
||||
.g_valid(zc_g_valid), .g_ready(zc_g_ready), .g_x(zc_g_x), .g_y(zc_g_y), .g_zq(zc_g_zq),
|
||||
.g_zmsk(zc_g_zmsk), .g_ztest(zc_g_ztest), .g_ztst(zc_g_ztst), .g_color(zc_g_color), .g_alpha(zc_g_alpha), .g_be(zc_g_be), .g_scene(zc_g_scene),
|
||||
.axi_clk(emif_clk), .axi_rst_n(emif_reset_n),
|
||||
.clear_start(zc_clear_start), .clear_done(zc_clear_done), .frame_drained(sh3_frame_drained),
|
||||
.z_araddr(zr_araddr), .z_arlen(zr_arlen), .z_arsize(zr_arsize), .z_arburst(zr_arburst),
|
||||
.z_arvalid(zr_arvalid), .z_arready(zr_arready),
|
||||
.z_rdata(zr_rdata), .z_rresp(zr_rresp), .z_rlast(zr_rlast), .z_rvalid(zr_rvalid), .z_rready(zr_rready),
|
||||
.d_araddr(dr_araddr), .d_arlen(dr_arlen), .d_arsize(dr_arsize), .d_arburst(dr_arburst),
|
||||
.d_arvalid(dr_arvalid), .d_arready(dr_arready),
|
||||
.d_rdata(dr_rdata), .d_rresp(dr_rresp), .d_rlast(dr_rlast), .d_rvalid(dr_rvalid), .d_rready(dr_rready),
|
||||
.z_awaddr(zw_awaddr), .z_awlen(zw_awlen), .z_awsize(zw_awsize), .z_awburst(zw_awburst),
|
||||
.z_awvalid(zw_awvalid), .z_awready(zw_awready),
|
||||
.z_wdata(zw_wdata), .z_wstrb(zw_wstrb), .z_wlast(zw_wlast), .z_wvalid(zw_wvalid), .z_wready(zw_wready),
|
||||
.z_bvalid(zw_bvalid), .z_bready(zw_bready), .z_bresp(zw_bresp),
|
||||
.c_awaddr(c_awaddr), .c_awlen(c_awlen), .c_awsize(c_awsize), .c_awburst(c_awburst),
|
||||
.c_awvalid(c_awvalid), .c_awready(fbw_awready),
|
||||
.c_wdata(c_wdata), .c_wstrb(c_wstrb), .c_wlast(c_wlast), .c_wvalid(c_wvalid), .c_wready(fbw_wready),
|
||||
.c_bvalid(fbw_bvalid), .c_bready(c_bready), .c_bresp(fbw_bresp),
|
||||
.z_beats_read(), .z_beats_written(lpddr_bursts_w), .c_beats_written(lpddr_bytes_w),
|
||||
.col_ovf(lpddr_fifo_ovf_w), .bresp_err(lpddr_bresp_err_w), .idle(lpddr_idle_w)
|
||||
);
|
||||
// Color master -> fbw_* (gs_lpddr_wr_arb s0). c_* carries no awid; the arb tags s0 internally.
|
||||
assign fbw_awaddr = c_awaddr[29:0]; assign fbw_awburst = c_awburst; assign fbw_awid = 7'd0;
|
||||
assign fbw_awlen = c_awlen; assign fbw_awsize = c_awsize; assign fbw_awvalid = c_awvalid;
|
||||
assign fbw_wdata = c_wdata; assign fbw_wstrb = c_wstrb; assign fbw_wlast = c_wlast;
|
||||
assign fbw_wvalid = c_wvalid; assign fbw_bready = c_bready;
|
||||
assign emif_m_awaddr = 32'd0; assign emif_m_awid = 5'd0; // unused under _Z
|
||||
`else
|
||||
gs_lpddr_axi_master #(.FIFO_DEPTH(16)
|
||||
`ifdef GS_SH3_LPDDR_FB
|
||||
, .PIX_BYTES(4) // Ch353 — PSMCT32 = 8 px / 256-bit beat
|
||||
`endif
|
||||
) u_lpddr_axi (
|
||||
.gs_clk(design_clk), .gs_rst_n(core_rst_n), .enable(1'b1),
|
||||
.arm(lpddr_arm_w), .canary(lpddr_canary_w), .fb_base(lpddr_fb_base_w), .ctrl_commit(lpddr_ctrl_commit_w),
|
||||
`ifdef GS_SH3_LPDDR_FB
|
||||
.px_emit(demo_flush_emit && (demo_flush_psm == 6'h00)), // Ch353 — PSMCT32 raster emits only
|
||||
.px_addr(demo_flush_addr), .px_pix32(demo_flush_color32), .flush(sh3_fb_flush),
|
||||
`else
|
||||
.px_emit(demo_flush_emit && (demo_flush_psm == 6'h02)),
|
||||
.px_addr(demo_flush_addr), .px_pix16(demo_flush_pix16),
|
||||
.px_addr(demo_flush_addr), .px_pix32({16'd0, demo_flush_pix16}), .flush(1'b0),
|
||||
`endif
|
||||
.axi_clk(emif_clk), .axi_rst_n(emif_reset_n),
|
||||
.awaddr(emif_m_awaddr), .awlen(fbw_awlen), .awsize(fbw_awsize),
|
||||
.awburst(fbw_awburst), .awid(emif_m_awid), .awvalid(fbw_awvalid),
|
||||
@@ -2087,9 +2424,13 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.beats_written(lpddr_bytes_w), .bursts_issued(lpddr_bursts_w),
|
||||
.bresp_err_count(lpddr_bresp_err_w), .fifo_overflow_count(lpddr_fifo_ovf_w),
|
||||
.idle(lpddr_idle_w)
|
||||
`ifdef GS_SH3_LPDDR_FB
|
||||
, .frame_drained(sh3_frame_drained) // Ch353 — ordered drain ack -> hard scanout gate
|
||||
`endif
|
||||
);
|
||||
assign fbw_awaddr = emif_m_awaddr[29:0]; // EMIF addr is 30-bit (base 0)
|
||||
assign fbw_awid = {2'b00, emif_m_awid}; // EMIF awid is 7-bit
|
||||
`endif
|
||||
`ifdef GS_LPDDR_TEX
|
||||
// Ch322 — HPS write-probe (stage texture words) + 2:1 write arbiter (FB writer = priority).
|
||||
wire [29:0] wp_awaddr; wire [1:0] wp_awburst; wire [6:0] wp_awid;
|
||||
@@ -2116,10 +2457,17 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.s1_awsize(wp_awsize), .s1_awvalid(wp_awvalid), .s1_awready(wp_awready),
|
||||
.s1_wdata(wp_wdata), .s1_wstrb(wp_wstrb), .s1_wlast(wp_wlast), .s1_wvalid(wp_wvalid), .s1_wready(wp_wready),
|
||||
.s1_bresp(wp_bresp), .s1_bvalid(wp_bvalid), .s1_bready(wp_bready),
|
||||
`ifdef GS_SH3_LPDDR_FB_Z
|
||||
// Ch357 — s2 = persistent-Z write stream from gs_lpddr_zc_emit (zw_*).
|
||||
.s2_awaddr(zw_awaddr[29:0]), .s2_awburst(zw_awburst), .s2_awid(7'd6), .s2_awlen(zw_awlen), .s2_awsize(zw_awsize),
|
||||
.s2_awvalid(zw_awvalid), .s2_awready(zw_awready), .s2_wdata(zw_wdata), .s2_wstrb(zw_wstrb), .s2_wlast(zw_wlast),
|
||||
.s2_wvalid(zw_wvalid), .s2_wready(zw_wready), .s2_bresp(zw_bresp), .s2_bvalid(zw_bvalid), .s2_bready(zw_bready),
|
||||
`else
|
||||
// Ch323 — ports 2/3 (Z spill / HPS write-probe) unused in the GS_LPDDR_TEX build; tie inert.
|
||||
.s2_awaddr(30'd0), .s2_awburst(2'b01), .s2_awid(7'd6), .s2_awlen(8'd0), .s2_awsize(3'b101),
|
||||
.s2_awvalid(1'b0), .s2_awready(), .s2_wdata(256'd0), .s2_wstrb(32'd0), .s2_wlast(1'b0),
|
||||
.s2_wvalid(1'b0), .s2_wready(), .s2_bresp(), .s2_bvalid(), .s2_bready(1'b1),
|
||||
`endif
|
||||
.s3_awaddr(30'd0), .s3_awburst(2'b01), .s3_awid(7'd5), .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'b1),
|
||||
@@ -2284,6 +2632,8 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
// line-buffer; other profiles keep the runtime bridge bit (default frame-cache).
|
||||
`ifdef GS_TILE_SPILL
|
||||
wire scanout_lb_eff = 1'b1;
|
||||
`elsif GS_SH3_LPDDR_FB
|
||||
wire scanout_lb_eff = 1'b1; // Ch353 — always line-buffer (a 256x334 frame-cache = 334 KiB)
|
||||
`else
|
||||
wire scanout_lb_eff = scanout_lb_emif; // Ch352 — emif-domain coherent capture (not raw bridge bit)
|
||||
`endif
|
||||
@@ -2303,7 +2653,14 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
);
|
||||
gs_lpddr_scanout_lb #(.FB_BASE(SCANOUT_FB_BASE), .STRIDE_BYTES(SCANOUT_LB_STRIDE),
|
||||
.ROW_BEATS(SCANOUT_LB_ROW_BEATS), .N_ROWS(SCANOUT_LB_NROWS),
|
||||
.PSMCT32(SCANOUT_PSMCT32)) u_lpddr_scan_lb (
|
||||
.PSMCT32(SCANOUT_PSMCT32),
|
||||
.H_STRETCH_5_TO_4(SCANOUT_LB_H_STRETCH_5_TO_4),
|
||||
.V_SOURCE_START(SCANOUT_LB_V_SOURCE_START),
|
||||
.V_STRETCH_15_TO_14(SCANOUT_LB_V_STRETCH_15_TO_14),
|
||||
.V_LINEAR_FILTER(SCANOUT_LB_V_LINEAR_FILTER),
|
||||
.H_LINEAR_FILTER(SCANOUT_LB_H_LINEAR_FILTER),
|
||||
.H_SOURCE_PIXELS(SCANOUT_LB_H_SOURCE_PIXELS),
|
||||
.BINOMIAL_3X3_FILTER(SCANOUT_LB_BINOMIAL_3X3_FILTER)) u_lpddr_scan_lb (
|
||||
.axi_clk(emif_clk), .axi_rst_n(emif_reset_n),
|
||||
.enable(video_src_emif & scanout_lb_eff & frame_ready_emif),
|
||||
.video_clk(design_clk), .frame_start(demo_video_vsync),
|
||||
@@ -2354,6 +2711,9 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.s3_arready(reload_ar_arready),
|
||||
.s3_rdata(reload_r_rdata), .s3_rresp(reload_r_rresp), .s3_rlast(reload_r_rlast),
|
||||
.s3_rvalid(reload_r_rvalid), .s3_rready(reload_r_rready),
|
||||
.s4_araddr(dr_araddr[29:0]), .s4_arburst(dr_arburst), .s4_arid(7'd7),
|
||||
.s4_arlen(dr_arlen), .s4_arsize(dr_arsize), .s4_arvalid(dr_arvalid), .s4_arready(dr_arready),
|
||||
.s4_rdata(dr_rdata), .s4_rresp(dr_rresp), .s4_rlast(dr_rlast), .s4_rvalid(dr_rvalid), .s4_rready(dr_rready),
|
||||
.m_araddr(emif_ar_araddr), .m_arburst(emif_ar_arburst), .m_arid(emif_ar_arid),
|
||||
.m_arlen(emif_ar_arlen), .m_arsize(emif_ar_arsize), .m_arvalid(emif_ar_arvalid),
|
||||
.m_arready(emif_ar_arready),
|
||||
@@ -2413,6 +2773,14 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.color_o(demo_tile_reload_color), .z_o(demo_tile_reload_z),
|
||||
.reload_ready(demo_tile_reload_ready)
|
||||
);
|
||||
`elsif GS_SH3_LPDDR_FB_Z
|
||||
// Ch357 — read-port-3 carries the persistent-Z READ stream from gs_lpddr_zc_emit (zr_*).
|
||||
assign reload_ar_araddr=zr_araddr[29:0]; assign reload_ar_arburst=zr_arburst; assign reload_ar_arid=7'd6;
|
||||
assign reload_ar_arlen=zr_arlen; assign reload_ar_arsize=zr_arsize; assign reload_ar_arvalid=zr_arvalid;
|
||||
assign zr_arready=reload_ar_arready;
|
||||
assign zr_rdata=reload_r_rdata; assign zr_rresp=reload_r_rresp; assign zr_rlast=reload_r_rlast;
|
||||
assign zr_rvalid=reload_r_rvalid; assign reload_r_rready=zr_rready;
|
||||
assign reload_color_beats_w=32'd0; assign reload_z_beats_w=32'd0; assign reload_rd_errs_w=32'd0;
|
||||
`else
|
||||
// no reload engine — tie read-port-3 inert (arvalid=0, rready=1 drains) + counters 0.
|
||||
assign reload_ar_araddr=30'd0; assign reload_ar_arburst=2'b01; assign reload_ar_arid=7'd6;
|
||||
@@ -2434,7 +2802,7 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.gs_clk(design_clk), .gs_rst_n(core_rst_n), .enable(1'b1),
|
||||
.arm(lpddr_arm_w), .canary(lpddr_canary_w), .fb_base(lpddr_fb_base_w), .ctrl_commit(lpddr_ctrl_commit_w),
|
||||
.px_emit(demo_flush_emit && (demo_flush_psm == 6'h02)),
|
||||
.px_addr(demo_flush_addr), .px_pix16(demo_flush_pix16),
|
||||
.px_addr(demo_flush_addr), .px_pix32({16'd0, demo_flush_pix16}), .flush(1'b0),
|
||||
.axi_clk(CLOCK2_50), .axi_rst_n(~ninit_done),
|
||||
.awaddr(f2s_awaddr_w), .awlen(f2s_awlen_w), .awsize(f2s_awsize_w),
|
||||
.awburst(f2s_awburst_w), .awid(f2s_awid_w), .awvalid(f2s_awvalid_w),
|
||||
@@ -2682,6 +3050,15 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.emif_hps_emif_ref_clk_0_clk (LPDDR4A_REFCLK_p)
|
||||
);
|
||||
|
||||
// Ch357 — persistent-Z observability into the bridge (host fail-closed gates). Under GS_SH3_LPDDR_FB_Z the
|
||||
// zc_emit preclear ack + drop counter; tied 0 for every other profile (the status bits read 0 / clear_done 0).
|
||||
`ifdef GS_SH3_LPDDR_FB_Z
|
||||
wire bridge_clear_done = zc_clear_done; // emif domain (from gs_lpddr_zc_emit) -> 0x02C[7]
|
||||
wire [31:0] bridge_frag_drops = zc_g_drops; // design_clk domain -> 0x0EC snapshot + 0x02C[8] sticky
|
||||
`else
|
||||
wire bridge_clear_done = 1'b0;
|
||||
wire [31:0] bridge_frag_drops = 32'd0;
|
||||
`endif
|
||||
// The minimal null AXI4 slave for the hps2fpga bridge. Same port
|
||||
// signature as `splash_hps_bridge` so a future "real" ps2 bridge
|
||||
// can be dropped in without re-plumbing the top.
|
||||
@@ -2714,6 +3091,9 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.lpddr_bresp_err_i(lpddr_bresp_err_w),
|
||||
.lpddr_fifo_ovf_i (lpddr_fifo_ovf_w),
|
||||
.lpddr_idle_i (lpddr_idle_w),
|
||||
.frame_drained_i (sh3_frame_drained), // Ch353 — 0x02C[6] host-visible ordered drain ack (0 for non-SH3)
|
||||
.clear_done_i (bridge_clear_done), // Ch357 — 0x02C[7] persistent-Z preclear done (0 for non-Z)
|
||||
.frag_drops_i (bridge_frag_drops), // Ch357 — 0x0EC snapshot + 0x02C[8] sticky drop flag (0 for non-Z)
|
||||
.lpddr_rd_addr_o (lpddr_rd_addr_w),
|
||||
.lpddr_rd_pulse_o (lpddr_rd_pulse_w),
|
||||
.lpddr_rd_data_i (lpddr_rd_data_w),
|
||||
@@ -2849,7 +3229,16 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.feeder_go_tgl_o (feeder_go_tgl_w),
|
||||
.feeder_ready_i (feeder_ready_w),
|
||||
.feeder_records_i (feeder_records_w),
|
||||
.feeder_waits_i (feeder_waits_w)
|
||||
.feeder_waits_i (feeder_waits_w),
|
||||
|
||||
.clut_stage_waddr_o (clut_stage_waddr_w),
|
||||
.clut_stage_wdata_o (clut_stage_wdata_w),
|
||||
.clut_stage_we_o (clut_stage_we_w),
|
||||
.clut_commit_tgl_o (clut_commit_tgl_w),
|
||||
.clut_expected_crc_o (clut_expected_crc_w),
|
||||
.clut_busy_i (runtime_clut_busy_w),
|
||||
.clut_done_tgl_i (runtime_clut_done_tgl_w),
|
||||
.clut_crc_i (runtime_clut_crc_w)
|
||||
);
|
||||
|
||||
`else
|
||||
@@ -2886,6 +3275,11 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
assign feeder_go_tgl_w = 1'b0;
|
||||
assign feeder_stg_waddr_w = 12'd0;
|
||||
assign feeder_stg_wdata_w = 64'd0;
|
||||
assign clut_stage_waddr_w = 8'd0;
|
||||
assign clut_stage_wdata_w = 32'd0;
|
||||
assign clut_stage_we_w = 1'b0;
|
||||
assign clut_commit_tgl_w = 1'b0;
|
||||
assign clut_expected_crc_w = 32'd0;
|
||||
`endif // USE_QSYS_TOP
|
||||
|
||||
// Suppress unused-input warnings on lint (CLOCK0_50 / CLOCK1_50
|
||||
|
||||
@@ -195,12 +195,13 @@ module top_psmct32_raster_demo_bram
|
||||
// Default 0 generate-guards all perspective logic out (zero cost); only the
|
||||
// GS_PERSP_DEMO board profile sets it 1.
|
||||
parameter bit PERSPECTIVE_CORRECT = 1'b0,
|
||||
parameter bit SUBPIXEL_XY = 1'b0,
|
||||
parameter int PERSP_RECIP_IDX_BITS = 8, // Ch351 — perspective reciprocal LUT width (far-W -> 11)
|
||||
parameter int GRAD_DIV_CYCLES = 1, // Ch352 — triangle-setup divide settle cycles (board fits -> 4)
|
||||
parameter bit GRAD_SEQ_DIVIDER = 1'b0, // Ch352 — sequential gradient divider (board fits -> 1)
|
||||
// Ch344 — TEXTURED + source-over ALPHA SPRITE path (forwarded to gs_stub). Default 0 -> byte-identical.
|
||||
parameter bit SPRITE_TEX_ALPHA = 1'b0,
|
||||
parameter bit SPRITE_TEX_ALPHA_CLUT = 1'b0, // Ch347 — admit PSMT8 (CLUT) textures into the alpha-sprite path
|
||||
parameter bit SPRITE_TEX_ALPHA_CLUT = 1'b0, // Ch408 — admit PSMT8/PSMT4 CLUT textures into alpha sprites
|
||||
parameter bit CLUT_CSM1_ENABLE = 1'b0, // Ch350 — CSM1 16x16 CT32 grid CLUT load (SH3 indexed env path)
|
||||
// Ch302 — COMBINED textured+alpha+depth probe (forwarded to gs_stub). When 1,
|
||||
// a TME+ABE+ZTE triangle runs the multi-beat per-pixel FSM (Zread->Ztest->
|
||||
@@ -237,6 +238,11 @@ module top_psmct32_raster_demo_bram
|
||||
// dead logic, byte-identical for every existing profile.
|
||||
parameter bit FEEDER_ENABLE = 1'b0,
|
||||
parameter int FEEDER_STG_WORDS = 256,
|
||||
// Ch353 — auto-start the FIRST feeder render at C_SETUP (default, byte-identical). Set 0 ONLY for
|
||||
// the GS_SH3_LPDDR_FB profile: the disarmed boot render would otherwise leave a pending EOF that
|
||||
// falsely asserts frame_drained the instant the host later arms the writer. With AUTOSTART=0,
|
||||
// C_SETUP transitions straight to C_READY (no render) and every render waits for an explicit GO.
|
||||
parameter bit FEEDER_AUTOSTART = 1'b1,
|
||||
// Ch315 — primitive FIFO / per-tile bin depth (capacity). Power-of-2, default
|
||||
// 4 = byte-identical. GS_TILE_CAP_DEMO sets 8 to scale capacity past the old 4.
|
||||
parameter int TILE_FIFO_DEPTH = 4,
|
||||
@@ -366,7 +372,16 @@ module top_psmct32_raster_demo_bram
|
||||
output logic [31:0] flush_addr_o, // linear FB byte address
|
||||
output logic [15:0] flush_pix16_o,
|
||||
output logic [31:0] flush_color32_o, // Ch323 — full 32-bit flushed color (for spill round-trip capture)
|
||||
output logic [3:0] flush_be_o, // FRAME.FBMSK-compressed byte enables
|
||||
output logic [5:0] flush_psm_o,
|
||||
output logic [11:0] flush_x_o, // Ch357 — fragment x/y/z for the external LPDDR-Z ROP (perspective path)
|
||||
output logic [11:0] flush_y_o,
|
||||
output logic [31:0] flush_z_o,
|
||||
output logic flush_abe_o,
|
||||
output logic [16:0] flush_alpha_o,
|
||||
output logic flush_ztest_o,
|
||||
output logic [1:0] flush_ztst_o,
|
||||
output logic flush_zmsk_o,
|
||||
// Ch323 — tile Z-FLUSH stream (TILE_SPILL_ENABLE; the de25 routes it to an LPDDR Z-backing
|
||||
// writer). z_flush_addr_o is Z-backing-relative (pixel_index*4, 32-bit Z). Inert/0 unless
|
||||
// spilling; unused (left open) by every existing consumer.
|
||||
@@ -416,7 +431,15 @@ module top_psmct32_raster_demo_bram
|
||||
input logic feeder_go_i, // retrigger pulse (honoured only in C_READY)
|
||||
output logic feeder_ready_o, // control FSM is in C_READY (a new list may start)
|
||||
output logic [15:0] feeder_records_o, // primitives emitted by the current list
|
||||
output logic [31:0] feeder_waits_o // cycles the feeder paused under fifo_full
|
||||
output logic [31:0] feeder_waits_o, // cycles the feeder paused under fifo_full
|
||||
|
||||
// Ch367 -- runtime palette residency. The design-clock staging copier
|
||||
// owns this writer while busy; the legacy TEX0/VRAM loader remains the
|
||||
// sole writer at every other time.
|
||||
input logic runtime_clut_wr_en_i,
|
||||
input logic [7:0] runtime_clut_wr_idx_i,
|
||||
input logic [31:0] runtime_clut_wr_data_i,
|
||||
input logic runtime_clut_busy_i
|
||||
);
|
||||
|
||||
localparam int RAM_ADDR_W = $clog2(RAM_SIZE_BYTES);
|
||||
@@ -805,7 +828,12 @@ module top_psmct32_raster_demo_bram
|
||||
fdr_start <= 1'b0;
|
||||
unique case (cst)
|
||||
C_SETUP: if (dma_done_seen && !xfer_busy) begin // bootlet setup + TRX/IMAGE done
|
||||
fdr_start <= 1'b1; grid_ran <= 1'b0; cst <= C_RUN; end
|
||||
if (FEEDER_AUTOSTART) begin
|
||||
fdr_start <= 1'b1; grid_ran <= 1'b0; cst <= C_RUN; // auto boot render
|
||||
end else begin
|
||||
grid_ran <= 1'b0; cst <= C_READY; // Ch353: no boot render — await explicit GO
|
||||
end
|
||||
end
|
||||
C_RUN: begin if (gs_scene_busy) grid_ran <= 1'b1;
|
||||
if (fdr_done) cst <= C_DRAIN; end
|
||||
// Ch337 — gate on gs_scene_busy (NOT gs_raster_active): a >FIFO_DEPTH scene
|
||||
@@ -883,15 +911,39 @@ module top_psmct32_raster_demo_bram
|
||||
logic raster_pixel_emit;
|
||||
logic [63:0] raster_pixel_color_q;
|
||||
logic [31:0] raster_pixel_fb_addr_q;
|
||||
logic [11:0] raster_pixel_x_q, raster_pixel_y_q;
|
||||
logic [31:0] raster_pixel_z_q;
|
||||
logic [3:0] raster_pixel_be_q;
|
||||
logic [31:0] raster_pixel_mask_q;
|
||||
logic [63:0] gs_frame_1_q;
|
||||
logic [5:0] raster_pixel_psm_q;
|
||||
logic raster_pixel_abe_q;
|
||||
logic [16:0] raster_pixel_alpha_q;
|
||||
logic raster_pixel_ztest_q;
|
||||
logic [1:0] raster_pixel_ztst_q;
|
||||
logic raster_pixel_zmsk_q;
|
||||
|
||||
// Ch318 — expose the flush stream for an external LPDDR AXI writer (de25 top).
|
||||
assign flush_emit_o = raster_pixel_emit;
|
||||
assign flush_addr_o = raster_pixel_fb_addr_q;
|
||||
assign flush_pix16_o = raster_pixel_color_q[15:0];
|
||||
assign flush_color32_o = raster_pixel_color_q[31:0]; // Ch323 — full color for spill capture
|
||||
// The production LPDDR ROP supports the byte-granular FBMSK subset used
|
||||
// by the captured SH3 frame. A set mask byte preserves that destination
|
||||
// byte; partial-bit mask bytes are rejected by fixture generation.
|
||||
wire [3:0] frame_byte_be = {gs_frame_1_q[63:56] == 8'h00,
|
||||
gs_frame_1_q[55:48] == 8'h00,
|
||||
gs_frame_1_q[47:40] == 8'h00,
|
||||
gs_frame_1_q[39:32] == 8'h00};
|
||||
assign flush_be_o = raster_pixel_be_q & frame_byte_be;
|
||||
assign flush_x_o = raster_pixel_x_q; // Ch357 — fragment coords + Z for the LPDDR-Z ROP
|
||||
assign flush_y_o = raster_pixel_y_q;
|
||||
assign flush_z_o = raster_pixel_z_q;
|
||||
assign flush_abe_o = raster_pixel_abe_q;
|
||||
assign flush_alpha_o = raster_pixel_alpha_q;
|
||||
assign flush_ztest_o = raster_pixel_ztest_q;
|
||||
assign flush_ztst_o = raster_pixel_ztst_q;
|
||||
assign flush_zmsk_o = raster_pixel_zmsk_q;
|
||||
assign flush_psm_o = raster_pixel_psm_q;
|
||||
|
||||
// Ch295 — texture-sampler read port out of gs_stub. Wired to
|
||||
@@ -921,6 +973,11 @@ module top_psmct32_raster_demo_bram
|
||||
// that consumes it as clut_load_busy to hold the FIFO pop while the
|
||||
// VRAM->CLUT load runs). Driven by clut_loader_stub.load_busy below.
|
||||
logic clut_ld_busy;
|
||||
// Existing unit tops leave the new runtime ports open. Treat only a
|
||||
// driven-one as active so those legacy fixtures stay byte-identical.
|
||||
wire runtime_clut_busy = (runtime_clut_busy_i === 1'b1);
|
||||
wire runtime_clut_wr_en = (runtime_clut_wr_en_i === 1'b1);
|
||||
wire clut_busy = clut_ld_busy | runtime_clut_busy;
|
||||
|
||||
// Ch296 — gs_stub TEX0_1 decode taps that feed clut_loader_stub: the
|
||||
// 1-cycle commit pulse + CBP/CPSM/CSM/CSA/CLD that decide when (and
|
||||
@@ -960,6 +1017,7 @@ module top_psmct32_raster_demo_bram
|
||||
.FB_RD_REGISTERED (1'b1),
|
||||
.Z_RD_REGISTERED (1'b1),
|
||||
.PERSPECTIVE_CORRECT(PERSPECTIVE_CORRECT), // Ch301 — forwarded board param (default 0)
|
||||
.SUBPIXEL_XY (SUBPIXEL_XY), // Ch416 — native GS 12.4 coverage (default 0)
|
||||
.PERSP_RECIP_IDX_BITS(PERSP_RECIP_IDX_BITS), // Ch351 — perspective reciprocal LUT width (far-W -> 11)
|
||||
.GRAD_DIV_CYCLES(GRAD_DIV_CYCLES), // Ch352 — triangle-setup divide settle cycles (board -> 4)
|
||||
.GRAD_SEQ_DIVIDER(GRAD_SEQ_DIVIDER), // Ch352 — sequential gradient divider (board -> 1)
|
||||
@@ -997,7 +1055,7 @@ module top_psmct32_raster_demo_bram
|
||||
.pmode_q(pmode_q), .dispfb1_q(dispfb1_q), .display1_q(display1_q),
|
||||
.prim_q(), .rgbaq_q(),
|
||||
.xyz2_q(), .xyzf2_q(),
|
||||
.frame_1_q(), .zbuf_1_q(),
|
||||
.frame_1_q(gs_frame_1_q), .zbuf_1_q(),
|
||||
.tex0_1_q(), .tex0_1_cbp_q(gs_tex0_cbp), .tex0_1_cpsm_q(gs_tex0_cpsm),
|
||||
.tex0_1_csm_q(gs_tex0_csm), .tex0_1_csa_q(gs_tex0_csa),
|
||||
.tex0_1_cld_q(gs_tex0_cld), .tex0_1_wr_q(gs_tex0_wr),
|
||||
@@ -1018,12 +1076,18 @@ module top_psmct32_raster_demo_bram
|
||||
.pixel_fbp_q(), .pixel_fbw_q(), .pixel_psm_q(), .pixel_fb_addr_q(),
|
||||
.raster_pixel_emit(raster_pixel_emit),
|
||||
.raster_pixel_emit_count(),
|
||||
.raster_pixel_x_q(), .raster_pixel_y_q(),
|
||||
.raster_pixel_x_q(raster_pixel_x_q), .raster_pixel_y_q(raster_pixel_y_q),
|
||||
.raster_pixel_color_q(raster_pixel_color_q),
|
||||
.raster_pixel_fb_addr_q(raster_pixel_fb_addr_q),
|
||||
.raster_pixel_z_q(raster_pixel_z_q),
|
||||
.raster_pixel_be_q(raster_pixel_be_q),
|
||||
.raster_pixel_mask_q(raster_pixel_mask_q),
|
||||
.raster_pixel_psm_q(raster_pixel_psm_q),
|
||||
.raster_pixel_abe_q(raster_pixel_abe_q),
|
||||
.raster_pixel_alpha_q(raster_pixel_alpha_q),
|
||||
.raster_pixel_ztest_q(raster_pixel_ztest_q),
|
||||
.raster_pixel_ztst_q(raster_pixel_ztst_q),
|
||||
.raster_pixel_zmsk_q(raster_pixel_zmsk_q),
|
||||
.z_flush_emit_o(z_flush_emit_o), // Ch323 — tile Z-flush stream (de25 Z-writer)
|
||||
.z_flush_addr_o(z_flush_addr_o),
|
||||
.z_flush_data_o(z_flush_data_o),
|
||||
@@ -1047,7 +1111,7 @@ module top_psmct32_raster_demo_bram
|
||||
.tex_rd_data(gs_tex_rd_data),
|
||||
.clut_rd_idx (gs_clut_rd_idx),
|
||||
.clut_rd_data(gs_clut_rd_data),
|
||||
.clut_load_busy(clut_ld_busy), // hold pop while VRAM->CLUT load runs
|
||||
.clut_load_busy(clut_busy), // hold pop while either CLUT writer runs
|
||||
.fb_rd_en (gs_fb_rd_en),
|
||||
.fb_rd_addr(gs_fb_rd_addr),
|
||||
.fb_rd_data(gs_fb_rd_data),
|
||||
@@ -1422,11 +1486,22 @@ module top_psmct32_raster_demo_bram
|
||||
end
|
||||
end
|
||||
|
||||
wire clut_wr_en = runtime_clut_wr_en ? 1'b1 : clut_ld_wr_en_q;
|
||||
wire [7:0] clut_wr_idx = runtime_clut_wr_en ? runtime_clut_wr_idx_i : clut_ld_wr_idx_q;
|
||||
wire [31:0] clut_wr_data = runtime_clut_wr_en ? runtime_clut_wr_data_i : clut_ld_wr_data_c;
|
||||
|
||||
// synthesis translate_off
|
||||
always_ff @(posedge clk) begin
|
||||
if (rst_n && runtime_clut_wr_en && clut_ld_wr_en_q)
|
||||
$error("runtime CLUT copy collided with TEX0 CLUT loader");
|
||||
end
|
||||
// synthesis translate_on
|
||||
|
||||
clut_stub u_clut (
|
||||
.clk(clk), .rst_n(rst_n),
|
||||
.write_en (clut_ld_wr_en_q),
|
||||
.write_idx(clut_ld_wr_idx_q),
|
||||
.write_data(clut_ld_wr_data_c), // LIVE registered-read data
|
||||
.write_en (clut_wr_en),
|
||||
.write_idx(clut_wr_idx),
|
||||
.write_data(clut_wr_data),
|
||||
// pcrtc scanout read port — unused in this textured-board top
|
||||
// (PCRTC clut_enable=0). Tie its index to 0.
|
||||
.read_idx (8'd0),
|
||||
|
||||
Reference in New Issue
Block a user