Files
thejayman77 ec82764bef Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression
(272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps,
and all dump-derived textures/traces) is excluded via .gitignore and stays local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 20:10:50 -04:00

75 lines
3.0 KiB
Systemverilog

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