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