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