ec82764bef
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
143 lines
5.0 KiB
Systemverilog
143 lines
5.0 KiB
Systemverilog
// 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
|