# Wave 2.5 Mini-Plan: Memory-Backed DMAC Payload This document defines the consolidation step between Wave 2's `programmable BGCOLOR via DMA/GIF` proof and later expansion into wider DMAC, GIF, and EE-side behavior. Goal: - retire the biggest remaining Wave 2 shortcut, - make `MADR` real instead of trace-only, - keep the current Milestone A+ proof intact, - improve ownership boundaries before expanding into SIF/IOP or wider GIF work. Working milestone name: `memory-backed BGCOLOR via DMA/GIF` That means: - DMAC channel 2 is programmed with a real source address, - DMAC fetches payload from an addressable memory block, - GIF receives the fetched payload, - GS updates `BGCOLOR`, - platform video reflects the new color, - traces show the fetch path as well as the transfer path. ## Why this goes before SIF/IOP The current Wave 2 path is structurally good but still has one major artificial seam: - the testbench injects payload directly into DMAC. Before opening the EE↔IOP front, the design benefits more from tightening that EE-side ownership seam than from starting a second subsystem family. This step: - makes `MADR` meaningful, - introduces a real read-master relationship, - prepares the ground for multi-beat transfers, - keeps the work inside the already-active DMAC/GIF/GS lane. ## Deliverables The first Wave 2.5 pass should land: 1. `rtl/memory/ee_ram_stub.sv` 2. an updated `rtl/dmac/dmac_reg_stub.sv` with a memory-read master port 3. an updated `sim/tb/integration/tb_bgcolor_via_dma.sv` 4. any trace-schema refinements needed for DMAC fetch visibility 5. `Makefile` / `sim/README.md` updates if the run flow changes ## Ownership decision: memory source shape Recommendation: - add a new `rtl/memory/ee_ram_stub.sv` Do not: - extend `bios_rom_stub` into a read-write block, - add a DMAC-private payload RAM that lives inside `rtl/dmac/`. ### Why `ee_ram_stub.sv` This is the cleanest ownership boundary for future growth: - memory remains owned by the memory subsystem, - DMAC becomes a memory client, not a memory owner, - `ee_memory_map_stub` can grow toward multiple mapped regions without refactoring a DMAC-private storage hack back out later. It also tells the right architectural story: - BIOS is ROM, - EE RAM is RAM, - DMAC reads from memory through an explicit master interface. ## `ee_ram_stub.sv` exact scope Status target: - tiny, addressable, read-first memory block for DMAC-backed tests ### Owns in this phase - a small read/write memory array, - byte-addressed external interface, - one-cycle read latency, - optional simple write port for testbench preload, - trace events for read and write activity if useful. ### Explicit non-goals - full 32 MiB EE RAM sizing, - cache behavior, - arbitration among multiple masters, - full integration into the EE-visible memory map, - timing fidelity beyond a simple deterministic latency. ### Recommended size Use something small but qword-friendly: - default `SIZE_BYTES = 4 KiB` or `16 KiB` That is large enough for: - multiple DMAC packets, - future directed tests, - no simulator pain. ### Recommended interface Keep it simple and aligned with the current stub ecosystem. Suggested external interface: - read request: - `rd_en` - `rd_addr` - `rd_data` - `rd_valid` - write request: - `wr_en` - `wr_addr` - `wr_data` - `wr_be` Recommended data width: - `128-bit` data path for read and write Reason: - aligns with current DMAC qword semantics, - avoids extra packing/unpacking for the first memory-backed DMA proof, - keeps the first step focused on ownership, not bus-width adaptation. Addressing: - qword-aligned externally - low address bits ignored as needed ### Preload mechanism For the first implementation, allow either: - testbench writes through the normal write port, or - optional `$readmemh` preload file parameter Recommendation: - use the normal write port in the integration testbench first Why: - makes the preload path explicit and testable, - avoids adding file-format work unless it becomes useful later. ## DMAC fetch interface The direct payload input should be retired from the integrated proof path. Recommended new DMAC-side interface: - `mem_rd_en` - `mem_rd_addr` - `mem_rd_data` - `mem_rd_valid` That is enough for the first qword-fetch path. ### Ownership and routing For Wave 2.5: - connect `dmac_reg_stub` directly to `ee_ram_stub` Do not route the fetch through `ee_memory_map_stub` yet. Reason: - `ee_memory_map_stub` currently only decodes BIOS and unmapped space, - forcing DMAC through it now would either require a larger memory-map rewrite or add a fake bypass anyway, - direct connection still preserves the key ownership boundary: DMAC is a memory client and RAM is a memory block. This should be documented as a temporary topology, not the final architecture. ## `MADR` behavior in Wave 2.5 `MADR` stops being "recorded but ignored" and becomes the actual qword fetch source address. Recommended behavior: - on `DMA_START`, latch `MADR` - issue one or more qword reads starting at that address - increment by `16` bytes per beat Trace consequence: - DMAC trace should show the fetch source address clearly - memory trace should show the corresponding RAM read(s) ## QWC scope Recommendation: - support `QWC == 1` in the first Wave 2.5 implementation - make the internal design compatible with `QWC > 1` - do not require multi-beat support for initial signoff Reason: - the point of 2.5 is memory-backed ownership, not throughput expansion - `QWC > 1` becomes more valuable once the fetch path is stable Suggested follow-up: - call `QWC > 1` a `Wave 2.6` or `Wave 3a` extension unless it falls out naturally with low risk ## Trace schema additions / refinements Wave 2 already added: - `EV_DMA_CFG` - `EV_DMA_START` - `EV_DMA_BEAT` - `EV_DMA_DONE` - `EV_GIFTAG` - `EV_GS_WRITE` Wave 2.5 does not require new event names if the payloads are refined well. Recommended refinement: ### `DMAC EV_DMA_START` - `arg0 = channel` - `arg1 = qwc` - `arg2 = MADR` - `arg3 = path id` This is more useful now that `MADR` matters. ### `DMAC EV_DMA_BEAT` - `arg0 = channel` - `arg1 = beat index` - `arg2 = source address for this beat` - `arg3 = remaining count` ### `MEM READ` from `ee_ram_stub` Reuse existing `MEM READ` event shape: - `arg0 = address` - `arg1 = low data summary or full qword-low summary` - `arg2 = master id` - `arg3 = region id` Suggested ids for this phase: - master id: `1 = DMAC` - region id: `1 = EE_RAM` This lets traces show the DMAC→RAM→GIF ownership chain without inventing a new event family. ## `dmac_reg_stub` internal changes Recommended state flow: - `IDLE` - `FETCH_WAIT` - `ACTIVE_SEND` - `DONE` Suggested behavior: 1. CPU/testbench writes `MADR`, `QWC`, `CHCR` 2. `DMA_START` 3. issue memory read at `MADR + beat_index * 16` 4. wait for `mem_rd_valid` 5. present fetched qword to GIF 6. on accept, increment beat count 7. if beats remain, fetch next qword 8. otherwise `DMA_DONE` ### Guardrail Do not keep both the direct payload port and the memory-fetch path active in the integrated milestone as equal options. If a compatibility/debug path is retained temporarily, it must be: - clearly labeled as deprecated, - unused by the main integration testbench. ## Integration testbench migration `tb_bgcolor_via_dma.sv` should stop driving the direct payload port and instead: 1. reset the chain 2. preload one qword into `ee_ram_stub` through its write port 3. program `MADR` to that location 4. program `QWC = 1` 5. trigger `CHCR.start` 6. wait for `DMA_DONE` 7. verify the same visible color-change outcome as before ### Payload preload mechanism Recommended first mechanism: - direct writes into `ee_ram_stub` through its write port from the testbench This keeps the setup explicit and simple. ## Integrated testbench pass criteria Keep the current Wave 2 pass criteria stable, with the following additions: - at least one `MEM READ` from `ee_ram_stub` attributable to DMAC - `DMA_START` trace includes a meaningful `MADR` - `DMA_BEAT` source-address trace lines match the programmed `MADR` Suggested summary line: ```text [tb_bgcolor_via_dma] mem_reads=1 dma_start=1 dma_done=1 giftag=1 gs_bgcolor=1 bg=(ff,00,00) errors=0 ``` ## Recommended implementation order 1. add `ee_ram_stub.sv` 2. update `dmac_reg_stub.sv` to fetch from memory 3. update `tb_bgcolor_via_dma.sv` to preload RAM and drive `MADR` 4. adjust trace payload details if needed 5. wire docs / Makefile updates ## Guardrails - Do not route DMAC through `ee_memory_map_stub` yet unless Claude wants to deliberately broaden scope. - Do not broaden to `QWC > 1` unless it falls out naturally. - Do not let the preload mechanism become a hidden debug-only side channel. - Do not erase the existing Wave 2 trace visibility while refactoring the fetch path. ## Exit criteria for mini-plan acceptance This mini-plan is accepted when Claude can implement: 1. a new `ee_ram_stub.sv`, 2. a memory-master version of `dmac_reg_stub`, 3. an updated `tb_bgcolor_via_dma.sv` that preloads RAM rather than driving the direct payload port, 4. while preserving the visible Milestone A+ outcome and adding trace-visible proof that `MADR` is the actual payload source.