// retroDE_ps2 — trace package
//
// Defines the shared trace vocabulary used by Wave 1 stubs. Kept small on
// purpose: subsystem IDs, event codes, and string renderers only. See
// docs/decisions/0000-trace-format.md and docs/stub_module_plan.md.
//
// Contract:
//   trace line = cycle subsystem event arg0 arg1 arg2 arg3 flags
//
// Event codes are globally unique (not per-subsystem) in Wave 1 to keep the
// renderer trivial. Revisit if the namespace gets crowded.

`ifndef RETRODE_PS2_TRACE_PKG_SV
`define RETRODE_PS2_TRACE_PKG_SV

`timescale 1ns/1ps

package trace_pkg;

    typedef enum logic [3:0] {
        SUBSYS_EE    = 4'h0,
        SUBSYS_MEM   = 4'h1,
        SUBSYS_GS    = 4'h2,
        SUBSYS_INTC  = 4'h3,
        SUBSYS_SIF   = 4'h4,
        SUBSYS_DMAC  = 4'h5,
        SUBSYS_IOP   = 4'h6,
        SUBSYS_GIF   = 4'h7,
        SUBSYS_PLAT  = 4'h8,
        SUBSYS_OTHER = 4'hF
    } subsys_e;

    typedef enum logic [7:0] {
        EV_RESET     = 8'h00,
        EV_IFETCH    = 8'h01,
        EV_READ      = 8'h02,
        EV_WRITE     = 8'h03,
        EV_UNMAPPED  = 8'h04,
        EV_IRQ       = 8'h05,
        EV_MODE      = 8'h06,
        EV_BGCOLOR   = 8'h07,
        // Wave 2 additions — DMAC / GIF / GS write-path visibility
        // (see docs/wave2_dma_gif_plan.md).
        EV_DMA_CFG   = 8'h08,
        EV_DMA_START = 8'h09,
        EV_DMA_BEAT  = 8'h0A,
        EV_DMA_DONE  = 8'h0B,
        EV_GIFTAG    = 8'h0C,
        EV_GS_WRITE  = 8'h0D,
        // Ch76 — GS primitive-observer "primitive complete" pulse.
        // Fired by gs_stub when an XYZ2/XYZF2 vertex commit closes a
        // discrete primitive (POINT / LINE / TRI / SPRITE) per the
        // currently-latched PRIM[2:0]. arg0=prim_type, arg1=vert
        // threshold, arg2=cumulative prim count after this draw,
        // arg3=closing vertex data. No rasterization yet.
        EV_PRIM_DRAW = 8'h0E,
        EV_OTHER     = 8'hFF
    } event_e;

    // ------------------------------------------------------------------
    // Ch81 — structured GIF/GS field decoders
    //
    // The raw 64-bit XYZ2 / XYZF2 / RGBAQ payloads are an awkward
    // contract for the next layer of the pipeline (rasterizer or
    // pixel emit). These struct types carry the same data already
    // unpacked into channel components so a consumer doesn't have
    // to re-derive the bit slices.
    //
    // XYZ2  (PCSX2 GSRegs.h: bits[15:0]=X, [31:16]=Y, [63:32]=Z 32-bit)
    // XYZF2 (PCSX2 GSRegs.h: bits[15:0]=X, [31:16]=Y, [55:32]=Z 24-bit,
    //                       [63:56]=F fog byte)
    // RGBAQ (bits[7:0]=R, [15:8]=G, [23:16]=B, [31:24]=A, [63:32]=Q float)
    //
    // X and Y are PS2 12.4 fixed-point screen coordinates (top 12
    // bits = integer pixel, low 4 bits = sub-pixel). Z is treated
    // as opaque in this package — depth interpretation depends on
    // the GS framebuffer/zbuffer config, which the recognition
    // layer doesn't model. Q is the texture-coordinate divisor
    // (IEEE single-precision float); we carry it verbatim.
    //
    // is_xyzf2 records the source format so a consumer can
    // disambiguate the 24-bit-Z + 8-bit-fog packing from the full
    // 32-bit-Z packing without re-reading the original reg#.
    // ------------------------------------------------------------------

    typedef struct packed {
        logic        is_xyzf2;                                               // 1 = XYZF2 source, 0 = XYZ2
        logic [7:0]  fog;                                                    // valid iff is_xyzf2; else 0
        logic [31:0] z;                                                      // 32-bit (XYZ2) or zero-extended 24-bit (XYZF2)
        logic [15:0] y;                                                      // 12.4 fixed-point screen Y
        logic [15:0] x;                                                      // 12.4 fixed-point screen X
    } vertex_t;

    typedef struct packed {
        logic [31:0] q;                                                      // texture-coord divisor (IEEE float)
        logic [7:0]  a;
        logic [7:0]  b;
        logic [7:0]  g;
        logic [7:0]  r;
    } color_t;

    function automatic vertex_t decode_vertex(input logic [63:0] data,
                                              input logic        is_xyzf2);
        vertex_t v;
        v.x        = data[15:0];
        v.y        = data[31:16];
        v.is_xyzf2 = is_xyzf2;
        if (is_xyzf2) begin
            v.z   = {8'd0, data[55:32]};                                     // zero-extend 24 bits
            v.fog = data[63:56];
        end else begin
            v.z   = data[63:32];
            v.fog = 8'd0;
        end
        return v;
    endfunction

    function automatic color_t decode_color(input logic [63:0] data);
        color_t c;
        c.r = data[7:0];
        c.g = data[15:8];
        c.b = data[23:16];
        c.a = data[31:24];
        c.q = data[63:32];
        return c;
    endfunction

    function automatic string subsys_str(input subsys_e s);
        case (s)
            SUBSYS_EE:   return "EE";
            SUBSYS_MEM:  return "MEM";
            SUBSYS_GS:   return "GS";
            SUBSYS_INTC: return "INTC";
            SUBSYS_SIF:  return "SIF";
            SUBSYS_DMAC: return "DMAC";
            SUBSYS_IOP:  return "IOP";
            SUBSYS_GIF:  return "GIF";
            SUBSYS_PLAT: return "PLAT";
            default:     return "OTHER";
        endcase
    endfunction

    function automatic string event_str(input event_e e);
        case (e)
            EV_RESET:     return "RESET";
            EV_IFETCH:    return "IFETCH";
            EV_READ:      return "READ";
            EV_WRITE:     return "WRITE";
            EV_UNMAPPED:  return "UNMAPPED";
            EV_IRQ:       return "IRQ";
            EV_MODE:      return "MODE";
            EV_BGCOLOR:   return "BGCOLOR";
            EV_DMA_CFG:   return "DMA_CFG";
            EV_DMA_START: return "DMA_START";
            EV_DMA_BEAT:  return "DMA_BEAT";
            EV_DMA_DONE:  return "DMA_DONE";
            EV_GIFTAG:    return "GIFTAG";
            EV_GS_WRITE:  return "GS_WRITE";
            EV_PRIM_DRAW: return "PRIM_DRAW";
            default:      return "OTHER";
        endcase
    endfunction

endpackage : trace_pkg

`endif // RETRODE_PS2_TRACE_PKG_SV
