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>
1229 lines
60 KiB
Systemverilog
1229 lines
60 KiB
Systemverilog
// retroDE_ps2 — ee_memory_map_stub
|
||
//
|
||
// EE-visible address decode. Wave 2.7 revision added a DMAC read-master
|
||
// port and a RAM region that routes to ee_ram_stub. Wave 3 reverse-
|
||
// direction addition: a bridge write-master port for SIF egress landing
|
||
// (128-bit), mirroring the IOP map's bridge port but in the EE→RAM
|
||
// write direction. EE-core chapter 3 addition: a CPU-side EE DMAC
|
||
// channel-2 (GIF) register write port, decoded at phys[28:12] ==
|
||
// 17'h1_000A (i.e. 0x1000_A000-0x1000_AFFF, 4 KiB per-channel window).
|
||
// Only ch2 is decoded — other EE DMAC channels are intentionally not
|
||
// routed yet. Mirrors the IOP map's single-channel ch9 decode pattern.
|
||
// EE-core chapter 4 addition: a read counterpart at the same decode.
|
||
// The DMAC response joins the existing EE CPU read pipeline alongside
|
||
// BIOS and EE RAM, 1-cycle latency, so software can poll CHCR.start
|
||
// or DONE_COUNT instead of burning fixed delay slots. EE-core chapter
|
||
// 5 addition: an EE INTC register window at phys[28:12] == 17'h1_000F
|
||
// (0x1000_F000-0x1000_FFFF) with both read and write, so the EE core
|
||
// can program INTC_MASK, observe INTC_STAT, and ack via W1C — mirrors
|
||
// iop_memory_map_stub's IOP INTC decode but at the EE physical slot.
|
||
// Chapter 8 addition (first machine-state bring-up): an "EE bootstrap
|
||
// MMIO" window at phys[28:16] == 13'h1F80 (0x1F80_0000-0x1F80_FFFF,
|
||
// 64 KiB) covering MCH / SBUS / RDRAM-init registers the BIOS probes
|
||
// very early. Without decode, CPU reads there returned 0xDEADBEEF and
|
||
// that poison eventually wedged the core in a self-referential list
|
||
// walk. Routed to ee_bootstrap_mmio_stub with latched read/write
|
||
// semantics so read/modify/write sequences stay self-consistent.
|
||
//
|
||
// Contract refs:
|
||
// docs/stub_module_plan.md (Wave 1, item 3)
|
||
// docs/wave25_memory_backed_dma_plan.md (DMAC as memory client)
|
||
// docs/wave26_multi_beat_dma_plan.md (multi-beat transfers)
|
||
// docs/contracts/memory.md
|
||
//
|
||
// Address semantics:
|
||
// - EE fetch / CPU data port (32-bit data, CPU-visible virtual address):
|
||
// kseg0/kseg1 aliasing is modelled via `phys = ee_addr[28:0]` for
|
||
// both reads and writes. Regions decoded off the stripped phys:
|
||
// BIOS window phys[28:22] == 7'h7F (reads only)
|
||
// EE RAM window phys[28:25] == 4'h0 (reads and writes)
|
||
// EE DMAC ch2 (GIF) phys[28:12] == 17'h1_000A (reads and writes)
|
||
// → offset phys[7:0] passes to dmac_reg_stub
|
||
// (CHCR=0x00, MADR=0x10, QWC=0x20, TADR=0x30,
|
||
// DONE_COUNT=0x40)
|
||
// EE INTC phys[28:12] == 17'h1_000F (reads and writes)
|
||
// → offset phys[7:0] passes to intc_stub
|
||
// (INTC_STAT=0x00, INTC_MASK=0x10)
|
||
// EE bootstrap MMIO phys[28:16] == 13'h1F80 (reads and writes)
|
||
// → offset phys[15:0] passes to
|
||
// ee_bootstrap_mmio_stub (latched reg file)
|
||
// Anything else on this port is UNMAPPED.
|
||
// - DMAC read port (128-bit data): treats its address as a physical bus
|
||
// address directly. No kseg strip. RAM window decoded at
|
||
// dmac_addr[31:25] == 7'b0 (i.e., 0x00000000 - 0x01FFFFFF, 32 MiB).
|
||
// - Bridge write port (128-bit data): SIF egress bridge lands qwords
|
||
// at physical addresses in the same RAM window (bridge_wr_addr
|
||
// [31:25] == 7'b0). No kseg strip; writes bypass CPU side entirely.
|
||
// Caller drives its own master_id for trace attribution (convention:
|
||
// 5 = SIF EE-side bridge).
|
||
//
|
||
// 32-bit ↔ 128-bit bridging for CPU RAM access:
|
||
// EE RAM is 128-bit qword-addressable. A 32-bit CPU read selects one
|
||
// of four lanes by ee_rd_addr[3:2] on the response side. A 32-bit CPU
|
||
// write broadcasts ee_wr_data into the matching lane of the 128-bit
|
||
// write bus, with ram_wr_be[15:0] masked so only the four bytes of
|
||
// that lane are enabled (other lanes pass through as no-op). This is
|
||
// the same technique the sif_dma_ee_ram_bridge uses to build a qword
|
||
// from streamed 32-bit beats, but per-access instead of accumulated.
|
||
//
|
||
// Arbitration (for the shared 128-bit ram_rd / ram_wr ports):
|
||
// Reads: CPU wins over DMAC on same-cycle collision.
|
||
// Writes: CPU wins over bridge on same-cycle collision.
|
||
// TBs sequence masters in time; priority is defensive — on a real
|
||
// collision the loser's response data is undefined, documented not
|
||
// guarded. Mirrors the IOP map's CPU-vs-bridge write arbitration.
|
||
//
|
||
// Region ids (shared with ee_ram_stub and bios_rom_stub):
|
||
// 0 BIOS
|
||
// 1 EE_RAM
|
||
// 7 EE_DMAC (chapter 3 addition; avoids collision with IOP region ids
|
||
// 2..6 used by iop_memory_map_stub)
|
||
// 8 EE_INTC (chapter 5 addition)
|
||
// 9 EE_MISC_MMIO (chapter 8 addition; 0x1F80_xxxx bootstrap window)
|
||
// 10 EE_BIU (chapter 9 addition; 0xFFFE_0xxx window)
|
||
// 11 USEG_SHADOW (ch34 addition; first 4 MiB of useg, disjoint
|
||
// backing from kseg0 RAM after the ch33 de-aliasing)
|
||
// 0xFF UNMAPPED
|
||
//
|
||
// Master ids:
|
||
// 0 = EE_IFETCH
|
||
// 1 = DMAC
|
||
// 5 = SIF EE-side bridge (reverse-direction landing)
|
||
//
|
||
// Trace semantics:
|
||
// Map-layer events describe request routing (what was asked for, where it
|
||
// was sent). Arg1 is intentionally 0 when the request is routed to a
|
||
// backing store that will emit its own delivery event. `ee_ram_stub`
|
||
// emits the delivery MEM READ with the returned data — the two events
|
||
// together show the full ownership hop.
|
||
//
|
||
// Latency assumption (Wave 2.7):
|
||
// This map assumes fixed one-cycle backing-store latency. `bios_rd_valid`
|
||
// and `ram_rd_valid` are not consulted by the response pipeline — the
|
||
// map asserts `*_rd_valid` one cycle after the request unconditionally.
|
||
// All Wave 2.5/2.7 backing stubs honour that contract. If a later backing
|
||
// store introduces wait states, the map must grow proper response
|
||
// handshaking (tracking outstanding requests and gating `*_rd_valid` on
|
||
// the downstream `_rd_valid`). Flagged for the next memory-side expansion.
|
||
//
|
||
// Trace payload schemas:
|
||
// MAP.MEM READ arg0=addr arg1=0 arg2=master_id arg3=region_id
|
||
// MAP.MEM UNMAPPED arg0=addr arg1=0xDEADBEEF arg2=master_id arg3=0xFF
|
||
// (Wave 1 EE-write UNMAPPED unchanged: flags bit 0 indicates write)
|
||
|
||
`timescale 1ns/1ps
|
||
|
||
module ee_memory_map_stub
|
||
import trace_pkg::*;
|
||
#(
|
||
// Ch64 — narrow visibility experiment. When enabled, CPU useg
|
||
// stores whose phys falls in [CPU_USEG_TO_RAM_MIRROR_LO,
|
||
// CPU_USEG_TO_RAM_MIRROR_HI) are mirrored into ee_ram via the
|
||
// shared RAM write path, IN ADDITION to the existing write into
|
||
// useg_shadow_mem. This restores a narrow slice of the kseg0<->
|
||
// useg aliasing that Ch33's separate-backings simplification
|
||
// removed. Kept off by default; enabled by TB parameter override
|
||
// (CH64_USEG_MIRROR=1 in the bios-smoke build). Ch63 proved the
|
||
// BIOS writes memcpy source code via useg stores, so the memcpy
|
||
// at pc=0x30014 reading via kseg0 sees zero. A narrow mirror
|
||
// restores visibility for the affected address range only.
|
||
parameter bit CPU_USEG_TO_RAM_MIRROR_EN = 1'b0,
|
||
parameter logic [28:0] CPU_USEG_TO_RAM_MIRROR_LO = 29'h0004_4000,
|
||
parameter logic [28:0] CPU_USEG_TO_RAM_MIRROR_HI = 29'h0004_4700,
|
||
|
||
// Ch65 — symmetric narrow mirror for the destination direction.
|
||
// When enabled, CPU kseg0/kseg1 stores that hit the RAM decode
|
||
// AND whose phys lies in [CPU_KSEG0_TO_USEG_SHADOW_MIRROR_LO,
|
||
// _HI) are ALSO committed to useg_shadow_mem via the existing
|
||
// byte-enable write path, in addition to the normal ee_ram
|
||
// write. This restores the second half of kseg0<->useg aliasing
|
||
// for the memcpy destination region. Default off; enabled by TB
|
||
// parameter override (CH65_KSEG_MIRROR=1 in the bios-smoke
|
||
// build). Ch64 proved this BIOS pattern: build code via useg,
|
||
// copy via kseg0, execute via useg.
|
||
parameter bit CPU_KSEG0_TO_USEG_SHADOW_MIRROR_EN = 1'b0,
|
||
parameter logic [28:0] CPU_KSEG0_TO_USEG_SHADOW_MIRROR_LO = 29'h001A_4000,
|
||
parameter logic [28:0] CPU_KSEG0_TO_USEG_SHADOW_MIRROR_HI = 29'h001A_5000,
|
||
|
||
// Ch70 — coherent RAM-alias mode. Promotes the two narrow Ch64/
|
||
// Ch65 mirror experiments into a single bidirectional aliasing
|
||
// policy for the [LO, HI) phys window. When enabled, CPU writes
|
||
// anywhere in the window mirror into the OTHER backing
|
||
// (useg→ee_ram and kseg→useg_shadow), restoring the kseg0↔useg
|
||
// aliasing real PS2 hardware has via the TLB while keeping
|
||
// MMIO/DMAC/INTC/BIU/BIOS regions de-aliased per Ch33's intent
|
||
// (those decode predicates short-circuit RAM eligibility, so
|
||
// the alias never mirrors into them). Default off for
|
||
// regression compatibility. Default window covers the first
|
||
// 4 MiB — wide enough for the BIOS's RAM-resident copied code
|
||
// (Ch64..Ch69 evidence) without touching kseg0 RAM beyond the
|
||
// useg_shadow's 4 MiB span.
|
||
parameter bit CPU_RAM_ALIAS_EN = 1'b0,
|
||
parameter logic [28:0] CPU_RAM_ALIAS_LO = 29'h0000_0000,
|
||
parameter logic [28:0] CPU_RAM_ALIAS_HI = 29'h0040_0000,
|
||
|
||
// Ch145 — useg-shadow backing size. Default 1M words = 4 MiB
|
||
// matches the original ch34 contract (useg first 4 MiB has its
|
||
// own backing, disjoint from kseg0 RAM). For hardware builds
|
||
// where useg is unused (e.g., the Ch123 PSMCT32 raster demo
|
||
// runs the bootlet entirely from BIOS at 0xBFC0_0000 and the
|
||
// GIF payload from RAM at phys 0x100 — no useg traffic at all),
|
||
// override this to a small value (e.g., 1024 words = 4 KiB) to
|
||
// shrink the inferred BRAM footprint by ~1024×. No address
|
||
// decode changes; the index `ee_rd_phys[21:2]` is naturally
|
||
// bounded by the smaller array on smaller sizes (any access
|
||
// beyond returns whatever the synth tool maps; for the Ch123
|
||
// demo no such access ever happens). Keep the default to leave
|
||
// all existing TBs byte-identical.
|
||
parameter int unsigned USEG_SHADOW_WORDS_PARAM = 1024 * 1024,
|
||
|
||
// Ch296 — useg-shadow backing enable. Default 1 = current behavior
|
||
// EXACTLY (the `useg_shadow_mem` array and all its read/write logic
|
||
// are instantiated; every existing BIOS/qbert/useg sim is byte-
|
||
// identical). When 0, the array and its read/write logic are fully
|
||
// removed from elaboration (wrapped in a generate-if), so the ~33k
|
||
// flip-flops Quartus bit-blasts the array into on the board build
|
||
// disappear. With the shadow disabled, useg READS return the
|
||
// unmapped value (0xDEADBEEF via the existing read-mux fall-through,
|
||
// because `ee_rd_is_useg_shadow` is forced to 0) and useg WRITES are
|
||
// dropped (no-op). Every other region (BIOS, EE-RAM, GS-priv MMIO,
|
||
// DMAC, INTC, BIU, bootstrap MMIO) is unchanged. The board PSMCT32
|
||
// raster demo never issues useg traffic (bootlet runs from BIOS at
|
||
// 0xBFC0_0000, GIF payload from EE-RAM via DMAC), so disabling the
|
||
// shadow on the board path is free. ONLY the board/synth top sets 0;
|
||
// sim TBs and the BIOS/qbert path keep the default 1.
|
||
parameter bit USEG_SHADOW_ENABLE = 1'b1
|
||
) (
|
||
input logic clk,
|
||
input logic rst_n,
|
||
|
||
// ------------------------------------------------------------------
|
||
// EE fetch port (32-bit data, virtual address with kseg aliasing)
|
||
// ------------------------------------------------------------------
|
||
input logic ee_rd_en,
|
||
input logic [31:0] ee_rd_addr,
|
||
output logic [31:0] ee_rd_data,
|
||
output logic ee_rd_valid,
|
||
|
||
input logic ee_wr_en,
|
||
input logic [31:0] ee_wr_addr,
|
||
input logic [31:0] ee_wr_data,
|
||
input logic [3:0] ee_wr_be,
|
||
|
||
// ------------------------------------------------------------------
|
||
// DMAC read port (128-bit data, physical address)
|
||
// ------------------------------------------------------------------
|
||
input logic dmac_rd_en,
|
||
input logic [31:0] dmac_rd_addr,
|
||
output logic [127:0] dmac_rd_data,
|
||
output logic dmac_rd_valid,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Bridge write port (Wave 3 reverse-direction landing). 128-bit data,
|
||
// physical address. Caller provides its own master_id. Only EE RAM
|
||
// region is mapped from this port in current scope.
|
||
// ------------------------------------------------------------------
|
||
input logic bridge_wr_en,
|
||
input logic [31:0] bridge_wr_addr,
|
||
input logic [127:0] bridge_wr_data,
|
||
input logic [15:0] bridge_wr_be,
|
||
input logic [7:0] bridge_master_id,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Downstream to bios_rom_stub (EE fetch path)
|
||
// ------------------------------------------------------------------
|
||
output logic bios_rd_en,
|
||
output logic [21:0] bios_rd_addr,
|
||
input logic [31:0] bios_rd_data,
|
||
input logic bios_rd_valid,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Downstream to ee_ram_stub (DMAC read path).
|
||
// Address is presented as a full-width RAM-local offset; consumers may
|
||
// truncate to match their own backing-store address width.
|
||
// ------------------------------------------------------------------
|
||
output logic ram_rd_en,
|
||
output logic [24:0] ram_rd_addr,
|
||
input logic [127:0] ram_rd_data,
|
||
input logic ram_rd_valid,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Downstream RAM write port (Wave 3). Driven by bridge_wr_*; no
|
||
// other master writes to EE RAM through this map in current scope.
|
||
// ------------------------------------------------------------------
|
||
output logic ram_wr_en,
|
||
output logic [24:0] ram_wr_addr,
|
||
output logic [127:0] ram_wr_data,
|
||
output logic [15:0] ram_wr_be,
|
||
output logic [7:0] ram_master_id,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Downstream EE DMAC ch2 (GIF) register write port (chapter 3).
|
||
// Fires when the CPU writes within 0x1000_A000-0x1000_AFFF. 8-bit
|
||
// offset matches dmac_reg_stub's register surface (CHCR/MADR/QWC/
|
||
// TADR at 0x00/0x10/0x20/0x30).
|
||
// ------------------------------------------------------------------
|
||
output logic ee_dmac_ch2_wr_en,
|
||
output logic [7:0] ee_dmac_ch2_wr_addr,
|
||
output logic [31:0] ee_dmac_ch2_wr_data,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Downstream EE DMAC ch2 (GIF) register read port (chapter 4).
|
||
// 1-cycle latency mirrors BIOS and EE RAM reads. reg_rd_valid is
|
||
// not consulted by the response pipeline — the map asserts
|
||
// ee_rd_valid one cycle after the CPU request unconditionally,
|
||
// same convention as the other backing stubs.
|
||
// ------------------------------------------------------------------
|
||
output logic ee_dmac_ch2_rd_en,
|
||
output logic [7:0] ee_dmac_ch2_rd_addr,
|
||
input logic [31:0] ee_dmac_ch2_rd_data,
|
||
input logic ee_dmac_ch2_rd_valid,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Downstream EE INTC register ports (chapter 5). Same shape as the
|
||
// DMAC register ports: 8-bit shared offset surface, write-then-
|
||
// read response pipeline joins the EE CPU mux. Offsets INTC_STAT
|
||
// at 0x00 and INTC_MASK at 0x10 match intc_stub's default.
|
||
// ------------------------------------------------------------------
|
||
output logic ee_intc_wr_en,
|
||
output logic [7:0] ee_intc_wr_addr,
|
||
output logic [31:0] ee_intc_wr_data,
|
||
|
||
output logic ee_intc_rd_en,
|
||
output logic [7:0] ee_intc_rd_addr,
|
||
input logic [31:0] ee_intc_rd_data,
|
||
input logic ee_intc_rd_valid,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Downstream EE bootstrap-MMIO ports (chapter 8). 16-bit window
|
||
// offset (0x1F80_0000-0x1F80_FFFF, 64 KiB), 1-cycle read latency
|
||
// matching the rest of the stub ecosystem. Routed to
|
||
// ee_bootstrap_mmio_stub which latches writes and returns the
|
||
// last-written value on read (so BIOS read/modify/write sequences
|
||
// stay self-consistent instead of laundering 0xDEADBEEF into
|
||
// data structures).
|
||
// ------------------------------------------------------------------
|
||
output logic ee_misc_mmio_wr_en,
|
||
output logic [15:0] ee_misc_mmio_wr_addr,
|
||
output logic [31:0] ee_misc_mmio_wr_data,
|
||
output logic [3:0] ee_misc_mmio_wr_be,
|
||
|
||
output logic ee_misc_mmio_rd_en,
|
||
output logic [15:0] ee_misc_mmio_rd_addr,
|
||
input logic [31:0] ee_misc_mmio_rd_data,
|
||
input logic ee_misc_mmio_rd_valid,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Ch112 — GS privileged-MMIO window (0x1200_0000-0x1200_FFFF,
|
||
// 64 KiB). Routed to ee_gs_priv_bridge_stub, which accumulates
|
||
// 32-bit half-writes per 8-byte slot and fires a 64-bit
|
||
// gs_stub.reg_wr_* pulse on each EE half-write. The map
|
||
// decode is symmetric with the misc-MMIO path: top 13 bits of
|
||
// the 29-bit physical address tag the window. Read side is
|
||
// not modelled at this scope (the Ch111 bridge is write-only,
|
||
// matching the limited read coverage of the GS priv block).
|
||
// TBs that don't model GS-priv MMIO can leave these ports
|
||
// unconnected (named-port instantiation tolerates omitted
|
||
// outputs).
|
||
// ------------------------------------------------------------------
|
||
output logic ee_gs_priv_wr_en,
|
||
output logic [15:0] ee_gs_priv_wr_addr,
|
||
output logic [31:0] ee_gs_priv_wr_data,
|
||
output logic [3:0] ee_gs_priv_wr_be,
|
||
|
||
// ------------------------------------------------------------------
|
||
// EE BIU / cache-control window at 0xFFFE_0000-0xFFFE_0FFF (4 KiB).
|
||
// Narrow, dedicated stub — kept architecturally separate from the
|
||
// 0x1F80_xxxx bootstrap MMIO window so each decode surface has its
|
||
// own region tag and its own evidence trail.
|
||
// ------------------------------------------------------------------
|
||
output logic ee_biu_wr_en,
|
||
output logic [11:0] ee_biu_wr_addr,
|
||
output logic [31:0] ee_biu_wr_data,
|
||
output logic [3:0] ee_biu_wr_be,
|
||
|
||
output logic ee_biu_rd_en,
|
||
output logic [11:0] ee_biu_rd_addr,
|
||
input logic [31:0] ee_biu_rd_data,
|
||
input logic ee_biu_rd_valid,
|
||
|
||
// ------------------------------------------------------------------
|
||
// Trace (shared; priority EE > DMAC on collision)
|
||
// ------------------------------------------------------------------
|
||
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_BIOS = 64'd0;
|
||
localparam logic [63:0] REGION_EE_RAM = 64'd1;
|
||
localparam logic [63:0] REGION_EE_DMAC = 64'd7;
|
||
localparam logic [63:0] REGION_EE_INTC = 64'd8;
|
||
localparam logic [63:0] REGION_EE_MISC_MMIO = 64'd9;
|
||
localparam logic [63:0] REGION_EE_BIU = 64'd10;
|
||
// Ch33: dedicated tag for the useg-shadow backing (first 4 MiB of
|
||
// useg, disjoint from kseg0 RAM). Kept as a separate region so
|
||
// trace/post-run analysis can distinguish shadow hits from real
|
||
// ee_ram hits.
|
||
localparam logic [63:0] REGION_USEG_SHADOW = 64'd11;
|
||
// Ch112: GS-privileged-MMIO window (0x1200_0000-0x1200_FFFF).
|
||
// Routed to ee_gs_priv_bridge_stub.
|
||
localparam logic [63:0] REGION_EE_GS_PRIV = 64'd12;
|
||
// Ch287: EE DMAC global control/status registers at 0x1000_E000.
|
||
// Hosts D_CTRL/D_STAT/D_PCR/D_SQWC/D_RBSR/D_RBOR. Instantiated
|
||
// INTERNALLY (ee_dmac_ctrl_stub) so existing TBs don't need to
|
||
// route new ports.
|
||
localparam logic [63:0] REGION_EE_DMAC_CTRL = 64'd13;
|
||
// Ch288: EE DMAC per-channel register surfaces for channels NOT
|
||
// covered by a dedicated transfer-FSM stub. ch0 VIF0, ch1 VIF1,
|
||
// ch3 IPU_FROM, ch4 IPU_TO, ch5 SIF0 — each a 4 KiB window at
|
||
// 0x1000_8000 + N*0x1000. Latched CHCR/MADR/QWC/TADR only; no
|
||
// FSM. ch2 GIF stays on its dedicated external port.
|
||
localparam logic [63:0] REGION_EE_DMAC_PASSIVE = 64'd14;
|
||
localparam logic [63:0] REGION_UNMAPPED = 64'hFF;
|
||
localparam logic [63:0] MASTER_EE_IFETCH = 64'd0; // EE CPU (fetch + data)
|
||
localparam logic [63:0] MASTER_DMAC = 64'd1;
|
||
|
||
// EE DMAC channel-2 (GIF) MMIO base — only channel decoded in this
|
||
// chapter. phys[28:12] == EE_DMAC_CH2_BASE[28:12] identifies the
|
||
// 4 KiB per-channel register window at 0x1000_A000.
|
||
localparam logic [28:0] EE_DMAC_CH2_BASE = 29'h1000_A000;
|
||
// EE INTC MMIO base at 0x1000_F000.
|
||
localparam logic [28:0] EE_INTC_BASE = 29'h1000_F000;
|
||
// Ch287 — EE DMAC global control/status base at 0x1000_E000
|
||
// (D_CTRL/D_STAT/D_PCR/D_SQWC/D_RBSR/D_RBOR). Window is 4 KiB to
|
||
// match the discrimination pattern of the existing DMAC ch2 / INTC
|
||
// bases; the live registers occupy only the first 256 bytes
|
||
// (8-bit reg_offset), the remainder is silent within the window
|
||
// (writes dropped + traced, reads return 0).
|
||
localparam logic [28:0] EE_DMAC_CTRL_BASE = 29'h1000_E000;
|
||
|
||
// EE bootstrap-MMIO window covers the full 0x1F80_0000-0x1F80_FFFF
|
||
// range (64 KiB). Top 13 bits of the 29-bit physical address are
|
||
// the discriminator — see ee_bootstrap_mmio_stub.sv for the
|
||
// per-register latching semantics inside.
|
||
localparam logic [12:0] EE_MISC_MMIO_TAG = 13'h1F80;
|
||
|
||
// Ch112: GS privileged-MMIO window (PMODE/SMODE/DISPFB/DISPLAY/
|
||
// BGCOLOR/HWREG/etc.) at 0x1200_0000-0x1200_FFFF (64 KiB).
|
||
// Routed to ee_gs_priv_bridge_stub.
|
||
localparam logic [12:0] EE_GS_PRIV_TAG = 13'h1200;
|
||
|
||
// EE BIU/cache-control window at 0xFFFE_0000-0xFFFE_0FFF (4 KiB,
|
||
// phys 0x1FFE_0000-0x1FFE_0FFF after kseg1-strip). Narrow by design
|
||
// — chapter 9 covers a single architecturally-distinct surface the
|
||
// real BIOS touches for BIU/cache config. See ee_biu_mmio_stub.sv.
|
||
localparam logic [16:0] EE_BIU_MMIO_TAG = 17'h1FFE0;
|
||
|
||
// ------------------------------------------------------------------
|
||
// Decode: EE CPU side (kseg-stripped), bridge side (physical),
|
||
// DMAC side (physical).
|
||
// ------------------------------------------------------------------
|
||
|
||
logic [28:0] ee_rd_phys;
|
||
logic [28:0] ee_wr_phys;
|
||
logic ee_rd_is_bios;
|
||
logic ee_rd_is_ram;
|
||
logic ee_rd_is_dmac_ch2;
|
||
logic ee_rd_is_dmac_ctrl; // Ch287
|
||
logic ee_rd_is_dmac_passive; // Ch288 (ch0/1/3/4/5)
|
||
logic ee_rd_is_intc;
|
||
logic ee_rd_is_misc_mmio;
|
||
logic ee_rd_is_biu;
|
||
logic ee_wr_is_ram;
|
||
logic ee_wr_is_dmac_ch2;
|
||
logic ee_wr_is_dmac_ctrl; // Ch287
|
||
logic ee_wr_is_dmac_passive; // Ch288
|
||
logic ee_wr_is_intc;
|
||
logic ee_wr_is_misc_mmio;
|
||
logic ee_wr_is_biu;
|
||
logic ee_wr_is_gs_priv;
|
||
logic [21:0] ee_bios_offset;
|
||
logic [24:0] ee_rd_ram_offset;
|
||
logic [24:0] ee_wr_ram_offset;
|
||
|
||
// ------------------------------------------------------------------
|
||
// Chapter 33 — useg de-aliasing experiment. Prior behavior: phys =
|
||
// addr[28:0] strip treated useg (0x0000_0000-0x7FFF_FFFF) and kseg0
|
||
// (0x8000_0000-0x9FFF_FFFF) as the same physical word. Real MIPS
|
||
// has useg TLB-mapped, so that alias is only "correct" when the
|
||
// BIOS has programmed a TLB entry. Ch32 proved BIOS issues ZERO
|
||
// TLBWI/TLBWR/TLBP/TLBR pre-ENTRY14 — so real HW's useg is
|
||
// unmapped in that window, and our alias is too permissive.
|
||
//
|
||
// Experimental fix: route useg accesses whose phys lies in
|
||
// [0, 4 MiB) to a dedicated in-map shadow backing, DISJOINT from
|
||
// the kseg0/kseg1 RAM. Keeps useg reads/writes self-consistent
|
||
// (unlike a zero/sink model) so any genuine useg-internal work
|
||
// the BIOS does still behaves, but de-aliases the ch12 memcpy
|
||
// from the ch31 walker's kseg0 read.
|
||
//
|
||
// 4 MiB shadow = 1M × 32-bit words. Big but cheap in sim.
|
||
// USEG = addr[31]==0 (0x0000_0000..0x7FFF_FFFF)
|
||
// kseg0/kseg1/kseg2/3 keep their existing phys[28:0]-strip
|
||
// behavior.
|
||
// ------------------------------------------------------------------
|
||
logic ee_rd_is_useg;
|
||
logic ee_wr_is_useg;
|
||
logic ee_rd_is_useg_shadow;
|
||
logic ee_wr_is_useg_shadow;
|
||
|
||
assign ee_rd_phys = ee_rd_addr[28:0];
|
||
assign ee_wr_phys = ee_wr_addr[28:0];
|
||
assign ee_rd_is_useg = (ee_rd_addr[31] == 1'b0);
|
||
assign ee_wr_is_useg = (ee_wr_addr[31] == 1'b0);
|
||
// Shadow covers first 4 MiB: phys[28:22] == 0 → phys in [0, 0x3FFFFF].
|
||
// That's enough for the low-RAM init region the BIOS touches via
|
||
// useg (ch12 memcpy at phys 0x1E28, ch23 table ops at phys
|
||
// 0x200..0x3FF, etc.). Accesses beyond 4 MiB to useg fall through
|
||
// to existing decode (will mostly land UNMAPPED).
|
||
// When USEG_SHADOW_ENABLE=0 the shadow decode is forced low so useg
|
||
// reads fall through to the 0xDEADBEEF unmapped mux arm and useg
|
||
// writes are dropped (the write logic below is also generate-removed).
|
||
// ee_rd_is_useg / ee_wr_is_useg are NOT gated — they still exclude
|
||
// useg from the RAM decode (`!ee_*_is_useg`), preserving the Ch33
|
||
// de-aliasing intent regardless of this knob.
|
||
assign ee_rd_is_useg_shadow = USEG_SHADOW_ENABLE && ee_rd_is_useg && (ee_rd_phys[28:22] == 7'd0);
|
||
// Forward-decl: cpu_rd_hit_ram is declared further down (line ~593).
|
||
// Used inside the ram-rd arbitration block and in the DMAC
|
||
// response pipeline (Ch115 — see comment block below).
|
||
assign ee_wr_is_useg_shadow = USEG_SHADOW_ENABLE && ee_wr_is_useg && (ee_wr_phys[28:22] == 7'd0);
|
||
assign ee_rd_is_bios = (ee_rd_phys[28:22] == 7'h7F);
|
||
// Exclude useg from RAM decode only — the TLB-aliasing wedge is
|
||
// specifically about useg-store-to-RAM conflating with
|
||
// kseg0-load-from-RAM. Useg aliases of MMIO/DMAC/INTC/BIU windows
|
||
// remain routed as before; the existing test benches exercise
|
||
// those via useg addressing (e.g. synthetic DMAC program at
|
||
// 0x1000A010 with addr[31]=0) and must keep working.
|
||
assign ee_rd_is_ram = !ee_rd_is_useg && (ee_rd_phys[28:25] == 4'h0);
|
||
assign ee_rd_is_dmac_ch2 = (ee_rd_phys[28:12] == EE_DMAC_CH2_BASE[28:12]);
|
||
assign ee_rd_is_dmac_ctrl = (ee_rd_phys[28:12] == EE_DMAC_CTRL_BASE[28:12]); // Ch287
|
||
// Ch288 — passive per-channel surface: ch0/1/3/4/5. Match the
|
||
// 0x1000_8xxx..0x1000_Dxxx span, excluding 0x1000_Axxx (ch2 GIF
|
||
// has its own dedicated stub via ee_dmac_ch2_* ports).
|
||
assign ee_rd_is_dmac_passive =
|
||
(ee_rd_phys[28:16] == 13'h1000) &&
|
||
((ee_rd_phys[15:12] == 4'h8) || (ee_rd_phys[15:12] == 4'h9) ||
|
||
(ee_rd_phys[15:12] == 4'hB) || (ee_rd_phys[15:12] == 4'hC) ||
|
||
(ee_rd_phys[15:12] == 4'hD));
|
||
assign ee_rd_is_intc = (ee_rd_phys[28:12] == EE_INTC_BASE[28:12]);
|
||
assign ee_rd_is_misc_mmio = (ee_rd_phys[28:16] == EE_MISC_MMIO_TAG);
|
||
assign ee_rd_is_biu = (ee_rd_phys[28:12] == EE_BIU_MMIO_TAG);
|
||
assign ee_wr_is_ram = !ee_wr_is_useg && (ee_wr_phys[28:25] == 4'h0);
|
||
assign ee_wr_is_dmac_ch2 = (ee_wr_phys[28:12] == EE_DMAC_CH2_BASE[28:12]);
|
||
assign ee_wr_is_dmac_ctrl = (ee_wr_phys[28:12] == EE_DMAC_CTRL_BASE[28:12]); // Ch287
|
||
// Ch288 — passive per-channel write decode (mirrors read side).
|
||
assign ee_wr_is_dmac_passive =
|
||
(ee_wr_phys[28:16] == 13'h1000) &&
|
||
((ee_wr_phys[15:12] == 4'h8) || (ee_wr_phys[15:12] == 4'h9) ||
|
||
(ee_wr_phys[15:12] == 4'hB) || (ee_wr_phys[15:12] == 4'hC) ||
|
||
(ee_wr_phys[15:12] == 4'hD));
|
||
assign ee_wr_is_intc = (ee_wr_phys[28:12] == EE_INTC_BASE[28:12]);
|
||
assign ee_wr_is_misc_mmio = (ee_wr_phys[28:16] == EE_MISC_MMIO_TAG);
|
||
assign ee_wr_is_biu = (ee_wr_phys[28:12] == EE_BIU_MMIO_TAG);
|
||
assign ee_wr_is_gs_priv = (ee_wr_phys[28:16] == EE_GS_PRIV_TAG);
|
||
assign ee_bios_offset = ee_rd_phys[21:0];
|
||
assign ee_rd_ram_offset = ee_rd_phys[24:0];
|
||
assign ee_wr_ram_offset = ee_wr_phys[24:0];
|
||
|
||
// ------------------------------------------------------------------
|
||
// Bridge RAM decode (general — not useg-shadow specific, referenced
|
||
// by the RAM-write arbitration and trace below). Kept at module
|
||
// scope so it survives when the useg-shadow backing is generate-
|
||
// removed (USEG_SHADOW_ENABLE=0).
|
||
// ------------------------------------------------------------------
|
||
logic bridge_is_ram;
|
||
logic [24:0] bridge_ram_offset;
|
||
assign bridge_is_ram = (bridge_wr_addr[31:25] == 7'd0);
|
||
assign bridge_ram_offset = bridge_wr_addr[24:0];
|
||
|
||
// ------------------------------------------------------------------
|
||
// Useg-shadow read response. Declared at module scope because the EE
|
||
// CPU read mux references `useg_shadow_rd_data` unconditionally. The
|
||
// procedural driver lives inside the generate-if below — when the
|
||
// shadow is disabled the else-arm ties this to 0 and the mux never
|
||
// selects it anyway (ee_rd_was_useg_shadow stays 0).
|
||
// ------------------------------------------------------------------
|
||
logic [31:0] useg_shadow_rd_data;
|
||
|
||
// ------------------------------------------------------------------
|
||
// Useg-shadow backing: 4 MiB = 1M words. Separate from kseg0/kseg1
|
||
// RAM. 1-cycle read latency, per-byte write-enable.
|
||
//
|
||
// Ch296 — the entire backing array plus its CPU-read, CPU-write, and
|
||
// bridge-write logic is wrapped in a generate-if on USEG_SHADOW_ENABLE.
|
||
// When disabled (board/synth build), the ~33k flip-flops Quartus bit-
|
||
// blasts `useg_shadow_mem` into are fully removed: useg reads return
|
||
// the unmapped value via the read mux (ee_rd_is_useg_shadow is forced
|
||
// 0), useg writes are dropped, and `useg_shadow_rd_data` is tied 0.
|
||
// ------------------------------------------------------------------
|
||
generate
|
||
if (USEG_SHADOW_ENABLE) begin : g_useg_shadow
|
||
localparam int USEG_SHADOW_WORDS = USEG_SHADOW_WORDS_PARAM; // Ch145 — parameter-driven (default 1M = 4 MiB)
|
||
logic [31:0] useg_shadow_mem [0:USEG_SHADOW_WORDS-1];
|
||
initial begin
|
||
for (int i = 0; i < USEG_SHADOW_WORDS; i++) useg_shadow_mem[i] = 32'd0;
|
||
end
|
||
|
||
logic [19:0] useg_rd_idx;
|
||
logic [19:0] useg_wr_idx;
|
||
assign useg_rd_idx = ee_rd_phys[21:2];
|
||
assign useg_wr_idx = ee_wr_phys[21:2];
|
||
|
||
logic useg_shadow_rd_valid;
|
||
logic [31:0] useg_shadow_rd_data_q;
|
||
always_ff @(posedge clk) begin
|
||
if (!rst_n) begin
|
||
useg_shadow_rd_valid <= 1'b0;
|
||
useg_shadow_rd_data_q <= 32'd0;
|
||
end else begin
|
||
useg_shadow_rd_valid <= ee_rd_en && ee_rd_is_useg_shadow;
|
||
if (ee_rd_en && ee_rd_is_useg_shadow)
|
||
useg_shadow_rd_data_q <= useg_shadow_mem[useg_rd_idx];
|
||
end
|
||
end
|
||
assign useg_shadow_rd_data = useg_shadow_rd_data_q;
|
||
|
||
// Ch65 — CPU kseg0 store mirror hit. Parallels the Ch64
|
||
// useg->ram mirror in the opposite direction. Disjoint from
|
||
// ee_wr_is_useg_shadow by construction (kseg0 writes set
|
||
// ee_wr_is_ram, not ee_wr_is_useg_shadow). useg_wr_idx already
|
||
// extracts ee_wr_phys[21:2], which is the right word index for
|
||
// both useg-stripped and kseg0-stripped phys in the first 4 MiB.
|
||
// Ch70 unified alias also covers the kseg→useg_shadow direction
|
||
// for any CPU RAM write whose phys is in [CPU_RAM_ALIAS_LO,
|
||
// CPU_RAM_ALIAS_HI). Subsumes the Ch65 narrow knob when enabled.
|
||
logic cpu_wr_kseg_alias_hit;
|
||
logic cpu_wr_kseg_shadow_mirror_hit;
|
||
assign cpu_wr_kseg_alias_hit =
|
||
CPU_RAM_ALIAS_EN && ee_wr_en && ee_wr_is_ram &&
|
||
(ee_wr_phys >= CPU_RAM_ALIAS_LO) &&
|
||
(ee_wr_phys < CPU_RAM_ALIAS_HI);
|
||
assign cpu_wr_kseg_shadow_mirror_hit =
|
||
cpu_wr_kseg_alias_hit ||
|
||
(CPU_KSEG0_TO_USEG_SHADOW_MIRROR_EN && ee_wr_en && ee_wr_is_ram &&
|
||
(ee_wr_phys >= CPU_KSEG0_TO_USEG_SHADOW_MIRROR_LO) &&
|
||
(ee_wr_phys < CPU_KSEG0_TO_USEG_SHADOW_MIRROR_HI));
|
||
|
||
always_ff @(posedge clk) begin
|
||
if (rst_n && ee_wr_en &&
|
||
(ee_wr_is_useg_shadow || cpu_wr_kseg_shadow_mirror_hit)) begin
|
||
if (ee_wr_be[0]) useg_shadow_mem[useg_wr_idx][ 7: 0] <= ee_wr_data[ 7: 0];
|
||
if (ee_wr_be[1]) useg_shadow_mem[useg_wr_idx][15: 8] <= ee_wr_data[15: 8];
|
||
if (ee_wr_be[2]) useg_shadow_mem[useg_wr_idx][23:16] <= ee_wr_data[23:16];
|
||
if (ee_wr_be[3]) useg_shadow_mem[useg_wr_idx][31:24] <= ee_wr_data[31:24];
|
||
end
|
||
end
|
||
|
||
// Ch55: producer-side install seam. Bridge writes whose byte address
|
||
// falls in the narrow coordinated-install window [0x80..0x1FF] also
|
||
// shadow into useg_shadow_mem, so the EE CPU (which reads useg
|
||
// exception-entry words via the shadow backing) observes bytes a
|
||
// real external producer (SIF/IOP or BootROM/CDVD handoff) deposits
|
||
// into physical RAM. ee_ram is still written unchanged through
|
||
// bridge_wr_hit_ram below — this is purely additive mirroring.
|
||
//
|
||
// Narrowed per Ch55 Codex audit finding 1: earlier draft shadowed
|
||
// all 4 MiB of low RAM, which would let unrelated future bridge
|
||
// writes become visible through useg reads and muddy diagnostics.
|
||
// The shared-surface install the BIOS needs lives only in
|
||
// [0x80..0x1FF]; anything else goes through the regular
|
||
// bridge→ee_ram path, disjoint from useg_shadow, matching the
|
||
// Ch33 de-aliasing intent. If a future chapter needs a wider
|
||
// mirror, raise BRIDGE_USEG_SHADOW_END here explicitly.
|
||
localparam logic [31:0] BRIDGE_USEG_SHADOW_BASE = 32'h0000_0080;
|
||
localparam logic [31:0] BRIDGE_USEG_SHADOW_END = 32'h0000_0200;
|
||
|
||
logic bridge_wr_in_install_window;
|
||
logic bridge_wr_is_useg_shadow;
|
||
logic [19:0] bridge_useg_wr_idx0;
|
||
logic [19:0] bridge_useg_wr_idx1;
|
||
logic [19:0] bridge_useg_wr_idx2;
|
||
logic [19:0] bridge_useg_wr_idx3;
|
||
assign bridge_wr_in_install_window =
|
||
(bridge_wr_addr >= BRIDGE_USEG_SHADOW_BASE) &&
|
||
(bridge_wr_addr < BRIDGE_USEG_SHADOW_END);
|
||
assign bridge_wr_is_useg_shadow =
|
||
bridge_wr_en && bridge_is_ram && bridge_wr_in_install_window;
|
||
assign bridge_useg_wr_idx0 = bridge_wr_addr[21:2];
|
||
assign bridge_useg_wr_idx1 = bridge_wr_addr[21:2] + 20'd1;
|
||
assign bridge_useg_wr_idx2 = bridge_wr_addr[21:2] + 20'd2;
|
||
assign bridge_useg_wr_idx3 = bridge_wr_addr[21:2] + 20'd3;
|
||
|
||
always_ff @(posedge clk) begin
|
||
if (rst_n && bridge_wr_is_useg_shadow) begin
|
||
if (bridge_wr_be[ 0]) useg_shadow_mem[bridge_useg_wr_idx0][ 7: 0] <= bridge_wr_data[ 7: 0];
|
||
if (bridge_wr_be[ 1]) useg_shadow_mem[bridge_useg_wr_idx0][15: 8] <= bridge_wr_data[ 15: 8];
|
||
if (bridge_wr_be[ 2]) useg_shadow_mem[bridge_useg_wr_idx0][23:16] <= bridge_wr_data[ 23: 16];
|
||
if (bridge_wr_be[ 3]) useg_shadow_mem[bridge_useg_wr_idx0][31:24] <= bridge_wr_data[ 31: 24];
|
||
if (bridge_wr_be[ 4]) useg_shadow_mem[bridge_useg_wr_idx1][ 7: 0] <= bridge_wr_data[ 39: 32];
|
||
if (bridge_wr_be[ 5]) useg_shadow_mem[bridge_useg_wr_idx1][15: 8] <= bridge_wr_data[ 47: 40];
|
||
if (bridge_wr_be[ 6]) useg_shadow_mem[bridge_useg_wr_idx1][23:16] <= bridge_wr_data[ 55: 48];
|
||
if (bridge_wr_be[ 7]) useg_shadow_mem[bridge_useg_wr_idx1][31:24] <= bridge_wr_data[ 63: 56];
|
||
if (bridge_wr_be[ 8]) useg_shadow_mem[bridge_useg_wr_idx2][ 7: 0] <= bridge_wr_data[ 71: 64];
|
||
if (bridge_wr_be[ 9]) useg_shadow_mem[bridge_useg_wr_idx2][15: 8] <= bridge_wr_data[ 79: 72];
|
||
if (bridge_wr_be[10]) useg_shadow_mem[bridge_useg_wr_idx2][23:16] <= bridge_wr_data[ 87: 80];
|
||
if (bridge_wr_be[11]) useg_shadow_mem[bridge_useg_wr_idx2][31:24] <= bridge_wr_data[ 95: 88];
|
||
if (bridge_wr_be[12]) useg_shadow_mem[bridge_useg_wr_idx3][ 7: 0] <= bridge_wr_data[103: 96];
|
||
if (bridge_wr_be[13]) useg_shadow_mem[bridge_useg_wr_idx3][15: 8] <= bridge_wr_data[111:104];
|
||
if (bridge_wr_be[14]) useg_shadow_mem[bridge_useg_wr_idx3][23:16] <= bridge_wr_data[119:112];
|
||
if (bridge_wr_be[15]) useg_shadow_mem[bridge_useg_wr_idx3][31:24] <= bridge_wr_data[127:120];
|
||
end
|
||
end
|
||
end else begin : g_no_useg_shadow
|
||
// USEG_SHADOW_ENABLE=0 — no backing array, no read/write logic.
|
||
// useg reads fall through to the 0xDEADBEEF unmapped mux arm
|
||
// (ee_rd_is_useg_shadow is forced 0); useg writes are dropped.
|
||
assign useg_shadow_rd_data = 32'd0;
|
||
end
|
||
endgenerate
|
||
|
||
logic dmac_is_ram;
|
||
logic [24:0] dmac_ram_offset;
|
||
assign dmac_is_ram = (dmac_rd_addr[31:25] == 7'd0);
|
||
assign dmac_ram_offset = dmac_rd_addr[24:0];
|
||
|
||
// ------------------------------------------------------------------
|
||
// BIOS routing (CPU fetch only — BIOS is read-only from every port)
|
||
// ------------------------------------------------------------------
|
||
|
||
assign bios_rd_en = ee_rd_en && ee_rd_is_bios;
|
||
assign bios_rd_addr = ee_bios_offset;
|
||
|
||
// ------------------------------------------------------------------
|
||
// Shared 128-bit RAM read port. CPU wins over DMAC on collision.
|
||
// CPU 32-bit read selects a lane from the 128-bit qword on the
|
||
// response side.
|
||
// ------------------------------------------------------------------
|
||
|
||
logic cpu_rd_hit_ram;
|
||
logic dmac_rd_hit_ram;
|
||
assign cpu_rd_hit_ram = ee_rd_en && ee_rd_is_ram;
|
||
assign dmac_rd_hit_ram = dmac_rd_en && dmac_is_ram;
|
||
|
||
// ------------------------------------------------------------------
|
||
// Ch115 — CPU vs DMAC RAM-read arbitration with DMAC retry.
|
||
//
|
||
// PRE-Ch115 BUG: when both `cpu_rd_hit_ram` and
|
||
// `dmac_rd_hit_ram` fired on the same cycle, the map gave
|
||
// CPU priority on `ram_rd_addr` but ALSO returned `dmac_rd_valid`
|
||
// next cycle as if the DMAC had been serviced — so the DMAC
|
||
// saw the CPU's data instead of its own. With a RAM-resident
|
||
// EE bootlet busy-fetching while DMAC streamed a payload from
|
||
// the same RAM, this silently corrupted the DMAC payload
|
||
// (reproducer: tb_ee_ram_cpu_dmac_contention).
|
||
//
|
||
// FIX: keep CPU priority on the RAM bus, but when the DMAC's
|
||
// request is contended out, BUFFER the DMAC's address into a
|
||
// 1-deep retry slot here in the map. On the next cycle that
|
||
// is NOT cpu-rd-hit-ram, replay the buffered DMAC read. The
|
||
// DMAC's `mem_rd_en` is a one-shot pulse and `dmac_reg_stub`
|
||
// waits in S_FETCH_WAIT for `mem_rd_valid`, so deferring the
|
||
// valid response by one (or more) cycles is safe — the DMAC
|
||
// simply waits longer before advancing to S_ACTIVE_SEND. The
|
||
// CPU's path is unchanged: its request always fires this cycle.
|
||
// ------------------------------------------------------------------
|
||
logic dmac_rd_buf_q;
|
||
logic [24:0] dmac_rd_buf_addr_q;
|
||
logic dmac_rd_serviced_now;
|
||
|
||
// CPU priority remains absolute. DMAC fires when CPU isn't
|
||
// hitting RAM AND there's a request to service (either fresh
|
||
// this cycle or buffered from a prior contended cycle).
|
||
assign dmac_rd_serviced_now = !cpu_rd_hit_ram &&
|
||
(dmac_rd_buf_q || dmac_rd_hit_ram);
|
||
|
||
assign ram_rd_en = cpu_rd_hit_ram || dmac_rd_serviced_now;
|
||
assign ram_rd_addr = cpu_rd_hit_ram ? ee_rd_ram_offset
|
||
: dmac_rd_buf_q ? dmac_rd_buf_addr_q
|
||
: dmac_ram_offset;
|
||
|
||
always_ff @(posedge clk) begin
|
||
if (!rst_n) begin
|
||
dmac_rd_buf_q <= 1'b0;
|
||
dmac_rd_buf_addr_q <= '0;
|
||
end else begin
|
||
// Set buffer on a fresh contention cycle (DMAC issued a
|
||
// request that lost to the CPU). Only latch when the
|
||
// buffer is empty — the DMAC won't issue a new request
|
||
// while one is outstanding (it waits in S_FETCH_WAIT),
|
||
// so we never need to enqueue more than one.
|
||
if (!dmac_rd_buf_q && cpu_rd_hit_ram && dmac_rd_hit_ram) begin
|
||
dmac_rd_buf_q <= 1'b1;
|
||
dmac_rd_buf_addr_q <= dmac_ram_offset;
|
||
end
|
||
// Clear buffer the cycle the buffered request actually
|
||
// gets the bus.
|
||
else if (dmac_rd_buf_q && dmac_rd_serviced_now) begin
|
||
dmac_rd_buf_q <= 1'b0;
|
||
end
|
||
end
|
||
end
|
||
|
||
// ------------------------------------------------------------------
|
||
// Shared 128-bit RAM write port. CPU wins over bridge on collision.
|
||
// CPU 32-bit data expands to a 128-bit lane; ram_wr_be masks so
|
||
// only the four bytes of that lane are enabled.
|
||
// ------------------------------------------------------------------
|
||
|
||
logic cpu_wr_hit_ram;
|
||
logic bridge_wr_hit_ram;
|
||
assign cpu_wr_hit_ram = ee_wr_en && ee_wr_is_ram;
|
||
assign bridge_wr_hit_ram = bridge_wr_en && bridge_is_ram;
|
||
|
||
// Ch64 useg-mirror hit: the CPU write is targeting a useg address
|
||
// whose phys falls in the parameterized window. When enabled, the
|
||
// same data also lands in ee_ram (lane-expanded below). Disjoint
|
||
// from cpu_wr_hit_ram because ee_wr_is_useg and ee_wr_is_ram are
|
||
// mutually exclusive by construction.
|
||
//
|
||
// Ch70 unified alias: the same write also mirrors into ee_ram if
|
||
// CPU_RAM_ALIAS_EN is set and the phys is in [CPU_RAM_ALIAS_LO,
|
||
// CPU_RAM_ALIAS_HI). This subsumes the Ch64 narrow knob when
|
||
// enabled.
|
||
logic cpu_wr_useg_mirror_hit;
|
||
logic cpu_wr_useg_alias_hit;
|
||
assign cpu_wr_useg_alias_hit =
|
||
CPU_RAM_ALIAS_EN && ee_wr_en && ee_wr_is_useg_shadow &&
|
||
(ee_wr_phys >= CPU_RAM_ALIAS_LO) &&
|
||
(ee_wr_phys < CPU_RAM_ALIAS_HI);
|
||
assign cpu_wr_useg_mirror_hit =
|
||
cpu_wr_useg_alias_hit ||
|
||
(CPU_USEG_TO_RAM_MIRROR_EN && ee_wr_en && ee_wr_is_useg_shadow &&
|
||
(ee_wr_phys >= CPU_USEG_TO_RAM_MIRROR_LO) &&
|
||
(ee_wr_phys < CPU_USEG_TO_RAM_MIRROR_HI));
|
||
|
||
logic cpu_wr_to_ram_any;
|
||
assign cpu_wr_to_ram_any = cpu_wr_hit_ram || cpu_wr_useg_mirror_hit;
|
||
|
||
logic [1:0] cpu_wr_lane;
|
||
logic [127:0] cpu_wr_data_exp;
|
||
logic [15:0] cpu_wr_be_exp;
|
||
assign cpu_wr_lane = ee_wr_addr[3:2];
|
||
always_comb begin
|
||
cpu_wr_data_exp = 128'd0;
|
||
cpu_wr_be_exp = 16'd0;
|
||
case (cpu_wr_lane)
|
||
2'd0: begin
|
||
cpu_wr_data_exp[31:0] = ee_wr_data;
|
||
cpu_wr_be_exp[3:0] = ee_wr_be;
|
||
end
|
||
2'd1: begin
|
||
cpu_wr_data_exp[63:32] = ee_wr_data;
|
||
cpu_wr_be_exp[7:4] = ee_wr_be;
|
||
end
|
||
2'd2: begin
|
||
cpu_wr_data_exp[95:64] = ee_wr_data;
|
||
cpu_wr_be_exp[11:8] = ee_wr_be;
|
||
end
|
||
2'd3: begin
|
||
cpu_wr_data_exp[127:96] = ee_wr_data;
|
||
cpu_wr_be_exp[15:12] = ee_wr_be;
|
||
end
|
||
endcase
|
||
end
|
||
|
||
assign ram_wr_en = cpu_wr_to_ram_any || bridge_wr_hit_ram;
|
||
// cpu_wr_hit_ram and cpu_wr_useg_mirror_hit are mutually
|
||
// exclusive; ee_wr_phys[24:0] is the same extraction as
|
||
// ee_wr_ram_offset, so one address expression covers both CPU
|
||
// cases.
|
||
assign ram_wr_addr = cpu_wr_to_ram_any ? ee_wr_phys[24:0] : bridge_ram_offset;
|
||
assign ram_wr_data = cpu_wr_to_ram_any ? cpu_wr_data_exp : bridge_wr_data;
|
||
assign ram_wr_be = cpu_wr_to_ram_any ? cpu_wr_be_exp : bridge_wr_be;
|
||
assign ram_master_id = cpu_wr_to_ram_any ? 8'd0 : bridge_master_id;
|
||
|
||
// ------------------------------------------------------------------
|
||
// EE DMAC ch2 register write port (chapter 3, write-only)
|
||
// ------------------------------------------------------------------
|
||
|
||
assign ee_dmac_ch2_wr_en = ee_wr_en && ee_wr_is_dmac_ch2;
|
||
assign ee_dmac_ch2_wr_addr = ee_wr_phys[7:0];
|
||
assign ee_dmac_ch2_wr_data = ee_wr_data;
|
||
|
||
assign ee_dmac_ch2_rd_en = ee_rd_en && ee_rd_is_dmac_ch2;
|
||
assign ee_dmac_ch2_rd_addr = ee_rd_phys[7:0];
|
||
|
||
assign ee_intc_wr_en = ee_wr_en && ee_wr_is_intc;
|
||
assign ee_intc_wr_addr = ee_wr_phys[7:0];
|
||
assign ee_intc_wr_data = ee_wr_data;
|
||
|
||
assign ee_intc_rd_en = ee_rd_en && ee_rd_is_intc;
|
||
assign ee_intc_rd_addr = ee_rd_phys[7:0];
|
||
|
||
// ------------------------------------------------------------------
|
||
// Ch287 — EE DMAC global control/status stub, instantiated
|
||
// INTERNALLY so existing TBs don't need to route new ports.
|
||
// Surface: D_CTRL/D_STAT/D_PCR/D_SQWC/D_RBSR/D_RBOR in the
|
||
// 0x1000_E000-0x1000_E0FF window (broader 4 KiB window decoded by
|
||
// EE_DMAC_CTRL_BASE[28:12] match; the live registers occupy the
|
||
// first 256 bytes via reg_offset = ee_*_phys[7:0]).
|
||
// ------------------------------------------------------------------
|
||
logic ee_dmac_ctrl_wr_en;
|
||
logic [7:0] ee_dmac_ctrl_wr_addr;
|
||
logic [31:0] ee_dmac_ctrl_wr_data;
|
||
logic ee_dmac_ctrl_rd_en;
|
||
logic [7:0] ee_dmac_ctrl_rd_addr;
|
||
logic [31:0] ee_dmac_ctrl_rd_data;
|
||
logic ee_dmac_ctrl_rd_valid;
|
||
// Trace from the inner stub is currently unwired (the outer
|
||
// map already emits one trace event per CPU access via the
|
||
// EV_READ/EV_WRITE arms below; merging two trace sources here
|
||
// would require a mux that doesn't exist yet). Future chapters
|
||
// that need DMAC-level retire detail can plumb these into
|
||
// trace_sink_stub directly from the TB hierarchy.
|
||
logic ee_dmac_ctrl_ev_valid;
|
||
trace_pkg::subsys_e ee_dmac_ctrl_ev_subsys;
|
||
trace_pkg::event_e ee_dmac_ctrl_ev_event;
|
||
logic [63:0] ee_dmac_ctrl_ev_arg0;
|
||
logic [63:0] ee_dmac_ctrl_ev_arg1;
|
||
logic [63:0] ee_dmac_ctrl_ev_arg2;
|
||
logic [63:0] ee_dmac_ctrl_ev_arg3;
|
||
logic [31:0] ee_dmac_ctrl_ev_flags;
|
||
|
||
assign ee_dmac_ctrl_wr_en = ee_wr_en && ee_wr_is_dmac_ctrl;
|
||
assign ee_dmac_ctrl_wr_addr = ee_wr_phys[7:0];
|
||
assign ee_dmac_ctrl_wr_data = ee_wr_data;
|
||
assign ee_dmac_ctrl_rd_en = ee_rd_en && ee_rd_is_dmac_ctrl;
|
||
assign ee_dmac_ctrl_rd_addr = ee_rd_phys[7:0];
|
||
|
||
ee_dmac_ctrl_stub u_dmac_ctrl (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.reg_wr_en(ee_dmac_ctrl_wr_en),
|
||
.reg_offset(ee_dmac_ctrl_wr_en ? ee_dmac_ctrl_wr_addr
|
||
: ee_dmac_ctrl_rd_addr),
|
||
.reg_wr_data(ee_dmac_ctrl_wr_data),
|
||
.reg_rd_en(ee_dmac_ctrl_rd_en),
|
||
.reg_rd_data(ee_dmac_ctrl_rd_data),
|
||
.reg_rd_valid(ee_dmac_ctrl_rd_valid),
|
||
.ev_valid(ee_dmac_ctrl_ev_valid),
|
||
.ev_subsys(ee_dmac_ctrl_ev_subsys),
|
||
.ev_event(ee_dmac_ctrl_ev_event),
|
||
.ev_arg0(ee_dmac_ctrl_ev_arg0),
|
||
.ev_arg1(ee_dmac_ctrl_ev_arg1),
|
||
.ev_arg2(ee_dmac_ctrl_ev_arg2),
|
||
.ev_arg3(ee_dmac_ctrl_ev_arg3),
|
||
.ev_flags(ee_dmac_ctrl_ev_flags)
|
||
);
|
||
|
||
// ------------------------------------------------------------------
|
||
// Ch288 — Passive per-channel surface (ch0/1/3/4/5). Hosts
|
||
// CHCR/MADR/QWC/TADR per channel; latched, no FSM, no D_STAT
|
||
// side effects. Same internal-instance pattern as Ch287.
|
||
// ------------------------------------------------------------------
|
||
logic ee_dmac_passive_wr_en;
|
||
logic [15:0] ee_dmac_passive_wr_addr;
|
||
logic [31:0] ee_dmac_passive_wr_data;
|
||
logic ee_dmac_passive_rd_en;
|
||
logic [15:0] ee_dmac_passive_rd_addr;
|
||
logic [31:0] ee_dmac_passive_rd_data;
|
||
logic ee_dmac_passive_rd_valid;
|
||
logic ee_dmac_passive_ev_valid;
|
||
trace_pkg::subsys_e ee_dmac_passive_ev_subsys;
|
||
trace_pkg::event_e ee_dmac_passive_ev_event;
|
||
logic [63:0] ee_dmac_passive_ev_arg0;
|
||
logic [63:0] ee_dmac_passive_ev_arg1;
|
||
logic [63:0] ee_dmac_passive_ev_arg2;
|
||
logic [63:0] ee_dmac_passive_ev_arg3;
|
||
logic [31:0] ee_dmac_passive_ev_flags;
|
||
|
||
assign ee_dmac_passive_wr_en = ee_wr_en && ee_wr_is_dmac_passive;
|
||
assign ee_dmac_passive_wr_addr = ee_wr_phys[15:0];
|
||
assign ee_dmac_passive_wr_data = ee_wr_data;
|
||
assign ee_dmac_passive_rd_en = ee_rd_en && ee_rd_is_dmac_passive;
|
||
assign ee_dmac_passive_rd_addr = ee_rd_phys[15:0];
|
||
|
||
ee_dmac_passive_chan_stub u_dmac_passive (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.reg_wr_en(ee_dmac_passive_wr_en),
|
||
.chan_addr(ee_dmac_passive_wr_en ? ee_dmac_passive_wr_addr
|
||
: ee_dmac_passive_rd_addr),
|
||
.reg_wr_data(ee_dmac_passive_wr_data),
|
||
.reg_rd_en(ee_dmac_passive_rd_en),
|
||
.reg_rd_data(ee_dmac_passive_rd_data),
|
||
.reg_rd_valid(ee_dmac_passive_rd_valid),
|
||
.ev_valid(ee_dmac_passive_ev_valid),
|
||
.ev_subsys(ee_dmac_passive_ev_subsys),
|
||
.ev_event(ee_dmac_passive_ev_event),
|
||
.ev_arg0(ee_dmac_passive_ev_arg0),
|
||
.ev_arg1(ee_dmac_passive_ev_arg1),
|
||
.ev_arg2(ee_dmac_passive_ev_arg2),
|
||
.ev_arg3(ee_dmac_passive_ev_arg3),
|
||
.ev_flags(ee_dmac_passive_ev_flags)
|
||
);
|
||
|
||
assign ee_misc_mmio_wr_en = ee_wr_en && ee_wr_is_misc_mmio;
|
||
assign ee_misc_mmio_wr_addr = ee_wr_phys[15:0];
|
||
assign ee_misc_mmio_wr_data = ee_wr_data;
|
||
assign ee_misc_mmio_wr_be = ee_wr_be;
|
||
|
||
// Ch112 — GS privileged-MMIO write routing.
|
||
assign ee_gs_priv_wr_en = ee_wr_en && ee_wr_is_gs_priv;
|
||
assign ee_gs_priv_wr_addr = ee_wr_phys[15:0];
|
||
assign ee_gs_priv_wr_data = ee_wr_data;
|
||
assign ee_gs_priv_wr_be = ee_wr_be;
|
||
|
||
assign ee_misc_mmio_rd_en = ee_rd_en && ee_rd_is_misc_mmio;
|
||
assign ee_misc_mmio_rd_addr = ee_rd_phys[15:0];
|
||
|
||
assign ee_biu_wr_en = ee_wr_en && ee_wr_is_biu;
|
||
assign ee_biu_wr_addr = ee_wr_phys[11:0];
|
||
assign ee_biu_wr_data = ee_wr_data;
|
||
assign ee_biu_wr_be = ee_wr_be;
|
||
|
||
assign ee_biu_rd_en = ee_rd_en && ee_rd_is_biu;
|
||
assign ee_biu_rd_addr = ee_rd_phys[11:0];
|
||
|
||
// ------------------------------------------------------------------
|
||
// EE CPU read response pipeline (one-cycle latency, matches the rest
|
||
// of the stub ecosystem). Latch which region answered plus the lane
|
||
// index for RAM reads.
|
||
// ------------------------------------------------------------------
|
||
|
||
logic ee_rd_pending;
|
||
logic ee_rd_was_bios;
|
||
logic ee_rd_was_ram;
|
||
logic ee_rd_was_dmac_ch2;
|
||
logic ee_rd_was_dmac_ctrl; // Ch287
|
||
logic ee_rd_was_dmac_passive; // Ch288
|
||
logic ee_rd_was_intc;
|
||
logic ee_rd_was_misc_mmio;
|
||
logic ee_rd_was_biu;
|
||
logic ee_rd_was_useg_shadow;
|
||
logic [1:0] ee_rd_ram_lane;
|
||
|
||
always_ff @(posedge clk) begin
|
||
if (!rst_n) begin
|
||
ee_rd_pending <= 1'b0;
|
||
ee_rd_was_bios <= 1'b0;
|
||
ee_rd_was_ram <= 1'b0;
|
||
ee_rd_was_dmac_ch2 <= 1'b0;
|
||
ee_rd_was_dmac_ctrl <= 1'b0;
|
||
ee_rd_was_dmac_passive <= 1'b0;
|
||
ee_rd_was_intc <= 1'b0;
|
||
ee_rd_was_misc_mmio <= 1'b0;
|
||
ee_rd_was_biu <= 1'b0;
|
||
ee_rd_was_useg_shadow <= 1'b0;
|
||
ee_rd_ram_lane <= 2'd0;
|
||
end else begin
|
||
ee_rd_pending <= ee_rd_en;
|
||
if (ee_rd_en) begin
|
||
ee_rd_was_bios <= ee_rd_is_bios;
|
||
ee_rd_was_ram <= ee_rd_is_ram;
|
||
ee_rd_was_dmac_ch2 <= ee_rd_is_dmac_ch2;
|
||
ee_rd_was_dmac_ctrl <= ee_rd_is_dmac_ctrl; // Ch287
|
||
ee_rd_was_dmac_passive <= ee_rd_is_dmac_passive; // Ch288
|
||
ee_rd_was_intc <= ee_rd_is_intc;
|
||
ee_rd_was_misc_mmio <= ee_rd_is_misc_mmio;
|
||
ee_rd_was_biu <= ee_rd_is_biu;
|
||
ee_rd_was_useg_shadow <= ee_rd_is_useg_shadow;
|
||
ee_rd_ram_lane <= ee_rd_addr[3:2];
|
||
end
|
||
end
|
||
end
|
||
|
||
logic [31:0] ee_rd_ram_slice;
|
||
always_comb begin
|
||
case (ee_rd_ram_lane)
|
||
2'd0: ee_rd_ram_slice = ram_rd_data[31:0];
|
||
2'd1: ee_rd_ram_slice = ram_rd_data[63:32];
|
||
2'd2: ee_rd_ram_slice = ram_rd_data[95:64];
|
||
2'd3: ee_rd_ram_slice = ram_rd_data[127:96];
|
||
default: ee_rd_ram_slice = 32'd0;
|
||
endcase
|
||
end
|
||
|
||
assign ee_rd_valid = ee_rd_pending;
|
||
assign ee_rd_data = ee_rd_was_bios ? bios_rd_data
|
||
: ee_rd_was_ram ? ee_rd_ram_slice
|
||
: ee_rd_was_useg_shadow ? useg_shadow_rd_data
|
||
: ee_rd_was_dmac_ch2 ? ee_dmac_ch2_rd_data
|
||
: ee_rd_was_dmac_ctrl ? ee_dmac_ctrl_rd_data // Ch287
|
||
: ee_rd_was_dmac_passive ? ee_dmac_passive_rd_data // Ch288
|
||
: ee_rd_was_intc ? ee_intc_rd_data
|
||
: ee_rd_was_misc_mmio ? ee_misc_mmio_rd_data
|
||
: ee_rd_was_biu ? ee_biu_rd_data
|
||
: 32'hDEADBEEF;
|
||
|
||
// ------------------------------------------------------------------
|
||
// DMAC read response pipeline (128-bit). Ch115 — `dmac_rd_pending`
|
||
// now sets ONLY when the DMAC's read actually hits the RAM bus
|
||
// this cycle (`dmac_rd_serviced_now`), so a contended-out request
|
||
// doesn't return false data with the CPU's contents (the
|
||
// pre-Ch115 corruption bug). For non-RAM dmac_rd_en hits (other
|
||
// dmac_is_* targets), the existing behavior is preserved.
|
||
// ------------------------------------------------------------------
|
||
|
||
logic dmac_rd_pending;
|
||
logic dmac_rd_was_ram;
|
||
logic dmac_rd_actually_serviced;
|
||
|
||
// The DMAC's pending response fires when:
|
||
// (a) it actually got the RAM bus this cycle (RAM target), OR
|
||
// (b) its request hit a non-RAM target (dmac_rd_en && !dmac_is_ram —
|
||
// no contention possible there).
|
||
// Otherwise it stays in S_FETCH_WAIT, waiting for the buffered
|
||
// replay (RAM case) or the original request (non-RAM case).
|
||
assign dmac_rd_actually_serviced =
|
||
dmac_rd_serviced_now ||
|
||
(dmac_rd_en && !dmac_is_ram);
|
||
|
||
always_ff @(posedge clk) begin
|
||
if (!rst_n) begin
|
||
dmac_rd_pending <= 1'b0;
|
||
dmac_rd_was_ram <= 1'b0;
|
||
end else begin
|
||
dmac_rd_pending <= dmac_rd_actually_serviced;
|
||
if (dmac_rd_actually_serviced)
|
||
dmac_rd_was_ram <= dmac_rd_serviced_now;
|
||
end
|
||
end
|
||
|
||
assign dmac_rd_valid = dmac_rd_pending;
|
||
assign dmac_rd_data = dmac_rd_was_ram
|
||
? ram_rd_data
|
||
: 128'hDEAD_BEEF_DEAD_BEEF_DEAD_BEEF_DEAD_BEEF;
|
||
|
||
// ------------------------------------------------------------------
|
||
// Trace emission — one event per cycle, priority:
|
||
// EE read > EE write > DMAC read
|
||
// Two paths are unlikely to be active simultaneously in Wave 2.7
|
||
// testbenches (each TB exercises a single master); priority here is
|
||
// defensive.
|
||
// ------------------------------------------------------------------
|
||
|
||
always_ff @(posedge clk) begin
|
||
if (!rst_n) begin
|
||
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 if (ee_rd_en) begin
|
||
ev_valid <= 1'b1;
|
||
ev_subsys <= SUBSYS_MEM;
|
||
if (ee_rd_is_bios) begin
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_BIOS;
|
||
end else if (ee_rd_is_ram) begin
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_EE_RAM;
|
||
end else if (ee_rd_is_dmac_ch2) begin
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_EE_DMAC;
|
||
end else if (ee_rd_is_dmac_ctrl) begin // Ch287
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_EE_DMAC_CTRL;
|
||
end else if (ee_rd_is_dmac_passive) begin // Ch288
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_EE_DMAC_PASSIVE;
|
||
end else if (ee_rd_is_intc) begin
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_EE_INTC;
|
||
end else if (ee_rd_is_misc_mmio) begin
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_EE_MISC_MMIO;
|
||
end else if (ee_rd_is_biu) begin
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_EE_BIU;
|
||
end else if (ee_rd_is_useg_shadow) begin
|
||
// Ch34: useg-shadow hits get their own region tag so
|
||
// post-run analysis can distinguish them from kseg0
|
||
// RAM hits. Pre-ch33 code conflated the two via the
|
||
// phys=addr[28:0] strip; the shadow is now a separate
|
||
// 4 MiB backing.
|
||
ev_event <= EV_READ;
|
||
ev_arg1 <= 64'd0;
|
||
ev_arg3 <= REGION_USEG_SHADOW;
|
||
end else begin
|
||
ev_event <= EV_UNMAPPED;
|
||
ev_arg1 <= 64'hDEADBEEF;
|
||
ev_arg3 <= REGION_UNMAPPED;
|
||
end
|
||
ev_arg0 <= {32'd0, ee_rd_addr};
|
||
ev_arg2 <= MASTER_EE_IFETCH;
|
||
ev_flags <= 32'd0;
|
||
end else if (ee_wr_en) begin
|
||
ev_valid <= 1'b1;
|
||
ev_subsys <= SUBSYS_MEM;
|
||
if (ee_wr_is_ram) begin
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_RAM;
|
||
end else if (ee_wr_is_dmac_ch2) begin
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_DMAC;
|
||
end else if (ee_wr_is_dmac_ctrl) begin // Ch287
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_DMAC_CTRL;
|
||
end else if (ee_wr_is_dmac_passive) begin // Ch288
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_DMAC_PASSIVE;
|
||
end else if (ee_wr_is_intc) begin
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_INTC;
|
||
end else if (ee_wr_is_misc_mmio) begin
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_MISC_MMIO;
|
||
end else if (ee_wr_is_biu) begin
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_BIU;
|
||
end else if (ee_wr_is_gs_priv) begin
|
||
// Ch112: GS-privileged window (0x1200_xxxx) routed
|
||
// to ee_gs_priv_bridge_stub. Without this branch a
|
||
// valid 0x1200_xxxx write would surface as
|
||
// EV_UNMAPPED at the trace.
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_EE_GS_PRIV;
|
||
end else if (ee_wr_is_useg_shadow) begin
|
||
// Ch34: dedicated useg-shadow tag (see read-side note).
|
||
ev_event <= EV_WRITE;
|
||
ev_arg3 <= REGION_USEG_SHADOW;
|
||
end else begin
|
||
ev_event <= EV_UNMAPPED;
|
||
ev_arg3 <= REGION_UNMAPPED;
|
||
end
|
||
ev_arg0 <= {32'd0, ee_wr_addr};
|
||
ev_arg1 <= {32'd0, ee_wr_data};
|
||
ev_arg2 <= MASTER_EE_IFETCH;
|
||
ev_flags <= 32'h0000_0001;
|
||
end else if (dmac_rd_en) begin
|
||
ev_valid <= 1'b1;
|
||
ev_subsys <= SUBSYS_MEM;
|
||
ev_event <= dmac_is_ram ? EV_READ : EV_UNMAPPED;
|
||
ev_arg0 <= {32'd0, dmac_rd_addr};
|
||
ev_arg1 <= dmac_is_ram ? 64'd0 : 64'hDEADBEEF;
|
||
ev_arg2 <= MASTER_DMAC;
|
||
ev_arg3 <= dmac_is_ram ? REGION_EE_RAM : REGION_UNMAPPED;
|
||
ev_flags <= 32'd0;
|
||
end else if (bridge_wr_en) begin
|
||
ev_valid <= 1'b1;
|
||
ev_subsys <= SUBSYS_MEM;
|
||
ev_event <= bridge_is_ram ? EV_WRITE : EV_UNMAPPED;
|
||
ev_arg0 <= {32'd0, bridge_wr_addr};
|
||
ev_arg1 <= bridge_wr_data[63:0];
|
||
ev_arg2 <= {56'd0, bridge_master_id};
|
||
ev_arg3 <= bridge_is_ram ? REGION_EE_RAM : REGION_UNMAPPED;
|
||
ev_flags <= 32'h0000_0001;
|
||
end else begin
|
||
ev_valid <= 1'b0;
|
||
end
|
||
end
|
||
|
||
endmodule : ee_memory_map_stub
|