The stub run does not park at HOST PORT - 15. Both DUART failures are reported,
the board LED blinks once (finite L3F208660), TYPE 'GO' TO CONTINUE is printed
(no input is read), and the level-1 runner continues ('CONTINUING THE TESTS').
The runner never returns to 3F204440, so 3F208060/3F208650 are never executed.
The run then wedges at frame ~2839 in a DUART1 counter-ready interrupt storm:
the ISR polls DUART1 reg 5 (bit 0x06400050) and always reads 0x08; the counter
runs in timer mode (ACR=0x60) with CTUR/CTLR never programmed, so MAME re-arms
at 1 tick and the interrupt re-asserts every ~229 CPU cycles. Frames at 3500 /
6000 / 12000 are byte-identical; RAM differs by one byte.
Corrects README.md and annotates GATE_CLEANUP_REPORT.md, BRINGUP_LOG.md and
DUART_REPORT.md. Adds a console+PC/milestone instrument and the finding report.
7.1 KiB
VT1200_* env-gate cleanup — outcome
CORRECTION (2026-10-16, later). This report's
no-envsection says the run goes "up to the HOST PORT test (then the LED loop)" and calls3F2088B0/3F208B20/3F208A80/3F208950"the LED loop". Measured over 20 000 frames (harness/mame/LEVEL1_CONTINUE_REPORT.md), those PCs are inside the finite one-shot blinkL3F208660;3F208060/3F208650are never executed and the run does not end there. The DUART failures are followed byCONTINUING THE TESTSand then a DUART1 counter-ready interrupt storm from frame ~2839. The baseline values below are unchanged; only the "LED loop" reading is corrected.
Executes docs/superpowers/plans/2026-10-16-env-gate-cleanup.md. The working
configuration is now the default: a bare vt1200 vt1200 (no env at all)
behaves exactly like the old incantation
VT1200_VRAM=1 VT1200_BOARD_MODEL=handshake VT1200_BOARD_BUSY_TICKS=2 \
VT1200_BOARD_SWITCH="0640000D:70:70" VT1200_DUART=1 VT1200_DUART_SEL=1
Only harness/mame/vt1200.cpp was changed (build.sh needed no edit). ROM
untouched: md5 b46a3e442ccb86134d2356bd70d22fd2.
Promoted (gate removed, value is now the default) — 5
| gate | new default (code) |
|---|---|
VT1200_VRAM |
map(VRAM_BASE_BITS, 0x1fffffff).ram().share("vram") unconditional |
VT1200_BOARD_MODEL |
m_board.set_model_handshake(true) |
VT1200_BOARD_BUSY_TICKS |
m_board.set_busy_ticks(2) |
VT1200_DUART |
DUART1 always mapped + ip4/5/6_w(1); irq_cb always wired |
VT1200_DUART_SEL |
folded to DUART1 only; DUART2 is a new opt-in VT1200_DUART2 |
Deleted (never on a default path) — 15
VT1200_CAL, VT1200_CAL_VID4M, VT1200_CAL_W8, VT1200_BOARD_RAM,
VT1200_BOARD_DEFAULT, VT1200_BOARD_BUSY_W2, VT1200_BOARD_BUSY_W3,
VT1200_BOARD_DMA_TICKS, VT1200_BOARD_SWITCH (superseded — see below),
VT1200_DUART_LB1, VT1200_DUART_LB2, VT1200_LOWLOG, VT1200_VRAMLOG,
VT1200_STRUCTLOG, and VT1200_DUART1_INT2 (folded into VT1200_SKIP_LEVEL1).
Kept — 15
Instrumentation: VT1200_BOARD_LOG, VT1200_BOARD_MAP, VT1200_DUARTLOG,
VT1200_IRQLOG, VT1200_LOG_UNMAPPED, VT1200_DPYLOG + VT1200_DPYLOG_FRAMES,
VT1200_DUMP_FRAME, VT1200_DUMP_RAM, VT1200_DUMP_VRAM, VT1200_DUMP_DIR,
VT1200_NO_RENDER.
Behaviour switches: VT1200_SKIP_LEVEL1 (renamed from VT1200_DUART_IP3),
VT1200_DUART2 (new opt-in for DUART2).
Equivalence proof (the promotion)
The "with env" capture is the six-variable incantation; the "after" capture is
a bare run with no environment variables at all. Same binary MAME build
(/home/arti/code/k-space/mame0289/vt1200), same commands, in the same order.
| observable | with env (before) | no env (after) | match |
|---|---|---|---|
| frame 160 md5 | 713c3e559e8e95b85e801901c505bf60 |
same | ✅ |
| frame 200 md5 | 330a44bfa3263eb54427a8e5320d69b8 |
same | ✅ |
| frame 600 md5 | e8c133380ca1d4d063b95a74a39e17e3 |
same | ✅ |
progress.lua 200 frames |
78 distinct PCs, hot PC=3FDCE400 samples=53 |
byte-identical file | ✅ |
progress.lua 1500 frames |
103 distinct PCs, hot PC=3F2088B0 samples=415 |
byte-identical file | ✅ |
cap.lua 3000-frame console |
7 PRINT lines |
byte-identical file | ✅ |
Console transcript (both runs, identical):
PRINT ... a9=3FDCA8E8 "LEVEL1/2 TESTING ** "
PRINT ... a9=3FDC9C68 "LEVEL1/2 ERROR -> HOST PORT - 15 "
PRINT ... a9=0080000C / 00C0000C / 0100000C / 0200000C (RAM diagnostic pointers)
PRINT ... a9=3FDCD2A8 "TYPE 'GO' TO CONTINUE"
diff before/progress-*.txt after/progress-*.txt and the console diff are empty.
A bare vt1200 vt1200 therefore reaches exactly as far as the incantation.
The five promoted gates were all set in the "before" capture (the incantation is
their conjunction), so the before/after pair covers the promoted set. Each was
load-bearing in the old code — its old default was off/0, and the committed
reports record the consequence of the off state: RENDER_REPORT.md §6 (VRAM off
→ level-1 VIDEO MEMORY fails), BRINGUP_LOG.md Gate 1/3/4 (no handshake/busy →
pole at PC=3FDCE400), DUART_REPORT.md FINAL FINDINGS (no DUART → host-port
transmit never runs). None was a dead promotion.
VT1200_BOARD_SWITCH is superseded (deletion proof, the one uncertain gate)
0x0640000D is the DUART1 IP register — it is inside the DUART1 mapping
(VT1200_WIN3..+0xff, off 0x0D < 0x10), which is registered after the
board-window model, so map precedence (last-wins) hands the read to the DUART
and the board model's switch is never consulted. Measured:
- six-var incantation with
BOARD_SWITCHvs without it: frame md5s, both progress files and the console file are byte-identical (beforevsbefore_noswitch). - with no env at all, the DUART1 IP read is
val=00F0(bit-7 marker + the VR1500x70), the monitor-switch value, from every PC that reads it.
Deletion proof (all deleted gates)
Every deleted gate was read only through getenv("<VAR>") and its handler had
no other caller. After deletion the file has 0 getenv("<VAR>")
occurrences for each, the removed handlers (log_probe/cal*, vramlog*,
lowlog*, structlog*) are gone, and the driver links — so no default path can
reach removed code. VT1200_DUART_LB1/2 had no effect unless set (the firmware
sets MR2 local loopback itself). The deleted probe handlers were registered
only inside their own if (getenv(...)) block. git diff: +126 / −480 lines.
Re-baseline (expected, recorded)
| value | |
|---|---|
| old no-env baseline (200 frames) | PC=3FDCE400 samples=199 (1 distinct PC — the early hardware-ready wedge) |
| new no-env baseline (200 frames) | PC=3FDCE400 samples=53, 78 distinct PCs; at 1500 frames hot PCs are the LED loop 3F2088B0/3F208B20/3F208A80/3F208950 |
Reason: the no-env run is now the working configuration, so it leaves the early wedge and runs POST/level 1 up to the HOST PORT test (then the LED loop). The baseline is a change detector, not a specification; it changed deliberately.
Design points
VT1200_DUART_IP3renamed toVT1200_SKIP_LEVEL1and it now also selects the OS-phase interrupt routing: default (level 1 runs) → POST routing (m_duart1_int2 = false, INT1);VT1200_SKIP_LEVEL1→ drives IP3 high and setsm_duart1_int2 = true(INT2, the OS's DUART1 driver). The standaloneVT1200_DUART1_INT2knob is gone. Verified live:SKIP_LEVEL1=1gives 143 distinct PCs, OS-phase hot PCs (3FAEE280,3FB30390, …) and no console output, i.e. it really skips level 1.- The skip gate itself is not promoted: the faithful default runs level 1
(real terminal reads IP3 low);
VT1200_SKIP_LEVEL1is how we diverge.
Not changed / follow-ups
harness/mame/README.mdstill says the DUARTs are "not modelled" and lists the old mapping table — now stale. Not edited (file ownership), flagged here.vt1200_board.h/.cppstill exposeset_default/set_monitor_switch/set_dma_ticks/set_window_busy_ticks; now unused by the driver but left untouched (not owned by this task).