docs: plan-1 outcome, rulings, and triaged findings (durable record before workspace cleanup)

This commit is contained in:
SDD committed 2026-10-16 02:15:51 +03:00
1 parent 66784de1aa
commit 170d07f0a2
1 file changed
+85
+85
View File
@@ -0,0 +1,85 @@
# Plan 1 outcome — VT1200 board register model
Plan: `docs/superpowers/plans/2026-10-16-vt1200-board-model.md`
Spec: `docs/superpowers/specs/2026-10-16-vt1200-board-model-design.md`
Commits: `acb92d3e44ec..e23dadcfd4de` (7 commits)
Status: **all 4 tasks complete, final whole-branch review clean after one documentation-only fix wave.**
This file is the durable record; the SDD workspace was deleted after review, as the process
requires, with git history as the record.
## What was delivered
| Commit | What |
|---|---|
| `43f69738f405` | board register model extracted into a **MAME-free, unit-tested** class (`vt1200_board.h/.cpp`, `test_vt1200_board.cpp`); driver forwards to it |
| `db2caa555803` | fix round 1: switch knob made unambiguous (`0x70` raw bits vs position) and non-silent |
| `66fe15367b90` | per-window busy state machines |
| `a2f19b2d29a4` | the `0x5800000`/`0x5900000` DMA command/data pair |
| `2d7747a20d48` | configurable timings + the timing sweep and its honest findings |
| `8e18d81cef07` | fix round 1: verbatim sweep/differential/INTENB evidence into the tracked log |
| `e23dadcfd4de` | fix wave: documentation corrections (four windows, real callback trap, guessed DMA timing) |
Guarantees that hold: **no regression** — with no `VT1200_*` env vars set the driver still
reproduces the original wedge `PC=3FDCE400 samples=199`, argued structurally as well as
measured; 9 unit tests pass and the model compiles standalone with plain `g++`.
## The experiment's real result (negative, and valuable)
* The timing sweep is **flat**: `BUSY_W2` in `{1,2,4,8}` all give `total_distinct=59`. The
reason is structural — `tick()` advances **once per emulated frame**, so busy durations of
1/2/4/8 ticks are indistinguishable. Duration is the wrong axis.
* **The critical handshake is isolated to `0x06200000` (WIN2):**
`BUSY_TICKS=0` -> stuck `PC=3FDCE400` (5 PCs); `BUSY_TICKS=0 BUSY_W2=1` -> 56 PCs at
`PC=3F208950`; `BUSY_TICKS=0 BUSY_W3=1` -> still stuck.
* **`INTENB` never becomes non-zero** across 900 frames (`INTPEND=0400` throughout), so the
level-0 interrupt boundary is still not crossed.
## Rulings I made (all of them, in order)
1. **Initialised a git repository in the project.** The directory was not under version
control and the process needs an isolated tree plus per-task commits. A strict
`.gitignore` excludes generated artifacts (160 MB AVI, RAM dumps, traces, core files,
nested clones). *Cost if wrong:* a `.git` the user does not want; reversible with
`rm -rf .git`.
2. **Pinned the `tick()` call site to the scanline callback**, guarded on
`scanline == screen.visible_area().max_y`. The plan left it ambiguous and the
`screen_update` alternative is wrong (it fires in small clip regions). *Cost if wrong:*
busy machines advance at the wrong rate; one call site.
3. **Model policy: DeepSeek V4.1 (`deepseek/deepseek-flash`) preferred over V4**, per user
guidance; `high` variant for implementers/reviewers, `max` for the final review. *Cost if
wrong:* a task or two on a weaker model, with review coverage.
4. **Ran the memory-space investigation as a spike, not a plan**, with full Ghidra access —
output is an answer plus durable artefacts, not product code. *Cost if wrong:* one
worker's time; deliverables additive and write-isolated.
5. **Resumed Task 1's implementer on a different model for its fix round** (V4.1 vs its
V4 Pro dispatch), keeping session context. *Cost if wrong:* none observed — the
re-review found no new breakage.
6. **Treated the spike's VRAM finding as inference, not proof**, so the video plan's first
task is an *empirical* determination (watchpoint `DPYADR`), not a static one. *Cost if
wrong:* one wasted probe.
7. **Task 4's flat sweep stands as a successful outcome.** No improvement was claimed and
none was fabricated; the negative result is the deliverable.
## Reviewer findings triaged as acceptable (not fixed, deliberately)
Thirteen minors were raised across the four tasks; the final review triaged them and
required only the three documentation corrections (now fixed). The rest were judged
acceptable: write-back latches on non-handshake reads; the handshake matching only the low
16 bits; `m_busy_ticks` default 2 -> 0; assorted test-coverage gaps; the unmasked key in
`set_window_busy_ticks`; the DMA defaults-off gate being untested; a WIN1 read ignoring the
register offset (inert while DMA defaults off); and cosmetic diagnostic wording.
**Two worth acting on before the next modelling round** (the reviewer's words): mask the
key in `set_window_busy_ticks`, and offset-gate the WIN1 DMA read so a WIN1 status bit is
not shadowed.
## Where the goal stands
This plan deliberately delivered only its slice. `INTENB` still never leaves zero and no
frame has been rendered — the spec's success criteria 2 and 3 remain open, to be met by the
two named follow-on plans: **video RAM + scanline renderer**, and **DUART / NVRAM / MAC ROM**.
The spike (`reference/memory-space-map.md`) plus this plan's findings tell the video plan
where to start: the framebuffer is not in main RAM, it is set at runtime via `DPYADR`, and
the most-touched unmodelled region is `0x5600000` (~110 accesses on the display/X-init path).