// retroDE_ps2 — iop_memory_map_stub // // IOP-side memory map. Gives IOP-visible addresses architectural meaning. // Wave 3 first-pass scope is deliberately narrow: only the IOP-RAM window // is routed; every other address decodes as UNMAPPED with deterministic // fault data. SIF registers, IOP I/O, SPU2, CDVD, and IOP-side BIOS are // all intentionally deferred — slots noted in comments so the map can // grow without re-shaping its interface. // // Contract refs: // docs/contracts/iop.md (IOP-local address decode) // docs/contracts/memory.md (IOP RAM lives at phys 0x00000000- // 0x001FFFFF, 2 MiB) // // Address semantics: // IOP CPU side is MIPS R3000-class. kseg0/kseg1 aliases // (0x80000000/0xA0000000 mirrors of 0x00000000) are modelled via // `phys = iop_addr[28:0]`, consistent with how ee_memory_map_stub // strips kseg for EE fetches. Physical window decode then works on // the low 29 bits. // // Bridge-side write port (Wave 3 addition): the SIF-to-IOP-RAM bridge // writes directly at physical offsets — no kseg strip. The map decodes // its address bits directly against the same region rules. // // DMA read-master port (Wave 3 reverse-direction addition): the IOP // DMAC (ch9 SIF0 egress, and any other future channel) fetches source // bytes through this port. Physical addressing; RAM-only decode in // current scope. Caller provides its own master_id (convention: 4 = // IOP_DMAC). // // Arbitration (Wave 3 scope): // Two potential write masters on the RAM path: the IOP CPU port and // the bridge port. Two potential read masters on the RAM path: the // IOP CPU port and the DMA read master. Collisions within the same // cycle are not expected in the current TBs (CPU programming / readback // phases are separate from DMA transfer phases). Policy if they ever // collide: CPU wins. Documented here rather than hidden in priority // ordering; RAM port is mux'd accordingly. // // Region decode (current): // - IOP RAM window: phys[28:21] == 8'b00000000 // (0x0000_0000 - 0x001F_FFFF, 2 MiB) // → route to iop_ram_stub (offset phys[20:0]) // - SIF registers (IOP side): phys[28:24] == 5'b11101 // (0x1D00_0000 block) → route to the SIF // register shell with offset phys[7:0]. The // mailbox stub's register surface covers // offsets 0x00/0x10/0x20/0x30. // - IOP DMAC channel 9: phys[28:4] == 25'h01F8_0152 // (0x1F80_1520 - 0x1F80_152F, 16 bytes) // → route to iop_dmac_reg_stub with 4-bit // offset phys[3:0]. Channel 9 is SIF0 // (IOP→EE) in the real PS2 DMAC map; other // channels are intentionally not decoded. // - IOP INTC: phys[28:4] == 25'h01F8_0107 // (0x1F80_1070 - 0x1F80_107F, 16 bytes) // → route to intc_stub with 8-bit offset // phys[7:0]. Matches the real PS2 IOP INTC // placement (I_STAT / I_MASK). // - Shared BIOS ROM: phys[28:22] == 7'b1111111 // (0x1FC0_0000 - 0x1FFF_FFFF, 4 MiB) // → route to bios_rom_stub with 22-bit // offset phys[21:0]. kseg1 aliasing maps // 0xBFC0_0000 fetches to this window via // the standard [28:0] strip. The IOP core // reset vector normally points here. // Writes to BIOS decode as UNMAPPED // (read-only ROM). // - everything else: UNMAPPED, reads return 32'hDEADBEEF // // Future regions (reserved in comments, not wired): // - Other IOP DMAC channels: 0x1F80_1080-0x1F80_156F (partial block) // - IOP timers / SIO: elsewhere in 0x1F80_0000 block // - SPU2: 0x1F90_0000 block // // Trace semantics (matches ee_memory_map_stub's request-routing pattern): // Map-layer events describe routing (what was asked for, where it was // sent). Arg1 is 0 when the request is routed to a backing store that // will emit its own delivery event; 0xDEADBEEF on unmapped reads; the // actual write data on unmapped writes (so the TB can see what software // tried to write). // // Latency assumption (mirrors ee_memory_map_stub note): // Assumes fixed one-cycle backing-store latency. `ram_rd_valid` is not // consulted — the map asserts its own `iop_rd_valid` one cycle after // request unconditionally. All Wave 3 backing stubs honour that. If a // later backing store introduces wait states, the map must grow proper // response handshaking. // // Trace payload schema: // IOP READ arg0=addr arg1=0 arg2=master_id arg3=region_id // IOP WRITE arg0=addr arg1=wr_data arg2=master_id arg3=region_id // IOP UNMAPPED arg0=addr arg1=0xDEADBEEF arg2=master_id arg3=0xFF // region_id: 2 = IOP_RAM, 3 = SIF_REGS, 4 = IOP_DMAC, 5 = IOP_INTC, // 6 = IOP_BIOS // master_id: 2 = IOP_CPU, 3 = SIF bridge (writes), 4 = IOP_DMAC (reads) // flags bit 0: 1 = write, 0 = read `timescale 1ns/1ps module iop_memory_map_stub import trace_pkg::*; ( input logic clk, input logic rst_n, // ------------------------------------------------------------------ // IOP CPU-side request interface (32-bit data, virtual address) // ------------------------------------------------------------------ input logic iop_rd_en, input logic [31:0] iop_rd_addr, output logic [31:0] iop_rd_data, output logic iop_rd_valid, input logic iop_wr_en, input logic [31:0] iop_wr_addr, input logic [31:0] iop_wr_data, input logic [3:0] iop_wr_be, // Caller-provided master id for trace attribution. Conventional: // 0 = TB direct, 2 = IOP CPU (once a fetch stub exists). input logic [7:0] master_id, // ------------------------------------------------------------------ // Bridge-side write port (Wave 3). Physical addresses; no kseg strip. // Used by sif_dma_iop_ram_bridge_stub and similar DMA-side masters. // Caller provides its own master_id (convention: 3 = SIF bridge). // ------------------------------------------------------------------ input logic bridge_wr_en, input logic [31:0] bridge_wr_addr, input logic [31:0] bridge_wr_data, input logic [3:0] bridge_wr_be, input logic [7:0] bridge_master_id, // ------------------------------------------------------------------ // DMA read-master port (Wave 3). Physical addressing; intended for // IOP DMAC ch9 reads out of IOP RAM. One-cycle read latency, same // pipeline shape as the CPU read. Caller provides its own master_id // (convention: 4 = IOP_DMAC). // ------------------------------------------------------------------ input logic dma_rd_en, input logic [31:0] dma_rd_addr, input logic [7:0] dma_master_id, output logic [31:0] dma_rd_data, output logic dma_rd_valid, // ------------------------------------------------------------------ // Downstream to iop_ram_stub. // Address presented as a 21-bit offset within the 2 MiB IOP RAM // window; consumers may truncate to match their backing-store width. // ------------------------------------------------------------------ output logic ram_rd_en, output logic [20:0] ram_rd_addr, input logic [31:0] ram_rd_data, input logic ram_rd_valid, output logic ram_wr_en, output logic [20:0] ram_wr_addr, output logic [31:0] ram_wr_data, output logic [3:0] ram_wr_be, output logic [7:0] ram_master_id, // ------------------------------------------------------------------ // Downstream to the SIF register shell (sif_mailbox_stub IOP-side // port). Low byte of the physical address is presented; writes go // out with the CPU's data/be; reads come back with 1-cycle latency // consistent with the rest of the stub ecosystem. // ------------------------------------------------------------------ output logic sif_rd_en, output logic [7:0] sif_rd_addr, input logic [31:0] sif_rd_data, input logic sif_rd_valid, output logic sif_wr_en, output logic [7:0] sif_wr_addr, output logic [31:0] sif_wr_data, // ------------------------------------------------------------------ // Downstream to the IOP DMAC register shell (channel 9). 4-bit // offset; data path uses the CPU write data. Read returns with // one-cycle latency like the rest of the stub ecosystem. // ------------------------------------------------------------------ output logic iop_dmac_rd_en, output logic [3:0] iop_dmac_rd_addr, input logic [31:0] iop_dmac_rd_data, input logic iop_dmac_rd_valid, output logic iop_dmac_wr_en, output logic [3:0] iop_dmac_wr_addr, output logic [31:0] iop_dmac_wr_data, // ------------------------------------------------------------------ // Downstream to the IOP INTC register shell (intc_stub reused). // 8-bit offset passed downstream; read returns with one-cycle // latency consistent with the rest of the stub ecosystem. // ------------------------------------------------------------------ output logic iop_intc_rd_en, output logic [7:0] iop_intc_rd_addr, input logic [31:0] iop_intc_rd_data, input logic iop_intc_rd_valid, output logic iop_intc_wr_en, output logic [7:0] iop_intc_wr_addr, output logic [31:0] iop_intc_wr_data, // ------------------------------------------------------------------ // Downstream to bios_rom_stub (shared BIOS window). // 22-bit byte offset within the 4 MiB window. Writes are never // forwarded (BIOS is ROM); the map routes any bios-window write // attempt to the UNMAPPED trace event instead. // ------------------------------------------------------------------ output logic bios_rd_en, output logic [21:0] bios_rd_addr, input logic [31:0] bios_rd_data, input logic bios_rd_valid, // ------------------------------------------------------------------ // Ch234 — bridge-clock-domain pad bitmaps from ps2_hps_bridge // (INPUT_P1/P2 latches @ 0x040/0x044). Sync'd into the IOP clock // by the internal `sio2_input_stub` instance below. TBs that // don't exercise the pad path can tie both ports to `32'd0`. // ------------------------------------------------------------------ input logic [31:0] input_p1, input logic [31:0] input_p2, // ------------------------------------------------------------------ // 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 ); localparam logic [63:0] REGION_IOP_RAM = 64'd2; localparam logic [63:0] REGION_SIF_REGS = 64'd3; localparam logic [63:0] REGION_IOP_DMAC = 64'd4; localparam logic [63:0] REGION_IOP_INTC = 64'd5; localparam logic [63:0] REGION_IOP_BIOS = 64'd6; localparam logic [63:0] REGION_PAD_IO = 64'd7; // Ch234 localparam logic [63:0] REGION_UNMAPPED = 64'hFF; localparam logic [28:0] DMAC_CH9_BASE = 29'h1F80_1520; localparam logic [28:0] IOP_INTC_BASE = 29'h1F80_1070; // Ch234 — retroDE-local pad I/O window (256 bytes), deliberately // OUTSIDE the real SIO2 range (0x1F80_8200..0x1F80_82FF) so a // faithful SIO2 emulation chapter can land later without collision. localparam logic [28:0] PAD_IO_BASE = 29'h1F80_8500; // ------------------------------------------------------------------ // Region decode (combinational, shared for read + write) // ------------------------------------------------------------------ // CPU-side decode (virtual → physical via kseg strip) logic [28:0] rd_phys_addr; logic [28:0] wr_phys_addr; logic rd_is_ram; logic rd_is_sif; logic rd_is_dmac; logic rd_is_intc; logic rd_is_bios; logic rd_is_pad; // Ch234 logic cpu_wr_is_ram; logic cpu_wr_is_sif; logic cpu_wr_is_dmac; logic cpu_wr_is_intc; logic cpu_wr_is_bios; logic cpu_wr_is_pad; // Ch234 logic [20:0] rd_ram_offset; logic [20:0] cpu_wr_ram_offset; assign rd_phys_addr = iop_rd_addr[28:0]; assign wr_phys_addr = iop_wr_addr[28:0]; assign rd_is_ram = (rd_phys_addr[28:21] == 8'd0); assign rd_is_sif = (rd_phys_addr[28:24] == 5'b11101); assign rd_is_dmac = (rd_phys_addr[28:4] == DMAC_CH9_BASE[28:4]); assign rd_is_intc = (rd_phys_addr[28:4] == IOP_INTC_BASE[28:4]); assign rd_is_bios = (rd_phys_addr[28:22] == 7'b1111111); // Ch234 — pad I/O region is 256 bytes at PAD_IO_BASE, so the // decode is bits [28:8] (= 21 high bits of the 29-bit phys addr). assign rd_is_pad = (rd_phys_addr[28:8] == PAD_IO_BASE[28:8]); assign cpu_wr_is_ram = (wr_phys_addr[28:21] == 8'd0); assign cpu_wr_is_sif = (wr_phys_addr[28:24] == 5'b11101); assign cpu_wr_is_dmac = (wr_phys_addr[28:4] == DMAC_CH9_BASE[28:4]); assign cpu_wr_is_intc = (wr_phys_addr[28:4] == IOP_INTC_BASE[28:4]); assign cpu_wr_is_bios = (wr_phys_addr[28:22] == 7'b1111111); assign cpu_wr_is_pad = (wr_phys_addr[28:8] == PAD_IO_BASE[28:8]); assign rd_ram_offset = rd_phys_addr[20:0]; assign cpu_wr_ram_offset = wr_phys_addr[20:0]; // Bridge-side decode (physical, no strip). Bridge writes are routed // to IOP RAM only — no SIF destination from the bridge side yet. logic bridge_wr_is_ram; logic [20:0] bridge_wr_ram_offset; assign bridge_wr_is_ram = (bridge_wr_addr[28:21] == 8'd0); assign bridge_wr_ram_offset = bridge_wr_addr[20:0]; // DMA-side read decode (physical, no strip). Scope covers RAM only. logic dma_rd_is_ram; logic [20:0] dma_rd_ram_offset; assign dma_rd_is_ram = (dma_rd_addr[28:21] == 8'd0); assign dma_rd_ram_offset = dma_rd_addr[20:0]; // RAM routing. Ch261 — DMA wins the port on CPU+DMA collision; the // CPU's read address is latched into a one-entry pending slot and // serviced on the next RAM cycle that the DMA does not consume. // Pre-Ch261 the comment above this block was "CPU read wins over // DMA read on same-cycle collision" but the silent consequence was // the DMA path sampling `ram_rd_data` from the CPU's address — // silent DMA data corruption. The Ch261 SIF-landing TB found it. // // Single-entry slot is sufficient because every existing CPU // client of this map is request-then-wait-for-valid (no second // outstanding read in flight): exec stub, iop_core_stub, fetch // stub all stall in their own wait state until `iop_rd_valid` // asserts. A sim-only overflow assertion below catches any future // client that breaks that assumption. logic cpu_rd_hit; logic dma_rd_hit; logic cpu_dma_collision; assign cpu_rd_hit = iop_rd_en && rd_is_ram; assign dma_rd_hit = dma_rd_en && dma_rd_is_ram; assign cpu_dma_collision = cpu_rd_hit && dma_rd_hit; // One-entry deferred CPU-RAM-read slot. logic cpu_pend_valid; logic [20:0] cpu_pend_addr; // Service priority (mutually exclusive): // serve_dma — DMA wins the bus any cycle it asks // serve_cpu_def — deferred CPU read services on the next non-DMA cycle // serve_cpu_now — live CPU read services when neither of the above fires logic serve_dma; logic serve_cpu_def; logic serve_cpu_now; assign serve_dma = dma_rd_hit; assign serve_cpu_def = !dma_rd_hit && cpu_pend_valid; assign serve_cpu_now = !dma_rd_hit && !cpu_pend_valid && cpu_rd_hit; assign ram_rd_en = serve_dma || serve_cpu_def || serve_cpu_now; assign ram_rd_addr = serve_dma ? dma_rd_ram_offset : serve_cpu_def ? cpu_pend_addr : rd_ram_offset; // Slot update: latch on collision, clear on service. always_ff @(posedge clk) begin if (!rst_n) begin cpu_pend_valid <= 1'b0; cpu_pend_addr <= 21'd0; end else begin if (cpu_dma_collision && !cpu_pend_valid) begin cpu_pend_valid <= 1'b1; cpu_pend_addr <= rd_ram_offset; end else if (serve_cpu_def) begin cpu_pend_valid <= 1'b0; end end end `ifndef SYNTHESIS // Overflow detector: a second CPU+DMA collision while the slot is // already pending means we'd drop the new CPU read silently. The // current set of CPU clients can't trigger this (single outstanding // read each), but future producers should fail loudly here. always_ff @(posedge clk) begin if (rst_n && cpu_dma_collision && cpu_pend_valid) begin $error("[iop_memory_map_stub] Ch261 deferred-CPU-slot overflow: cpu_dma_collision while cpu_pend_valid (live addr=0x%05h pending addr=0x%05h)", rd_ram_offset, cpu_pend_addr); end end `endif // SIF register-shell routing. Low byte of the physical address is // presented downstream (mailbox uses 8-bit offsets). assign sif_rd_en = iop_rd_en && rd_is_sif; assign sif_rd_addr = rd_phys_addr[7:0]; assign sif_wr_en = iop_wr_en && cpu_wr_is_sif; assign sif_wr_addr = wr_phys_addr[7:0]; assign sif_wr_data = iop_wr_data; // IOP DMAC ch9 routing. Low 4 bits of the physical address select // among MADR / BCR / CHCR (and any other in-block offsets). assign iop_dmac_rd_en = iop_rd_en && rd_is_dmac; assign iop_dmac_rd_addr = rd_phys_addr[3:0]; assign iop_dmac_wr_en = iop_wr_en && cpu_wr_is_dmac; assign iop_dmac_wr_addr = wr_phys_addr[3:0]; assign iop_dmac_wr_data = iop_wr_data; // IOP INTC routing. Low byte of the physical address selects // INTC_STAT (0x00) or INTC_MASK (0x10). assign iop_intc_rd_en = iop_rd_en && rd_is_intc; assign iop_intc_rd_addr = rd_phys_addr[7:0]; assign iop_intc_wr_en = iop_wr_en && cpu_wr_is_intc; assign iop_intc_wr_addr = wr_phys_addr[7:0]; assign iop_intc_wr_data = iop_wr_data; // Ch234 — pad-I/O region wiring. The map owns a single internal // `sio2_input_stub` instance; the bridge's INPUT_P1/P2 latches // flow into it directly. `pad_rd_*` / `pad_wr_*` are the // map↔stub handshake (4-bit word offset within the 256-byte // region, captured from phys_addr[5:2]). wire pad_rd_en; wire [3:0] pad_rd_addr; wire [31:0] pad_rd_data; wire pad_rd_valid; wire pad_wr_en; wire [3:0] pad_wr_addr; wire [31:0] pad_wr_data; assign pad_rd_en = iop_rd_en && rd_is_pad; assign pad_rd_addr = rd_phys_addr[5:2]; assign pad_wr_en = iop_wr_en && cpu_wr_is_pad; assign pad_wr_addr = wr_phys_addr[5:2]; assign pad_wr_data = iop_wr_data; sio2_input_stub u_sio2_input ( .clk (clk), .rst_n (rst_n), .input_p1 (input_p1), .input_p2 (input_p2), .rd_en (pad_rd_en), .rd_addr (pad_rd_addr), .rd_data (pad_rd_data), .rd_valid (pad_rd_valid), .wr_en (pad_wr_en), .wr_addr (pad_wr_addr), .wr_data (pad_wr_data) ); // BIOS ROM routing. 22-bit byte offset within the 4 MiB window. // No write path — BIOS is read-only. assign bios_rd_en = iop_rd_en && rd_is_bios; assign bios_rd_addr = rd_phys_addr[21:0]; // Write-path arbitration for the RAM side: CPU wins on same-cycle // collision. Neither TB nor current design exercises collision; // priority is defensive. SIF writes are a separate port and don't // contend with RAM writes. logic cpu_wr_hit; logic bridge_wr_hit; assign cpu_wr_hit = iop_wr_en && cpu_wr_is_ram; assign bridge_wr_hit = bridge_wr_en && bridge_wr_is_ram; assign ram_wr_en = cpu_wr_hit || bridge_wr_hit; assign ram_wr_addr = cpu_wr_hit ? cpu_wr_ram_offset : bridge_wr_ram_offset; assign ram_wr_data = cpu_wr_hit ? iop_wr_data : bridge_wr_data; assign ram_wr_be = cpu_wr_hit ? iop_wr_be : bridge_wr_be; assign ram_master_id = cpu_wr_hit ? master_id : bridge_master_id; // ------------------------------------------------------------------ // Read response pipeline // cycle N : iop_rd_en high, request routed downstream (or unmapped) // cycle N+1: iop_rd_valid high, data from RAM or fault // ------------------------------------------------------------------ logic rd_pending; logic rd_was_ram; logic rd_was_sif; logic rd_was_dmac; logic rd_was_intc; logic rd_was_bios; logic rd_was_pad; // Ch234 // Ch261 — rd_pending only pulses when the CPU read is ACTUALLY // serviced this cycle. Three cases: // 1. Non-RAM CPU read: always serviced (separate decode paths, // no arbitration). Pulse rd_pending normally. // 2. RAM CPU read, no collision: serviced this cycle (serve_cpu_now // fires above). Pulse rd_pending. // 3. RAM CPU read in collision: deferred (cpu_pend_valid latches). // Do NOT pulse rd_pending — iop_rd_valid stays low until the // deferred read finally fires (serve_cpu_def). // 4. Deferred RAM read finally serviced (serve_cpu_def): pulse // rd_pending with rd_was_ram=1; the data arrives next cycle. always_ff @(posedge clk) begin if (!rst_n) begin rd_pending <= 1'b0; rd_was_ram <= 1'b0; rd_was_sif <= 1'b0; rd_was_dmac <= 1'b0; rd_was_intc <= 1'b0; rd_was_bios <= 1'b0; rd_was_pad <= 1'b0; end else if (serve_cpu_def) begin // Deferred RAM read serviced this cycle — data next cycle. rd_pending <= 1'b1; rd_was_ram <= 1'b1; rd_was_sif <= 1'b0; rd_was_dmac <= 1'b0; rd_was_intc <= 1'b0; rd_was_bios <= 1'b0; rd_was_pad <= 1'b0; end else if (iop_rd_en && !(rd_is_ram && cpu_dma_collision)) begin // Normal read path: live RAM read with no collision, OR // any non-RAM CPU read (decoded by rd_is_*, routed via // independent paths so no arbitration concern). rd_pending <= 1'b1; rd_was_ram <= rd_is_ram; rd_was_sif <= rd_is_sif; rd_was_dmac <= rd_is_dmac; rd_was_intc <= rd_is_intc; rd_was_bios <= rd_is_bios; rd_was_pad <= rd_is_pad; end else begin // Collision-deferred OR idle cycle. CPU waits for deferred // read to fire; iop_rd_valid stays low. rd_pending <= 1'b0; end end assign iop_rd_valid = rd_pending; assign iop_rd_data = rd_was_ram ? ram_rd_data : rd_was_sif ? sif_rd_data : rd_was_dmac ? iop_dmac_rd_data : rd_was_intc ? iop_intc_rd_data : rd_was_bios ? bios_rd_data : rd_was_pad ? pad_rd_data : 32'hDEADBEEF; // ------------------------------------------------------------------ // DMA read response pipeline (separate from CPU pipeline). Ch261 — // CPU+DMA collision is now handled cleanly by the deferred-CPU-slot // above: DMA wins the port immediately, CPU's read is latched and // serviced on the next non-DMA cycle. DMA always gets its own word // on its expected timing; no silent corruption. // ------------------------------------------------------------------ logic dma_rd_pending; logic dma_rd_was_ram; always_ff @(posedge clk) begin if (!rst_n) begin dma_rd_pending <= 1'b0; dma_rd_was_ram <= 1'b0; end else begin dma_rd_pending <= dma_rd_en; if (dma_rd_en) dma_rd_was_ram <= dma_rd_is_ram; end end assign dma_rd_valid = dma_rd_pending; assign dma_rd_data = dma_rd_was_ram ? ram_rd_data : 32'hDEADBEEF; // ------------------------------------------------------------------ // Trace emission — one event per cycle. Priority: // CPU read > CPU write > DMA read > bridge write // Masters are expected to be sequenced in TBs; priority is defensive // for the rare collision case. // ------------------------------------------------------------------ always_ff @(posedge clk) begin if (!rst_n) begin ev_valid <= 1'b0; ev_subsys <= SUBSYS_IOP; 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 if (iop_rd_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_IOP; if (rd_is_ram) begin ev_event <= EV_READ; ev_arg1 <= 64'd0; ev_arg3 <= REGION_IOP_RAM; end else if (rd_is_sif) begin ev_event <= EV_READ; ev_arg1 <= 64'd0; ev_arg3 <= REGION_SIF_REGS; end else if (rd_is_dmac) begin ev_event <= EV_READ; ev_arg1 <= 64'd0; ev_arg3 <= REGION_IOP_DMAC; end else if (rd_is_intc) begin ev_event <= EV_READ; ev_arg1 <= 64'd0; ev_arg3 <= REGION_IOP_INTC; end else if (rd_is_bios) begin ev_event <= EV_READ; ev_arg1 <= 64'd0; ev_arg3 <= REGION_IOP_BIOS; end else if (rd_is_pad) begin ev_event <= EV_READ; ev_arg1 <= 64'd0; ev_arg3 <= REGION_PAD_IO; end else begin ev_event <= EV_UNMAPPED; ev_arg1 <= 64'hDEADBEEF; ev_arg3 <= REGION_UNMAPPED; end ev_arg0 <= {32'd0, iop_rd_addr}; ev_arg2 <= {56'd0, master_id}; ev_flags <= 32'd0; end else if (iop_wr_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_IOP; if (cpu_wr_is_ram) begin ev_event <= EV_WRITE; ev_arg3 <= REGION_IOP_RAM; end else if (cpu_wr_is_sif) begin ev_event <= EV_WRITE; ev_arg3 <= REGION_SIF_REGS; end else if (cpu_wr_is_dmac) begin ev_event <= EV_WRITE; ev_arg3 <= REGION_IOP_DMAC; end else if (cpu_wr_is_intc) begin ev_event <= EV_WRITE; ev_arg3 <= REGION_IOP_INTC; end else if (cpu_wr_is_pad) begin ev_event <= EV_WRITE; ev_arg3 <= REGION_PAD_IO; end else begin ev_event <= EV_UNMAPPED; ev_arg3 <= REGION_UNMAPPED; end ev_arg0 <= {32'd0, iop_wr_addr}; ev_arg1 <= {32'd0, iop_wr_data}; ev_arg2 <= {56'd0, master_id}; ev_flags <= 32'h0000_0001; end else if (dma_rd_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_IOP; ev_event <= dma_rd_is_ram ? EV_READ : EV_UNMAPPED; ev_arg0 <= {32'd0, dma_rd_addr}; ev_arg1 <= dma_rd_is_ram ? 64'd0 : 64'hDEADBEEF; ev_arg2 <= {56'd0, dma_master_id}; ev_arg3 <= dma_rd_is_ram ? REGION_IOP_RAM : REGION_UNMAPPED; ev_flags <= 32'd0; end else if (bridge_wr_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_IOP; ev_event <= bridge_wr_is_ram ? EV_WRITE : EV_UNMAPPED; ev_arg0 <= {32'd0, bridge_wr_addr}; ev_arg1 <= {32'd0, bridge_wr_data}; ev_arg2 <= {56'd0, bridge_master_id}; ev_arg3 <= bridge_wr_is_ram ? REGION_IOP_RAM : REGION_UNMAPPED; ev_flags <= 32'h0000_0001; end else begin ev_valid <= 1'b0; end end endmodule : iop_memory_map_stub