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>
9.1 KiB
Wave 2.6 Mini-Plan: Multi-Beat DMAC to GIF to GS
This document defines the next consolidation step after the completed
Wave 2.5 memory-backed BGCOLOR via DMA/GIF milestone.
Goal:
- prove the DMAC/GIF path across more than one qword,
- validate address stepping from
MADR, - validate end-of-packet signaling on the final beat only,
- preserve the visible Milestone A+ outcome through the existing GS/platform chain,
- do all of that without expanding packet-format scope prematurely.
Working milestone name:
multi-beat BGCOLOR via DMA/GIF
That means:
- DMAC channel 2 is programmed with
QWC = 2, - DMAC performs two memory-backed qword fetches,
- GIF accepts two qwords as two standalone register-write packets,
- GS observes two consecutive writes,
- platform video reflects the final written color,
- traces prove beat ordering, source-address stepping, and
gif_tag_lastbehavior.
Why this goes before memory-map routing
Wave 2.5 established the right ownership seam:
- DMAC is now a memory client,
MADRis real,- RAM is owned by the memory subsystem,
- the graphics-visible path is intact.
The next most valuable risk to retire is not topology, it is transfer shape.
Multi-beat transfer support is the first place where subtle bugs are likely to hide:
- off-by-one address stepping,
- incorrect remaining-count bookkeeping,
gif_tag_lastasserted too early or too late,- state-machine stalls between fetch and send,
- final-color behavior when multiple writes land back-to-back.
Once that is stable, routing the same traffic through ee_memory_map_stub
becomes a narrower structural refactor instead of a behavioral and structural
change combined.
Deliverables
The first Wave 2.6 pass should land:
- an updated
rtl/dmac/dmac_reg_stub.sv - a small comment/README update in
rtl/gif_gs/gif_path_stub.svif needed to make multi-beat behavior explicit - an updated
sim/tb/integration/tb_bgcolor_via_dma.sv sim/Makefileupdates only if the run flow changes- optional README note if the integration-TB expectations materially change
No new subsystem contracts or decision records are required for this step.
Scope boundary
This plan is intentionally narrow.
It does not attempt to implement:
- real GIFtag decode,
- packed register lists,
- chain mode,
- linked-list DMA,
- path arbitration,
- full EE memory-map routing,
- any IOP or SIF behavior,
- GS drawing primitives or VRAM.
The purpose is to prove:
QWC > 1 works correctly on the already-established temporary topology.
Transfer length scope
Recommendation:
- sign off this phase on
QWC = 2
Do not require QWC = 4 for first signoff.
Why two qwords is enough
Two beats cover every new behavior category this phase is meant to validate:
- beat 0 source address =
MADR - beat 1 source address =
MADR + 16 - beat 0 has
gif_tag_last = 0 - beat 1 has
gif_tag_last = 1 - the transfer must remain active across an intermediate beat
- the final beat must retire cleanly into
DMA_DONE
Four beats would add more distance but not a new category of behavior.
If the implementation naturally supports QWC > 2, that is welcome, but the
required directed proof for this phase should stay at 2.
Payload semantics
Recommendation:
- keep the current project-local packet model:
- one qword = one standalone GS register write
- use the same destination register twice:
BGCOLORon beat 0BGCOLORagain on beat 1 with a different RGB value
This is the simplest high-signal option.
Why this goes over the alternatives
Using one register twice keeps the focus on transport, not packet-model growth.
It gives us:
- two visible GS-side events,
- two visible GIF-side accepts,
- a deterministic final platform-visible color,
- no need to invent a tag-qword/data-qword pairing before we are ready to tackle real GIFtag structure.
Using two different GS registers would blur the phase boundary by making the test partly about GS register-surface breadth. That coverage already exists in the single-register-path and can expand later when GIFtag work begins.
Recommended concrete payload
Preload two qwords at consecutive addresses:
- beat 0 packet:
- register =
BGCOLOR - value = a clearly non-final color, for example blue
- register =
- beat 1 packet:
- register =
BGCOLOR - value = the intended final visible color, for example red
- register =
That gives a clean final assertion:
- two
EV_BGCOLORevents occurred, - final
bg_*equals the second payload.
dmac_reg_stub exact scope
Status target:
- the current state machine becomes genuinely multi-beat for the signoff case
Owns in this phase
- repeated qword fetches based on
QWC - source-address stepping by
16bytes per beat - repeated send/accept handshakes into
gif_path_stub - correct
gif_tag_lastbehavior on the final beat only - transfer completion only after the final beat is accepted
Explicit non-goals
- channel arbitration
- chain-mode
TADRbehavior - interrupt-driven completion semantics
- routing through
ee_memory_map_stub
Required behavioral rules
For QWC = 2:
DMA_START.arg2reports the latchedMADR- beat 0 fetch/read uses
MADR - beat 1 fetch/read uses
MADR + 16 - beat 0 emits
gif_tag_last = 0 - beat 1 emits
gif_tag_last = 1 DMA_DONEoccurs only after beat 1 is accepted downstream
Implementation note:
- if the RTL naturally supports arbitrary
QWC > 0, that is fine - the TB and acceptance criteria only need to lock
QWC = 2
gif_path_stub behavior in Wave 2.6
Recommendation:
- keep
gif_path_stubstateless with respect to packet framing - keep the current project-local interpretation:
- every accepted qword is one standalone register write
- preserve
in_lastas trace-visible metadata only
This means no new internal "tag phase vs. data phase" state is added yet.
Why this is the right boundary
Wave 2.6 is about transfer length, not packet-model realism.
If we introduce tag/data pairing now, we turn one scoped extension into two:
- multi-beat DMA sequencing
- a new packet parser contract
That is exactly the kind of scope expansion we have been avoiding well so far.
Trace policy
No new event names are required for Wave 2.6.
Reuse the current vocabulary:
EV_DMA_CFGEV_DMA_STARTEV_DMA_BEATEV_DMA_DONEEV_GIFTAGEV_BGCOLOR
Required trace-visible facts
The Wave 2.6 proof must make the following visible in traces:
- two DMAC-backed RAM reads from consecutive qword addresses
- two
EV_DMA_BEATevents with:- beat index
0, source addressMADR - beat index
1, source addressMADR + 16
- beat index
- two
EV_GIFTAGevents with:flags[0] = 0on beat 0flags[0] = 1on beat 1
- two GS-side
EV_BGCOLORevents - one
EV_DMA_DONEafter the second beat completes
Cycle-perfect alignment between subsystems is not the primary comparison rule. Order and causality are the primary rules:
- read for beat 0 precedes send for beat 0
- read for beat 1 precedes send for beat 1
- done follows final acceptance
Integration testbench shape
Recommendation:
- update the existing
sim/tb/integration/tb_bgcolor_via_dma.sv
Do not create a second near-duplicate integration TB for first signoff.
Why update instead of fork
Wave 2.6 is a strict extension of the current Milestone A+ proof:
- same subsystem chain
- same top-level outcome
- same trace sinks
Keeping one canonical integration TB reduces maintenance churn and makes the current path's expectations clearer.
If later we want a minimal single-beat smoke test, that can be added as a focused DMAC unit TB rather than cloning the whole platform chain.
TB preload shape
The TB should preload two qwords into ee_ram_stub:
- first qword at
MADR - second qword at
MADR + 16
Suggested values:
- beat 0:
BGCOLOR = blue - beat 1:
BGCOLOR = red
TB pass criteria
At minimum, the updated integration TB should require:
mem_reads_dmac >= 2dma_cfg_count >= 3dma_start_count == 1dma_beat_count == 2dma_done_count == 1giftag_count == 2gs_bgcolor_count == 2- first observed beat source address =
MADR - second observed beat source address =
MADR + 16 - first GIF end-of-packet flag =
0 - second GIF end-of-packet flag =
1 - final
bg_*equals the second payload color - platform still renders active pixels correctly after transfer completion
Optional but useful:
- count post-transfer frames as before
- assert that
DMA_DONEis observed only after the secondEV_GIFTAG
Exit criteria
Wave 2.6 is complete when all of the following are true:
dmac_reg_stubperforms a two-beat memory-backed transferMADRstepping is trace-visible and correctgif_tag_lastis false on beat 0 and true on beat 1- GIF accepts two qwords without new packet-state machinery
- GS observes two BGCOLOR writes
- platform video settles to the second color
make full_checksremains green
Next step after Wave 2.6
If this passes cleanly, the next recommended step is:
- route DMAC through
ee_memory_map_stub
That is the right moment for topology cleanup, because the transfer behavior itself will already be stable and trace-proven.