// retroDE_ps2 — gs_texel_addr // // Texture-sampling address generator (brick 1, step 1 of GS texturing). // // Given a texture coordinate (u,v) and the TEX0 texture descriptor, computes // the LINEAR VRAM byte address of that texel — the read-side mirror of the // rasterizer's existing framebuffer-address math (gs_stub.sv ~line 530: // fb_addr = base + (Y*FBW*64 + X) * bytes_per_pixel ). // // Linear (non-swizzled) only, on purpose: the swizzle paths in gs_stub are // param-gated OFF by default, so linear is the baseline. Swizzled texel // addressing will reuse the existing gs_swizzle_* modules later. // // `base_byte_addr` is the texture base in VRAM, ALREADY scaled to bytes by // the caller from TEX0.TBP0. Keeping the base as a byte input (rather than // scaling TBP0 here) isolates the one thing that must be reconciled with the // texture-UPLOAD path (gif_image_xfer_stub / BITBLTBUF) — so we read texels // from exactly where BITBLT wrote them. That reconciliation is tracked as the // next integration step; this module's (u,v)->offset math is unambiguous and // unit-tested below. `timescale 1ns/1ps module gs_texel_addr #( parameter int ADDR_W = 32 ) ( input logic [31:0] base_byte_addr, // texture base in VRAM (bytes) input logic [10:0] u, // texel column (0..2047) input logic [10:0] v, // texel row (0..2047) input logic [13:0] tbw, // TEX0.TBW — texels-per-row / 64 input logic [5:0] psm, // pixel storage mode output logic [ADDR_W-1:0] texel_byte_addr, output logic nibble_hi // PSMT4: high nibble of the byte? ); localparam logic [5:0] PSMCT32 = 6'h00; localparam logic [5:0] PSMCT16 = 6'h02; localparam logic [5:0] PSMT8 = 6'h13; localparam logic [5:0] PSMT4 = 6'h14; // texels per row = TBW * 64 logic [19:0] row_texels; // linear texel index = v * row_texels + u logic [31:0] texel_offset; always_comb begin row_texels = {tbw, 6'b000000}; // tbw * 64 texel_offset = (v * row_texels) + {21'd0, u}; unique case (psm) PSMCT32: begin texel_byte_addr = base_byte_addr + (texel_offset << 2); // 4 B/texel nibble_hi = 1'b0; end PSMCT16: begin texel_byte_addr = base_byte_addr + (texel_offset << 1); // 2 B/texel nibble_hi = 1'b0; end PSMT8: begin texel_byte_addr = base_byte_addr + texel_offset; // 1 B/texel nibble_hi = 1'b0; end PSMT4: begin texel_byte_addr = base_byte_addr + (texel_offset >> 1); // 4 b/texel nibble_hi = texel_offset[0]; end default: begin texel_byte_addr = base_byte_addr + (texel_offset << 2); nibble_hi = 1'b0; end endcase end endmodule : gs_texel_addr