// retroDE_ps2 — clut_stub (Ch97) // // Minimal palette RAM for indexed-color scanout. PSMT8 scanout // (Ch96) currently surfaces the index as grayscale; with this // CLUT wired in, the index is looked up to produce real RGB. // // Scope (intentionally minimal for Ch97): // - 256 entries × 32 bits (PSMCT32 ABGR per entry). PSMT4 // (16 entries) uses the same RAM with a smaller index range. // - CSM2 (linear) addressing only. Index N reads entry N. CSA // (entry offset) is honored OUTSIDE this module — pcrtc // computes effective_idx = idx + (CSA << 4) and presents it // as `read_idx`. CSM1 (16×16 grid swizzle inside a CSPM // block) is deferred. // - Combinational read port for pcrtc (tight scanout latency). // - Single registered write port. Two writers exist at this // scope, picked by the wiring at the TB level: // (a) TB-direct programming for tests that want to lock // pcrtc-side decode in isolation (Ch97 PSMT8+CLUT TB, // Ch98 TEX0_1 CSA-flow TB). // (b) `clut_loader_stub` (Ch99/Ch100) — a small FSM that // copies 256 entries from VRAM[CBP*256] into this RAM // when a TEX0_1 GIF write commits with CLD!=0, // CSM=CSM2, and CPSM ∈ {PSMCT32, PSMCT16}. PSMCT16 // entries are unpacked from RGB5A1 to PSMCT32 ABGR // inside the loader, so clut_stub always stores // PSMCT32 regardless of source. clut_stub doesn't know // which writer is in play; it just commits whatever // the wired write_* port carries. // // Real PS2 CLUT is held in a 1 KiB internal staging area and // loaded from VRAM[CBP] when CLD bits in TEX0 fire. Ch99/Ch100 // model the load path for CPSM ∈ {PSMCT32, PSMCT16} with CSM2; // CSM1 swizzle, conditional CLD modes (2..7), CSA partial-window // loads (CLD=4), and CPSM ∉ {PSMCT32, PSMCT16} stay deferred. `timescale 1ns/1ps module clut_stub #( parameter int unsigned ENTRIES = 256 ) ( input logic clk, input logic rst_n, // TB-direct write port (no GIF TEX0 path yet). input logic write_en, input logic [7:0] write_idx, input logic [31:0] write_data, // Combinational read port consumed by gs_pcrtc_stub (scanout). input logic [7:0] read_idx, output logic [31:0] read_data, // Ch296 — SECOND combinational read port for the TEXTURE sampler // (gs_stub texel-fetch path). Independent of the pcrtc scanout port // above: the table is a tiny 256x32 LUT, so a second read fan-out is // free and keeps the two consumers (scanout vs sampler) decoupled. // PSMT8 indexed texturing looks up clut_stub[tex_read_idx] to turn a // fetched 8-bit index into a PSMCT32 color. input logic [7:0] tex_read_idx, output logic [31:0] tex_read_data ); logic [31:0] mem [0:ENTRIES-1]; initial begin for (int i = 0; i < ENTRIES; i++) mem[i] = 32'd0; end assign read_data = mem[read_idx]; assign tex_read_data = mem[tex_read_idx]; always_ff @(posedge clk) begin if (rst_n && write_en) begin mem[write_idx] <= write_data; end end endmodule : clut_stub