// retroDE_ps2 — ee_biu_mmio_stub // // Narrow latched-register-file stub for the EE Bus Interface Unit / // cache-control window at virtual `0xFFFE_0000 - 0xFFFE_0FFF` // (physical `0x1FFE_0000 - 0x1FFE_0FFF` after kseg1-stripping). // Architecturally this is the R5900's privileged BIU/control // register space — the same place the BIOS writes CACHE-control // and BIU-config values during boot. // // Chapter 9: chapter 8 closed the 0x1F80_xxxx hole. The first- // unmapped observer in tb_ee_core_bios_smoke then showed the next // unmapped event was a WRITE at 0xFFFE_0130 (pc=0xBFC0_21BC, // cycle 808). Multiple more writes to that same offset fire later // with values 0xCC4, 0xCC0, 0x1E988, 0xC04, 0x3202_000F — // classic cache/BIU config dance. Without a stub, these writes // land as UNMAPPED events; the first one reads back to this stub // would return 0xDEADBEEF and re-poison the pointer chain chapter // 8 just cleaned up. // // Codex's call for chapter 9: give this its own dedicated stub // with its own region tag, NOT a broad "everything else" fallback. // Keep architecturally distinct surfaces distinct. If the BIOS // later touches 0x1FA0_0000 (next unmapped in the observer), that // will be its own chapter, not folded in here. // // Semantics (same shape as ee_bootstrap_mmio_stub): // - 4 KiB window = 1024 × 32-bit latched registers, zero-init. // - Writes latch per-byte: for each `wr_be[i]`, byte[i] of the // addressed register updates; untouched lanes preserve their // prior value. Makes SB/SH through the window safe. // - Reads return currently-latched value, one-cycle latency. // - No side effects. BIOS read-modify-write sequences stay // self-consistent. // // Size cost: 1024 × 32 bits = 4 KiB sim memory. Negligible. // // Trace: per-access event on SUBSYS_MEM with region tag // `REGION_EE_BIU = 10` (distinct from REGION_EE_MISC_MMIO=9 so // post-run analysis can separate the two windows). `timescale 1ns/1ps module ee_biu_mmio_stub import trace_pkg::*; ( input logic clk, input logic rst_n, // Write port — 12-bit offset within the 4 KiB window input logic reg_wr_en, input logic [11:0] reg_wr_addr, input logic [31:0] reg_wr_data, input logic [3:0] reg_wr_be, // Read port — 1-cycle latency input logic reg_rd_en, input logic [11:0] reg_rd_addr, output logic [31:0] reg_rd_data, output logic reg_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 ); localparam int WORDS = 1024; // 4 KiB / 4 localparam logic [63:0] REGION_EE_BIU = 64'd10; logic [31:0] regs [0:WORDS-1]; initial begin for (int i = 0; i < WORDS; i++) regs[i] = 32'd0; end logic [9:0] wr_idx; logic [9:0] rd_idx; assign wr_idx = reg_wr_addr[11:2]; assign rd_idx = reg_rd_addr[11:2]; // Per-byte write latch always_ff @(posedge clk) begin if (rst_n && reg_wr_en) begin if (reg_wr_be[0]) regs[wr_idx][ 7: 0] <= reg_wr_data[ 7: 0]; if (reg_wr_be[1]) regs[wr_idx][15: 8] <= reg_wr_data[15: 8]; if (reg_wr_be[2]) regs[wr_idx][23:16] <= reg_wr_data[23:16]; if (reg_wr_be[3]) regs[wr_idx][31:24] <= reg_wr_data[31:24]; end end // Read — 1-cycle latency always_ff @(posedge clk) begin if (!rst_n) begin reg_rd_data <= 32'd0; reg_rd_valid <= 1'b0; end else begin reg_rd_valid <= reg_rd_en; if (reg_rd_en) reg_rd_data <= regs[rd_idx]; end end // Trace — write wins same-cycle collision (defensive; map enforces // mutual exclusion) always_ff @(posedge clk) begin if (!rst_n) begin ev_valid <= 1'b0; ev_subsys <= SUBSYS_MEM; ev_event <= EV_WRITE; ev_arg0 <= 64'd0; ev_arg1 <= 64'd0; ev_arg2 <= 64'd0; ev_arg3 <= 64'd0; ev_flags <= 32'd0; end else if (reg_wr_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_MEM; ev_event <= EV_WRITE; ev_arg0 <= {52'd0, reg_wr_addr}; ev_arg1 <= {32'd0, reg_wr_data}; ev_arg2 <= {60'd0, reg_wr_be}; ev_arg3 <= REGION_EE_BIU; ev_flags <= 32'h0000_0001; end else if (reg_rd_en) begin ev_valid <= 1'b1; ev_subsys <= SUBSYS_MEM; ev_event <= EV_READ; ev_arg0 <= {52'd0, reg_rd_addr}; ev_arg1 <= {32'd0, regs[rd_idx]}; ev_arg2 <= 64'd0; ev_arg3 <= REGION_EE_BIU; ev_flags <= 32'd0; end else begin ev_valid <= 1'b0; end end endmodule : ee_biu_mmio_stub