Files
vt1200/reference/level1-bypass-analysis.md

17 KiB
Raw Permalink Blame History

Can the level-1 HOST PORT test be skipped? — analysis

Task: determine whether the level-1 HOST PORT test (error 15) can be skipped, suppressed or configured away through anything persistent or configurable — NVRAM, port configuration, a test-selection record, a mode word, a strap — rather than by making it pass. ROMs untouched.

Date: 2026-10-16. Inputs: docs/EK-V1000-SV-002_service-guide.txt, harness/mame/hostport_dis34.txt (linear dis34 disassembly, firmware bit addresses), harness/mame/{BRINGUP_LOG,DUART_REPORT,CODE22_REPORT}.md, harness/mame/vt1200.cpp / vt1200_board.* (read only), and one short empirical run (reference/l1probe/).


Address conventions (four, reconciled)

name formula example for the level-1 call site
firmware bit address (what dis34 prints, what the CPU stores) 0x3F200000 + file_offset*8 0x3F204400
file offset (byte) into vt1200_v22.bin (bit − 0x3F200000)/8 0x880
Ghidra address 0x07E40000 + file_offset 0x07E40880
driver / board-model address bit >> 4, window base 0x06400000 0x06400000 + 0x0D for the firmware's @0x64000D0

Throughout this document I quote the firmware bit address (as hostport_dis34.txt prints it) and give the Ghidra equivalent where useful. A driver handler at base receives (bitaddr − base) >> 4, so the firmware's @0x64000D0 is board-model address 0x0640000D.

All "PC" values are the value of the TMS34010 PC, i.e. a bit address.


Verdict (short)

There is no persistent, configurable test-selection record that suppresses the level-1 host-port test. The level-1 batch runs unconditionally at power-up and its per-run test set comes from hard-coded ROM immediates written into a RAM descriptor, not from NVRAM. P3 only modifies how a test is run. The diagnostics menu's selection is RAM-only and is reached only after the power-up tests.

There is one in-firmware branch that skips the whole level-1 batch: a board-input gate at bit 0x3F2042D0–0x3F2043B0. If DUART1's input-port bit 3 (firmware @0x64000D0 bit 3 = IP3) reads 1 and the 0x6200000 status port has not returned the magic a3 = 0x55, the boot jumps straight to the OS cold-start at 0x3F5788C0, skipping all of level 1. This is a hardware-input condition, not a firmware setting; it skips the whole batch (not just the host port); it is undocumented; and it is not reachable on the normal POST path (bit 3 reads 0 in every harness configuration tried). See §6.

Practical consequence: to boot past level 1 the harness must make the level-1 tests pass, or deliberately assert DUART1 IP3 high (@0x64000D0 bit 3 = 1) so the boot takes the OS branch. There is no NVRAM/config byte to flip.


Q1. When does level 1 run, and is it conditional?

It runs unconditionally at power-up, as part of the boot ROM itself. It is not gated on any NVRAM or settings value.

Evidence — the boot code calls the level-1 runner directly:

3f2043e0: move   a14, -*sp, 1      ; L3F2043E0: the POST "run the suite" loop
3f2043f0: move   a3, *a14+, 1      ;   arg = a3
3f204400: calla  L3FDF72D0         ; <<< the level-1 runner
3f204430: move   a8, a10
3f204440: jane   L3F208060         ; nonzero return -> blink the board LED code
3f204460: jruc   L3F2043E0         ; zero -> loop

The runner L3FDF72D0 is the code that announces level 1: at bit 0x3FDF7770 it calls the reporter L3FDE55F0 with status 0xFFFF, which the dispatcher maps to the string LEVEL1/2 TESTING ** (string bit 0x3FDCA8E8, file 0x17951D). It then drives the memory/port tests (it calls L3FA7C050, the routine that contains the video-memory self-test L3F2018B0, the host test wrapper, etc.).

The call site has exactly one conditional, at 0x3F2042D0–0x3F2043B0, and it reads a hardware input port, not a configuration record:

3f2042d0: move   @0x64000d0, a0, 0   ; DUART1 read reg 0x0D = IP (IP0-IP6, bit7=1)
3f204300: btst   3, a0               ; IP3
3f204310: jane   L3F204360           ; IP3 == 1 -> check a3
3f204340: clr    a3
3f204350: jruc   L3F2043E0           ; IP3 == 0 -> run the suite (a3 = 0)
L3F204360:
3f204360: cmpi   0x55, a3
3f204380: jaeq   L3F2043E0           ; a3 == 0x55 -> run the suite (a3 = 0x55)
3f2043b0: jauc   L3F5788C0           ; else -> OS cold-start, skip level 1

btst sets Z=1 when the tested bit is 0 (MAME tms34010.cpp BTST_K: SET_Z_BIT_LO(~reg,bit)), so jane is taken when IP3 = 1. a3 is set to 0x55 only by the poll at 0x3F2031D0 (a level-0 board-status poll), which on this boot path is skipped (0x3F202660: jaeq L3F204020 jumps over 0x3F202690–0x3F20401F). On the normal harness path, therefore, bit 3 = 0 (measured) and the suite runs unconditionally.

The service guide agrees that level 1 is not optional: "Power-up self-tests run each time you turn on the power switch… Level 0 tests run first, followed by level 1 tests" (guide lines 632–641) and the LED sequence (lines 698–703). The guide does not describe any way to disable power-up testing.

Answer: unconditional. The only readable gate is the DUART1 IP3 hardware input bit, not a stored value.


Q2. Is the host-port test itself conditional (port "not installed")?

No. The firmware has presence checks for some optional hardware, but none for the host port.

Evidence:

  • Guide Table 2–2 (level-1 list, page 13) lists "Host port test" with no qualifier, in contrast to the two conditional entries: "Option RAM test (if present)" and "Image test (if installed)".
  • The firmware's only presence tests are:
    • SIMMs / option memory — port @0x5000000, bits 0–2, read at bit 0x3F2C7E70 / 0x3F2C7F50 / 0x3F2C7F90, printing Not Present (string 0x3F2CCDE8) / SIMM n installed (0x3F2CCEA8, 0x3F2CD040, 0x3F2CD1D8).
    • Image Option — port @0x62000D0 bit 5, read at bit 0x3F2C80B0 (btst 5,a11), printing Image Option / Not Present.
  • A ROM-string search finds no "host port … not present/installed" string; the strings are Host Port Test / Host port test (0x3F49E780, 0x3F49E7F8) and Host Port Error - 15 (0x3FAD5B20), only.

The level-1 host test therefore always runs as part of the batch. (The host-port wrapper does branch on a bit — 0x3FA84B80: move *a11,a9,1 / btst 10,a9 — but bit 10 (0x400) is the test's selection/status bit, which the boot sets, not a presence flag; see Q3.)


Q3. Is there a persistent test-selection or mode record?

No persistent record. Two selection mechanisms exist and neither is stored:

(a) The power-up test set is a hard-coded ROM immediate written into RAM. The level-1 runner builds the test descriptor with L3FA904C0 (driver-visible address 0x3FA904C0), which copies five arguments into a descriptor at RAM 0x0–0x220 (*a11(0x0), +0x20, +0x1a0, +0x1c0, +0x1e0, +0x200). The runner fills those words from immediates:

3fdf7e30: sub    a7, a7
3fdf7e40: movi   0x10fefd80, a9     ; default test set (normal power-up path)
3fdf7e70: move   a9, *a7, 1         ; RAM 0x00 = 0x10FEFD80

(and 0x3FDF7690: movi 0x50febf80 on the other entry). 0x10FEFD80 has bit 10 (0x400) set — that is exactly the code that selects the HOST PORT handler — so the host test is in the default set. Nothing reads these from NVRAM.

(b) The interactive diagnostics menu edits the same RAM words only. The dispatcher sends status code 0x1FFFF to the menu printer at bit 0x3FDE5810, whose first line is VERSION 2.08 - SELECTED TEST TYPE: (string 0x3FDCA990); it prints the four words at RAM 0x00, 0x20, 0x1A0, 0x1C0 and the A–Z selection list (e.g. E - DUART1, CHANNEL A (HOST) TEST (00000400h) at string 0x3FDCB488, O - LOOPBACK MODE (TOGGLE) (08000000h) at 0x3FDCC8D8). The list values are the error codes each test reports, and the words are plain RAM. There is no store-back to NVRAM.

This menu is reached only after a failure (the running harness lands there when level 0 fails / the whole batch reports), so it cannot change the power-up set of the power-up run.

(c) NVRAM is not consulted by the level-1 path at all. Every access to the NVRAM window @0x6000000 in the whole image is the user-settings code (0x3F4ABFA0, 0x3F4ACBA0, 0x3F4AF2D0) and the NVR access helpers (0x3FA7FAE0 region, @0x6000020/@0x6000030). None is on the level-1 path. The guide's NVR contents are user settings only — "group codes, host name or IP address, font paths, and the terminal IP address" (guide lines 2368–2374) — and the Customize dialogs (Customize Host Port, Customize Printer Port, Customize TCP/IP, …) contain no test/diagnostic enable switch.

P3 only modifies. Guide Table 2–5 (page 24, lines 1059–1068):

bit 0 (1)   External loopback: host port.
bit 1 (2)   External loopback: printer port.
bit 2 (4)   External loopback: mouse port.
bit 3 (8)   LANCE loopback: Ethernet port.
bit 4 (16)  Test all baud rates.
bit 5 (32)  Do not exercise modem control signals.

These are per-invocation arguments of the NCP TEST <p1> [<p2> <p3>] command (guide lines 1020–1094). None suppresses or deselects a test; P3 = 0 is "run it normally". Nothing stores P3.


Q4. What does the failure actually gate?

CORRECTED 2026-10-16 — the answer below is WRONG. Kept as the record of what we believed; the corrected account is harness/mame/LEVEL1_CONTINUE_REPORT.md.

A level-1 failure is NOT fatal. The runner reports it and continues. The stub run (VT1200_IO_PATH_STUB=1) shows: HOST PORT - 15 fails at frame 484 → a finite blink (L3F208660) → TYPE 'GO' TO CONTINUE at 1534 → continues → PRINTER PORT - 16 fails at 1627 → blinks → continues at 2759 and draws the X11 weave → then wedges at 2839, on a DUART1 counter interrupt storm.

Measured: 0x3F204440, 0x3F208060, 0x3F208650 and the infinite blink L3FDF1270 each fire 0 times in 20,000 frames, and the runner never returns to the boot loop. The blink actually seen (0x3F2088B0/…) is inside the finite L3F208660.

The real fatal route is L3FDF1010 → L3FDF1270, entered only when the status word *A13(0xFFA0) is nonzero — and the DUART path leaves it zero.

TYPE 'GO' TO CONTINUE is printed, not waited on: nothing answers it, no keypress is read, and no timeout is involved. The "it continues after some time" seen on screen is simply the ~1050-frame blink (~15 s at 72 Hz).

This matters beyond the correction: level 1 is not the hard blocker this document assumed, so the skip gate is a fast path rather than a necessity.

The superseded answer was:

A level-1 failure is fatal to the boot in this ROM: it wedges the machine in the system-board LED error-code loop. It is not merely a message.

Evidence:

  • The error dispatcher is 0x3FDF0630. It reads the status code from bit 0x16F0 (frame slot a13−0x20) and switches: code 0x400 → 0x3FDE9D70, the HOST PORT handler. That handler prints LEVEL1/2 ERROR -> HOST PORT - 15 (string 0x3FDC9C68), dumps the port diagnostics, prints BLINKING SYSTEM BOARD LED (0x3FDF50D0), calls L3F208660 to blink the LED once, prints TYPE 'GO' TO CONTINUE (string 0x3FDCD2A8), and returns.
  • The runner then returns a nonzero value to the boot loop, which executes 0x3F204440: jane L3F208060. L3F208060 blinks the two-digit LED code and loops forever: 0x3F208650: jruc L3F208060.
  • Measured (harness/mame/progress.lua, CAP_MAX/PROG_FRAMES runs, 900–3000 frames): the console transcript is exactly LEVEL1/2 TESTING ** , LEVEL1/2 ERROR -> HOST PORT - 15 , TYPE 'GO' TO CONTINUE; and the CPU is parked in the LED loop — the hottest PCs are 0x3F2088B0, 0x3F208B20, 0x3F208A80, 0x3F208950, all inside L3F208060. Nothing else is printed afterwards. This matches BRINGUP_LOG.md ("blocked, not slow").

So a level-1 failure does not "merely display an error and enter the menu" — the harness's earlier menu entry came from the level-0 I/O-data-path failure, a different path. Once level 1 itself is entered and fails, the boot stops in the blink loop and never reaches the OS/Terminal Manager.

(The guide's sentence "When a level 1 error occurs, the screen displays an error message in the upper-left corner and testing continues" — lines 1863–1866 — describes the diagnostic display sequence; the ROM's own control flow, and the measured result, end the boot at the LED loop.)

The TYPE 'GO' TO CONTINUE prompt is part of the diagnostic summary, not a skip: the harness has no keyboard to answer it, and even with one the boot proceeds to the blink loop, not to the OS.


Q5. Exact bytes, if a skip exists

No NVRAM or settings bytes suppress the test. The only lever that bypasses level 1 is the hardware gate in §6:

  • assert DUART1 input-port bit 3 high — firmware operand @0x64000D0, bit 3 (IP3); board-model/driver address 0x0640000D, value bit 3; the SCN2681 IP register, ip3_w(1). Keep bit 2 = 0 (the b3=1 path is the one that bypasses) and the monitor-switch bits 4–6 as the VR150 value 0x70; bit 7 of the IP register is the always-1 marker. In the board model a single override of 0x0640000D to 0xF8 expresses exactly that.
  • No NVRAM offset is involved.

This is not a per-test suppression (it skips the whole level-1 batch) and it is not a supported setting.


6. The one bypass branch, in detail

L3F2043E0  (run-the-suite entry)
    arg = a3
    calla L3FDF72D0             ; level-1 runner

Reached from 0x3F2042D0:

condition result
@0x64000D0 bit 3 = 0 clr a3; L3F2043E0 — run level 1 (the harness state)
bit 3 = 1 and a3 = 0x55 L3F2043E0 — run level 1
bit 3 = 1 and a3 ≠ 0x55 jauc 0x3F5788C0 — skip level 1, go to the OS

0x3F5788C0 is the OS cold-start: it disables interrupts, programs the DMA ports (@0x5900000, @0x5800000), the display (@0xC0000080), sets sp/a13, and calls the OS/X-server init routines.

a3 = 0x55 is produced only by the level-0 board poll at 0x3F2031D0 (movi 0x55,a3 … clr a3 on failure). That whole block (0x3F202690–0x3F20401F) is jumped over when @0x64000D0 bit 2 = 0 (0x3F202660: jaeq L3F204020), which is the case in the harness, so a3 keeps an earlier value. The measured a3 at the call site was 0 — so with bit 3 = 1 the bypass condition holds.

Empirical note (honest, and weaker than I would like). I exercised this via the board-model override VT1200_BOARD_MAP="0x06200001=0xBEEF;0x0640000D=F8" (correct key is the driver address 0x0640000D, not the firmware operand 0x0640000D0 printed in the driver header's example). With it, @0x64000D0 reads 0x00F8 (bit 3 = 1) and execution reads the port from PCs 0x3F3E1170 and 0x3F5FF7A0 that the normal (0x70) run never reaches — consistent with 0x3F2043B0 being taken, but confounded by the second override present in the same run. I could not confirm the end state: the MAME binary was being rebuilt by another worker during the analysis (its mtime changed between runs and it was momentarily zero-length), a 2500-frame run with 0x0640000D=0xF8 alone still ended in the 0x3F2088B0 LED loop, and I cannot set IP3 through the SCN2681 without a driver change. So: the branch and its condition are clear statically; whether taking it produces a usable terminal (resolves to the OS/X server rather than a later reset) is unverified.


7. What this means for the harness

  1. There is no memory (NVRAM/settings) or command (NCP/P3/diagnostics) that turns off the level-1 host-port test, or level 1, or the power-up tests.
  2. The host-port test is mandatory in the power-up batch; the port has no "not installed" sense.
  3. Because a level-1 failure wedges the boot in the LED-code loop, "ignore the failure" is not an option either.
  4. The only escape route that exists in the ROM is the board-input gate: assert DUART1 IP3 (@0x64000D0 bit 3) high (with bit 2 low) before the boot reads it at 0x3F2042D0, so the boot branches to the OS cold-start 0x3F5788C0. That skips all of level 1, needs no ROM change, and is exactly a harness-side input assertion (SCN2681 ip3_w(1), or 0x0640000D = 0xF8 in the board model). Its fidelity to real hardware is unknown — no document, log or ROM string describes DUART1 IP3 — and it is all-or-nothing.
  5. Otherwise the harness must make every level-1 test that runs pass — the path already taken for VIDEO MEMORY (VT1200_VRAM, REFCNT) and now capped at the host-port DUART sub-bit timing.

Reproduce

harness/mame/hostport_dis34.txt            # dis34, firmware bit addresses
grep -n "callers / labels" per section above

# empirical capture of the level-1 error path (see reference/l1probe/):
reference/l1probe/gate.lua                 # PC/site probe around the boot gate
reference/l1probe/console-transcript.txt   # decoded cap.lua console transcript

M=/home/arti/code/k-space/mame0289/vt1200
$M vt1200 -rompath harness/mame/roms -video none -sound none -nothrottle \
   -debug -debugger none -debuglog \
   -autoboot_script harness/mame/progress.lua -autoboot_delay 0
#   -> hottest PCs 0x3F2088B0/0x3F208B20 (LED loop) = the wedge