Ch443d: registered AXI R buffer (texcache fill) + drop fill_data_q reset
Closes the last currently-visible EMIF-handshake -> FSM setup family the
Ch443c fit exposed (-0.043/-0.022/-0.005 ns), the read-response analogue
of the AW/W buffers.
- gs_axi_r_regbuf: one-entry FULLY-registered AXI R buffer (the R twin of
gs_axi_w_regbuf). Buffers the complete {rdata,rresp,rlast}; u_rready =
!full only (NO combinational dependence on the texture FSM's d_rready);
captures on u_rvalid && u_rready; d_rvalid = full with the payload held
stable until d_rvalid && d_rready; resets only . Inserted between
read-arbiter s2 and gs_texture_cache (u_texf_rbuf). The arbiter is
unchanged -- it completes its R transaction into the buffer, which then
owns delivery to the fill FSM. Cuts EMIF rvalid/rdata -> fst.F_R.
- gs_texture_cache: drop the unobservable fill_data_q reset. F_DRAIN (its
only reader) is reachable only after F_R loads it, so the reset value is
never observed; removing it kills the separate lock_sync|dreg[1] ->
fill_data_q[80] setup path (-0.005 ns).
- New tb_gs_axi_r_regbuf: exactly-once/in-order, randomized responses +
stalls, full backpressure, the full && d_rready no-fall-through case,
{rdata,rresp,rlast} stability, reset-while-empty AND reset-while-full.
All green: r-buffer TB, texture_cache, texture_psmt8_clut, scanout_lb,
scanout_restart, scanout_diag, ps2_hps_bridge, rd_arb, and the complete
f52 replay BYTE-IDENTICAL (Z 0/307200, COLOR 0/245760). No Quartus/board/
push from here.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
// retroDE_ps2 — gs_axi_r_regbuf (Ch443d)
|
||||
//
|
||||
// Fully-registered ONE-ENTRY AXI R-channel (read-response) buffer. The R twin of
|
||||
// gs_axi_w_regbuf / gs_axi_aw_regbuf. Inserted between the read arbiter's s2 R
|
||||
// OUTPUT and the texture-cache fill FSM's R INPUT to cut the combinational path
|
||||
// EMIF gen_p2c_ff[*] (rvalid/rdata) -> gs_texture_cache F_R next-state (`fst`)
|
||||
// + fill_data_q capture — the -0.043 ns / -0.022 ns EMIF setup family.
|
||||
//
|
||||
// CONTRACT (per Codex review, identical shape to gs_axi_w_regbuf):
|
||||
// - FULLY REGISTERED, not a fall-through skid: u_rready depends ONLY on the
|
||||
// registered occupancy `full`, never on the texture FSM's downstream d_rready.
|
||||
// EMIF RVALID therefore can never propagate combinationally into the fill FSM.
|
||||
// (i.e. NOT `u_rready = !full || d_rready`.)
|
||||
// - Buffers the COMPLETE {RDATA, RRESP, RLAST} payload and holds it stable on the
|
||||
// downstream side until the texture FSM accepts it.
|
||||
// - Capture only on u_rvalid && u_rready; exactly-once, in-order (one in flight —
|
||||
// the texture fill issues single-beat reads, ARLEN=0/RLAST=1, but RRESP/RLAST
|
||||
// are preserved regardless).
|
||||
// - Downstream VALID is `full`; payload held stable until d_rvalid && d_rready.
|
||||
// - Reset only `full`; payload registers deliberately unreset (qualified by full).
|
||||
// - The arbiter is unchanged: it completes its R transaction when the response is
|
||||
// accepted into this buffer (s2_rready = u_rready = !full); the buffer then owns
|
||||
// delivery to the texture FSM.
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module gs_axi_r_regbuf #(
|
||||
parameter int RDATA_W = 256,
|
||||
parameter int RRESP_W = 2
|
||||
) (
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
// upstream — from the read arbiter's s2 R output (EMIF read return)
|
||||
input logic [RDATA_W-1:0] u_rdata,
|
||||
input logic [RRESP_W-1:0] u_rresp,
|
||||
input logic u_rlast,
|
||||
input logic u_rvalid,
|
||||
output logic u_rready,
|
||||
// downstream — to the texture-cache fill FSM's R input
|
||||
output logic [RDATA_W-1:0] d_rdata,
|
||||
output logic [RRESP_W-1:0] d_rresp,
|
||||
output logic d_rlast,
|
||||
output logic d_rvalid,
|
||||
input logic d_rready
|
||||
);
|
||||
logic full;
|
||||
logic [RDATA_W-1:0] rdata_q;
|
||||
logic [RRESP_W-1:0] rresp_q;
|
||||
logic rlast_q;
|
||||
|
||||
// Upstream ready = registered occupancy ONLY (no d_rready term) -> EMIF RVALID
|
||||
// never reaches the texture fill FSM combinationally.
|
||||
assign u_rready = !full;
|
||||
// Downstream presents the held response, stable until the texture FSM accepts it.
|
||||
assign d_rvalid = full;
|
||||
assign d_rdata = rdata_q;
|
||||
assign d_rresp = rresp_q;
|
||||
assign d_rlast = rlast_q;
|
||||
|
||||
// One-entry register. Accept an offered upstream response only while empty;
|
||||
// release only when the texture FSM accepts the held response. When full and
|
||||
// accepted in the same cycle, u_rready is still 0 (full is registered), so the
|
||||
// next response waits one cycle -> a swap/drop/dup is impossible. Payload
|
||||
// registers deliberately have no reset (qualified by `full`/d_rvalid).
|
||||
always_ff @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
full <= 1'b0;
|
||||
end else if (!full) begin
|
||||
if (u_rvalid) begin
|
||||
full <= 1'b1;
|
||||
rdata_q <= u_rdata;
|
||||
rresp_q <= u_rresp;
|
||||
rlast_q <= u_rlast;
|
||||
end
|
||||
end else begin
|
||||
if (d_rready) full <= 1'b0;
|
||||
end
|
||||
end
|
||||
endmodule : gs_axi_r_regbuf
|
||||
@@ -126,7 +126,11 @@ module gs_texture_cache #(
|
||||
if (!axi_rst_n) begin
|
||||
fst <= F_IDLE; araddr <= '0; arvalid <= 1'b0; rready <= 1'b0;
|
||||
beat <= '0; fill_done <= 1'b0; fill_beats <= 32'd0; fill_bytes <= 32'd0;
|
||||
rd_errs <= 32'd0; fs_sync <= 3'd0; fill_data_q <= '0;
|
||||
rd_errs <= 32'd0; fs_sync <= 3'd0;
|
||||
// Ch443d (Codex): fill_data_q is deliberately UNRESET. F_DRAIN (its only reader)
|
||||
// is reachable only after F_R has loaded it from the buffered read response, so
|
||||
// its reset value is unobservable. Dropping the reset removes the separate
|
||||
// lock_sync_inst|dreg[1] -> fill_data_q[80] setup path (-0.005 ns).
|
||||
fill_lane <= 3'd0; fill_word_base <= '0; fill_crc <= 32'd0;
|
||||
end else begin
|
||||
fs_sync <= {fs_sync[1:0], fill_start};
|
||||
|
||||
@@ -1991,6 +1991,9 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
wire [29:0] texf_ar_araddr; wire [1:0] texf_ar_arburst; wire [6:0] texf_ar_arid;
|
||||
wire [7:0] texf_ar_arlen; wire [2:0] texf_ar_arsize; wire texf_ar_arvalid, texf_ar_arready;
|
||||
wire [255:0] texf_r_rdata; wire [1:0] texf_r_rresp; wire texf_r_rlast, texf_r_rvalid, texf_r_rready;
|
||||
// Ch443d — read-arbiter s2 R output feeds a one-entry registered R buffer (texf_ri_* =
|
||||
// buffer upstream, from the arbiter); the buffer drives texf_r_* into the texture fill FSM.
|
||||
wire [255:0] texf_ri_rdata; wire [1:0] texf_ri_rresp; wire texf_ri_rlast, texf_ri_rvalid, texf_ri_rready;
|
||||
|
||||
EMIF_Qsys u_emif_lpddr4b (
|
||||
.iopll_refclk_clk (CLOCK2_50),
|
||||
@@ -2719,8 +2722,8 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
.s2_araddr(texf_ar_araddr), .s2_arburst(texf_ar_arburst), .s2_arid(texf_ar_arid),
|
||||
.s2_arlen(texf_ar_arlen), .s2_arsize(texf_ar_arsize), .s2_arvalid(texf_ar_arvalid),
|
||||
.s2_arready(texf_ar_arready),
|
||||
.s2_rdata(texf_r_rdata), .s2_rresp(texf_r_rresp), .s2_rlast(texf_r_rlast),
|
||||
.s2_rvalid(texf_r_rvalid), .s2_rready(texf_r_rready),
|
||||
.s2_rdata(texf_ri_rdata), .s2_rresp(texf_ri_rresp), .s2_rlast(texf_ri_rlast),
|
||||
.s2_rvalid(texf_ri_rvalid), .s2_rready(texf_ri_rready),
|
||||
.s3_araddr(reload_ar_araddr), .s3_arburst(reload_ar_arburst), .s3_arid(reload_ar_arid),
|
||||
.s3_arlen(reload_ar_arlen), .s3_arsize(reload_ar_arsize), .s3_arvalid(reload_ar_arvalid),
|
||||
.s3_arready(reload_ar_arready),
|
||||
@@ -2740,6 +2743,16 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
// (one-shot before raster, armed by the bridge); sample side on design_clk, tapping
|
||||
// u_demo's texel-fetch request and returning the texel at the existing 1-cycle latency.
|
||||
`ifdef GS_LPDDR_TEX
|
||||
// Ch443d — one-entry fully-registered R buffer between read-arbiter s2 and the
|
||||
// texture fill FSM. Cuts the combinational EMIF RVALID/RDATA -> gs_texture_cache
|
||||
// F_R next-state (`fst`) path (the -0.043/-0.022 ns EMIF setup family). The arbiter
|
||||
// completes its R transaction into this buffer (s2_rready = !full); the buffer owns
|
||||
// delivery to the fill FSM. B/AR/W untouched.
|
||||
gs_axi_r_regbuf #(.RDATA_W(256), .RRESP_W(2)) u_texf_rbuf (
|
||||
.clk(emif_clk), .rst_n(emif_reset_n),
|
||||
.u_rdata(texf_ri_rdata), .u_rresp(texf_ri_rresp), .u_rlast(texf_ri_rlast), .u_rvalid(texf_ri_rvalid), .u_rready(texf_ri_rready),
|
||||
.d_rdata(texf_r_rdata), .d_rresp(texf_r_rresp), .d_rlast(texf_r_rlast), .d_rvalid(texf_r_rvalid), .d_rready(texf_r_rready)
|
||||
);
|
||||
gs_texture_cache #(
|
||||
.LPDDR_TEX_BASE(TEX_LPDDR_BASE), .TEX_VRAM_BASE(TEXC_VRAM_BASE), .TEX_BYTES(TEXC_BYTES), .N_BEATS(TEXC_NBEATS)
|
||||
) u_texcache (
|
||||
@@ -2758,7 +2771,7 @@ module de25_nano_psmct32_raster_demo_top (
|
||||
// no texture cache — tie read-port-2 inert (arvalid=0, rready=1 drains).
|
||||
assign texf_ar_araddr=30'd0; assign texf_ar_arburst=2'b01; assign texf_ar_arid=7'd4;
|
||||
assign texf_ar_arlen=8'd0; assign texf_ar_arsize=3'b101; assign texf_ar_arvalid=1'b0;
|
||||
assign texf_r_rready=1'b1;
|
||||
assign texf_ri_rready=1'b1; // Ch443d — drain the arbiter s2 R directly (no R buffer / texcache in this profile)
|
||||
assign tex_fill_done_w=1'b0; assign tex_fill_beats_w=32'd0;
|
||||
assign tex_fill_bytes_w=32'd0; assign tex_rd_errs_w=32'd0; assign tex_fill_crc_w=32'd0;
|
||||
`ifndef GS_TILE_SPILL
|
||||
|
||||
Reference in New Issue
Block a user