// retroDE_ps2 — bios_rom_stub
//
// Simulation stub for the 4 MiB BIOS ROM window. Gives Milestone B a
// deterministic instruction source before the rest of the memory system
// exists.
//
// Contract refs:
//   docs/stub_module_plan.md        (Wave 1, item 2)
//   docs/contracts/memory.md        (memory owns BIOS storage/visibility)
//   docs/contracts/iop.md           (IOP owns BIOS behavior — NOT here)
//   docs/decisions/0002-bios-policy.md (real BIOS + narrow stubs; this stub
//                                       is the storage adapter, not firmware
//                                       behavior, and needs no stub-policy
//                                       tracking)
//
// Backing store:
//   - If IMAGE_FILE is a non-empty string, `$readmemh` loads it at
//     elaboration. Caller is responsible for supplying a hex image produced
//     from a user-supplied BIOS dump. No BIOS image is shipped with this
//     repository (see third_party/LICENSING.md).
//   - If IMAGE_FILE is empty (default), a synthetic fixture is generated:
//         mem[word_i] = 32'h00000000 (MIPS NOP: sll $0, $0, 0)
//     Rationale: straight-line valid MIPS so the fixture is a legitimate
//     execution target for any future emulator comparison. This aligns
//     with sim/golden/trace_compare_spec.md ("first comparison target").
//     Earlier versions used 32'hBFC00000 | word_index for trace-distinct
//     inspection, but the spec explicitly rules out fixtures whose words
//     are not a sensible execution target.
//
// Interface:
//   - Byte-addressed within the 4 MiB window. The lower 2 bits of rd_addr
//     are ignored (word-aligned fetch). Upstream address decode is owned
//     by ee_memory_map_stub; this block does not validate the window itself.
//   - One-cycle read latency: rd_en pulses on cycle N, rd_data/rd_valid
//     present on cycle N+1.
//   - Each completed read emits a MEM.READ trace event.
//
// Trace payload schema (per stub plan):
//   MEM READ  arg0=addr  arg1=data  arg2=master  arg3=region
//     master: 0=EE_IFETCH (only source wired in Wave 1)
//     region: 0=BIOS

`timescale 1ns/1ps

module bios_rom_stub
    import trace_pkg::*;
#(
    parameter int    SIZE_BYTES = 4 * 1024 * 1024,
    parameter string IMAGE_FILE = ""
) (
    input  logic                          clk,
    input  logic                          rst_n,

    input  logic                          rd_en,
    input  logic [$clog2(SIZE_BYTES)-1:0] rd_addr,
    output logic [31:0]                   rd_data,
    output logic                          rd_valid,

    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
);

    localparam int WORD_COUNT = SIZE_BYTES / 4;
    localparam int ADDR_WIDTH = $clog2(SIZE_BYTES);
    localparam int WORD_INDEX_WIDTH = ADDR_WIDTH - 2;

    logic [31:0] mem [0:WORD_COUNT-1];

    initial begin
        if (IMAGE_FILE != "") begin
            $display("[bios_rom_stub] loading image: %0s", IMAGE_FILE);
            $readmemh(IMAGE_FILE, mem);
        end else begin
            for (int i = 0; i < WORD_COUNT; i++) begin
                mem[i] = 32'h00000000;      // MIPS NOP
            end
            $display("[bios_rom_stub] synthetic NOP sled loaded (%0d words)", WORD_COUNT);
        end
    end

    logic [WORD_INDEX_WIDTH-1:0] word_index;
    assign word_index = rd_addr[ADDR_WIDTH-1:2];

    always_ff @(posedge clk) begin
        if (!rst_n) begin
            rd_data  <= 32'd0;
            rd_valid <= 1'b0;

            ev_valid  <= 1'b0;
            ev_subsys <= SUBSYS_MEM;
            ev_event  <= EV_READ;
            ev_arg0   <= 64'd0;
            ev_arg1   <= 64'd0;
            ev_arg2   <= 64'd0;
            ev_arg3   <= 64'd0;
            ev_flags  <= 32'd0;
        end else begin
            rd_valid <= rd_en;

            if (rd_en) begin
                rd_data  <= mem[word_index];

                ev_valid  <= 1'b1;
                ev_subsys <= SUBSYS_MEM;
                ev_event  <= EV_READ;
                ev_arg0   <= {{(64-ADDR_WIDTH){1'b0}}, rd_addr};
                ev_arg1   <= {32'd0, mem[word_index]};
                ev_arg2   <= 64'd0;   // master: EE_IFETCH
                ev_arg3   <= 64'd0;   // region: BIOS
                ev_flags  <= 32'd0;
            end else begin
                ev_valid <= 1'b0;
            end
        end
    end

endmodule : bios_rom_stub
