// retroDE_ps2 — iop_fetch_stub
//
// Minimal IOP-side sequential fetcher. Mirrors ee_fetch_stub in shape and
// discipline — just the smallest honest primitive that produces visible
// IOP-side execution-flow traffic. Not a CPU. Explicitly NOT a BIOS boot
// stub: the default reset vector lives in IOP RAM, not in BIOS space.
//
// Contract refs:
//   docs/contracts/iop.md         (IOP CPU execution, required debug
//                                  visibility: PC stream)
//
// Behavior:
//   - On reset, PC = RESET_VECTOR (default 0x00000000, the low end of
//     IOP RAM).
//   - Each cycle while `enable` is high: issue a 32-bit read at PC,
//     advance PC += 4. No decode, no branches, no exceptions, no FPU.
//   - Responses return 1 cycle later via rd_valid/rd_data from the
//     map. The issued address is latched (pc_d1) so trace lines pair
//     address with data.
//
// Non-goals:
//   - full decode
//   - branch / exception / interrupt handling
//   - real IOP R3000 pipeline timing
//   - BIOS fetch (use a BIOS-pointing RESET_VECTOR param override if
//     needed, but that's intentionally not the default)
//
// Trace payload schema (matches ee_fetch_stub structure under SUBSYS_IOP):
//   IOP RESET  arg0=reset_vector
//   IOP IFETCH arg0=pc arg1=data arg2=resp_kind arg3=-
//     resp_kind: 0=OK (only path in this scope)

`timescale 1ns/1ps

module iop_fetch_stub
    import trace_pkg::*;
#(
    parameter logic [31:0] RESET_VECTOR = 32'h0000_0000
) (
    input  logic          clk,
    input  logic          rst_n,
    input  logic          enable,

    // Map-facing fetch port
    output logic          rd_en,
    output logic [31:0]   rd_addr,
    input  logic [31:0]   rd_data,
    input  logic          rd_valid,

    // Trace
    output logic          ev_valid,
    output subsys_e       ev_subsys,
    output event_e        ev_event,
    output logic [63:0]   ev_arg0,
    output logic [63:0]   ev_arg1,
    output logic [63:0]   ev_arg2,
    output logic [63:0]   ev_arg3,
    output logic [31:0]   ev_flags
);

    // ------------------------------------------------------------------
    // PC and issued-address shadow (same pattern as ee_fetch_stub):
    //   pc     is the address being issued THIS cycle (rd_addr)
    //   pc_d1  is the address whose response arrives THIS cycle on rd_valid
    // pc_d1 only advances alongside pc when enable is high, so it stays
    // aligned with the in-flight request.
    // ------------------------------------------------------------------

    logic [31:0] pc;
    logic [31:0] pc_d1;

    always_ff @(posedge clk) begin
        if (!rst_n) begin
            pc    <= RESET_VECTOR;
            pc_d1 <= RESET_VECTOR;
        end else if (enable) begin
            pc_d1 <= pc;
            pc    <= pc + 32'd4;
        end
    end

    assign rd_en   = enable;
    assign rd_addr = pc;

    // ------------------------------------------------------------------
    // Trace
    //   - Single EV_RESET pulse at reset exit.
    //   - EV_IFETCH one cycle after each rd_valid response.
    // ------------------------------------------------------------------

    logic reset_emit_pending;

    always_ff @(posedge clk) begin
        if (!rst_n) begin
            ev_valid           <= 1'b0;
            ev_subsys          <= SUBSYS_IOP;
            ev_event           <= EV_RESET;
            ev_arg0            <= 64'd0;
            ev_arg1            <= 64'd0;
            ev_arg2            <= 64'd0;
            ev_arg3            <= 64'd0;
            ev_flags           <= 32'd0;
            reset_emit_pending <= 1'b1;
        end else if (reset_emit_pending) begin
            ev_valid           <= 1'b1;
            ev_subsys          <= SUBSYS_IOP;
            ev_event           <= EV_RESET;
            ev_arg0            <= {32'd0, RESET_VECTOR};
            ev_arg1            <= 64'd0;
            ev_arg2            <= 64'd0;
            ev_arg3            <= 64'd0;
            ev_flags           <= 32'd0;
            reset_emit_pending <= 1'b0;
        end else if (rd_valid) begin
            ev_valid  <= 1'b1;
            ev_subsys <= SUBSYS_IOP;
            ev_event  <= EV_IFETCH;
            ev_arg0   <= {32'd0, pc_d1};
            ev_arg1   <= {32'd0, rd_data};
            ev_arg2   <= 64'd0;
            ev_arg3   <= 64'd0;
            ev_flags  <= 32'd0;
        end else begin
            ev_valid <= 1'b0;
        end
    end

endmodule : iop_fetch_stub
