// 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