// retroDE_ps2 — tb_gs_texel_addr
//
// Unit test for gs_texel_addr: hand-computed (u,v,tbw,psm) -> byte address
// cases across all four common PS2 pixel formats, including the PSMT4
// nibble-select. Pure combinational DUT; drive inputs, check outputs.

`timescale 1ns/1ps

module tb_gs_texel_addr;

    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;

    logic [31:0] base_byte_addr;
    logic [10:0] u, v;
    logic [13:0] tbw;
    logic [5:0]  psm;
    logic [31:0] texel_byte_addr;
    logic        nibble_hi;

    int errors = 0;

    gs_texel_addr #(.ADDR_W(32)) dut (
        .base_byte_addr (base_byte_addr),
        .u              (u),
        .v              (v),
        .tbw            (tbw),
        .psm            (psm),
        .texel_byte_addr(texel_byte_addr),
        .nibble_hi      (nibble_hi)
    );

    task automatic check(input string name,
                         input logic [31:0] exp_addr,
                         input logic exp_nib);
        #1;
        if (texel_byte_addr !== exp_addr || nibble_hi !== exp_nib) begin
            $display("FAIL %-22s addr=%0d (exp %0d) nib=%0b (exp %0b)",
                     name, texel_byte_addr, exp_addr, nibble_hi, exp_nib);
            errors++;
        end else begin
            $display("ok   %-22s addr=%0d nib=%0b", name, texel_byte_addr, nibble_hi);
        end
    endtask

    initial begin
        // PSMCT32, base 0, tbw=1 (64 texels/row), (u=3,v=2):
        //   offset = 2*64 + 3 = 131 -> *4 = 524
        base_byte_addr = 0; tbw = 1; psm = PSMCT32; u = 3; v = 2;
        check("CT32 b0 (3,2)", 32'd524, 1'b0);

        // PSMCT16, base 0x1000, tbw=2 (128/row), (u=10,v=1):
        //   offset = 128 + 10 = 138 -> *2 = 276 ; +0x1000(4096) = 4372
        base_byte_addr = 32'h1000; tbw = 2; psm = PSMCT16; u = 10; v = 1;
        check("CT16 b0x1000 (10,1)", 32'd4372, 1'b0);

        // PSMT8, base 0, tbw=4 (256/row), (u=5,v=0): offset=5 -> *1 = 5
        base_byte_addr = 0; tbw = 4; psm = PSMT8; u = 5; v = 0;
        check("T8 b0 (5,0)", 32'd5, 1'b0);

        // PSMT4, base 0, tbw=1 (64/row), (u=7,v=0): offset=7 -> >>1 = 3, nib=1
        base_byte_addr = 0; tbw = 1; psm = PSMT4; u = 7; v = 0;
        check("T4 b0 (7,0)", 32'd3, 1'b1);

        // PSMT4, (u=8,v=0): offset=8 -> >>1 = 4, nib=0
        base_byte_addr = 0; tbw = 1; psm = PSMT4; u = 8; v = 0;
        check("T4 b0 (8,0)", 32'd4, 1'b0);

        // CT32 row stride sanity: tbw=2 (128/row), (u=0,v=1): offset=128 -> 512
        base_byte_addr = 0; tbw = 2; psm = PSMCT32; u = 0; v = 1;
        check("CT32 stride (0,1)", 32'd512, 1'b0);

        if (errors == 0)
            $display("\nPASS tb_gs_texel_addr (6/6)");
        else
            $display("\nFAIL tb_gs_texel_addr (%0d errors)", errors);
        $finish;
    end

endmodule
