# The bottom diagnostics message box — window, text source, and the Session→Quit re-show Status: **DONE**, with one honest emulator caveat (the MAME skip-level1 restart does not bring the Terminal Manager back; the last step is static code + the real unit's observed box, not an end-to-end MAME reproduction). Address convention: **Ghidra = `0x07E40000 + ROM file offset`**, firmware **bit address = Ghidra × 8**. The TMS34010 program space is bit-addressed, so every firmware address below is a **bit** address unless it is explicitly a Ghidra address. --- ## 1. Which window is the bottom box? It is a **separate top-level X window owned by the Terminal Manager (`SESSIONMGR_PROC`)**, not a child of the TM window and not a status bar drawn by the window manager. Creation code: `FUN_rom_07e94880` (Ghidra `0x07E94880`, bit `0x3F4A4400`). ``` 07E9492A MOVE *A11(0x40),*A14+,0x1 ; parent = screen->root 07E9492E MOVE A7,*A14+,0x1 ; display 07E94930 CALLA 0x07FA8372 ; XCreateSimpleWindow(d, root, ...) 07E94936 MOVE A8,@0xB7C60 ; <-- box window id 07E9494E CALLA 0x07FB2FAA ; XSelectInput(d, win, 0x8000) 07E94976 CALLA 0x07FA70EE ; XChangeWindowAttributes(d, win, 0x200, attrs) ``` The window is mapped at the end of the builder, `0x07E949FA CALLA 0x07FAC9EC` (`XMapWindow(d, @0xB7C60)`). The parent really is the root window: `0x07E948AC` loads `@0xB78E0` (the TM's `Display *`, see `GUI_APPS.md`), walks `display->screens[]` (`+0x480`, `+0x440`) and takes `screen->root` (`+0x40`) before the `XCreateSimpleWindow` call. Live on the real unit (`peek`, read-only, two samples 2 s apart): ``` peek 0xB7C60 4 -> 2d 00 10 00 = 0x0010002d ``` `0x0010002d` is an X resource id (client base `0x00100000`), i.e. a real server window, not a sentinel. The screenshot `dwt/evidence/real-unit-msgbox-allpassed.png` shows the separate wide box at the bottom, with its own border and no title bar. **Owner/process:** the TM's process entry is `0x07E5CDBC` (bit `0x3F2E6DE0`, `SESSIONMGR_PROC`); the box id and all its state are in that process's globals. ## 2. Where the text comes from ### 2.1 The message table The strings are in ROM in a table of **22 records, 20 bytes each**, at Ghidra `0x07FE5552` (bit `0x3FF2AA90`): ``` record = 8 zero bytes + [English ptr][French ptr][German ptr] (20 bytes) ``` The pointer for record `r`, language `L` is at `0x3FF2AA90 + r*0xA0 + 0x40 + L*0x20` (the `+0x40` skips the 8-byte header; `0x20` bits = 4 bytes per language pointer). | record | mask bit | English text | |---|---|---| | 0 | 7 | `NVR Checksum Error - 14` | | 1 | 8 | `Video RAM Error - 22` | | 2 | 9 | `MAIN Memory Error - 13` | | 3 | 10 | `Host Port Error - 15` | | 4 | 11 | `Printer Port Error - 16` | | 5 | 12 | `Keyboard Port Error - 18` | | 6 | 13 | `Mouse Port Error - 19` | | 7 | 14 | `Keyboard Error - 27` | | 8 | **15** | **`Ethernet Port Error - 24`** | | 9 | 16 | `Mouse Error - 26` | | 10 | 17 | `Video Error - 25` | | 11 | 18 | `Ethernet ROM Error - 23` | | 12 | 19 | `Timer 1 Error - 17` | | 13 | 20 | `Timer 2 Error - 21` | | 14 | 21 | `Optional RAM Simm 1 Error - 13` | | 15 | 22 | `Optional RAM Simm 2 Error - 13` | | 16 | 23 | `Optional RAM Simm 3 Error - 13` | | 17 | — | `UNEXPECTED DIAGNOSTIC ERROR RECEIVED` (table entry; not selected by the box builder's bit branches) | | 18 | mask == 0 | **`All Diagnostics Passed`** | | 19 | bits 0–3 | `ROM Checksum Error - 12` | | 20 | — | `Memory Path Error - xx` (table entry; not selected by the box builder) | | 21 | bit 28 | `Image Board Error - 43` | Record 18's English pointer is `0x3F4AB9A0` (Ghidra `0x07E95734`), the exact string in the box. Record 8's is `0x3F4AB090` (Ghidra `0x07E95612`). ### 2.2 The selection code The builder is `FUN_rom_07e94986` (bit `0x3F4A4C30`), called from the TM's session-start path at `0x07E5E6BC`. It calls `FUN_rom_07e94a08` (bit `0x3F4A5040`) to turn the status mask into a list of message pointers: ``` 07E94A16 MOVE @0xCB640,A11,0x1 ; <-- STATUS MASK 07E94A1C JREQ 0x07E94E4C ; mask == 0 -> "All Diagnostics Passed" ... 07E94A3A MOVE @0x19FF10,A7,0x0 ; language index 07E94A40 SLL 0x5,A7 ; *32 bits = *4 bytes 07E94A4C ADDI 0x19E3D0,A7 ; record 0 + 8 (pointer field) 07E94A52 MOVE *A7(0x0),*A9(0x40),0x1 ; message ptr -> list entry +8 ``` Destination list arithmetic (`0x07E94A28`–`0x07E94A32`): ``` SLL 0x7,A9 ; count * 128 SLL 0x5,A7 ; count * 32 ADD A7,A9 ; count * 160 bits = count * 20 bytes ADDI 0x19F150,A9 ; list base ``` So the live list is a **20-byte record per error** at bit **`0x19F150`**, with the string pointer at **entry + 0x40 bits (8 bytes)**; the builder appends a null-pointer terminator. The "All passed" branch uses record 18's pointer (`0x19EF10`); the error branches use record 0..16's pointers (`0x19E3D0` … `0x19EDD0`), record 19 for bits 0–3 (`0x19EFB0`), and record 21 for bit 28 (`0x19F0F0`). The table is also present as a **RAM copy**, byte-for-byte: `0x19E390` = record header 0 (bit address), `0x19E3D0` = record 0's English pointer. (Verified by comparing the dump at frame 3000 with ROM `0x7FE5552`/`0x7FE555A`; the RAM copy begins at byte `0x33C72` in a RAM dump, i.e. bit `0x19E390`.) Live on the real unit: ``` peek 0x19F190 4 -> a0 b9 4a 3f = 0x3F4AB9A0 peek 0x19F230 4 -> 00 00 00 00 (null terminator) peek 0x19E3D0 4 -> f0 aa 4a 3f = record 0 (NVR) peek 0x19E8D0 4 -> 90 b0 4a 3f = record 8 (Ethernet Port - 24) peek 0x19EF10 4 -> a0 b9 4a 3f = record 18 (All Passed) peek 0x3F4AB9A0 24 -> b'All Diagnostics Passed\x00A' ``` ### 2.3 The status variable and its writer **Status variable: the 32-bit failure mask at bit `0xCB640`.** Read by the box builder at `0x07E94A16`. Accumulated by the diagnostics test result handler `FUN_rom_07e7bcf6`: ``` 07E7BD7C MOVE @0xCB640,A11,0x1 07E7BD82 OR A11,A9 ; A9 = one result bit (1 << test number) 07E7BD84 MOVE A9,@0xCB640,0x1 ; <-- OR the failure bit into the mask ``` The same routine prints the corresponding table entry at `0x07E7BDA8 ADDI 0x19E390,A11` (record base) and `0x07E7BDB2 CALLA printf`, so the mask and the printed diagnostic report use the same table. Cleared by the two wrappers: ``` 07E7C212 SUB A11,A11 07E7C214 MOVE A11,@0xCB640,0x1 ; FUN_07e7c20a ... 07E7C276 MOVE A11,@0xCB640,0x1 ; FUN_07e7c26a ``` `FUN_07e7c20a` is called from the boot diagnostics block `0x07EAF184 CALLA 0x07E7C20A`; `FUN_07e7c26a` from the trap/error path `0x07EAF526 CALLA 0x07E7C26A`. No other instruction writes `0xCB640`. Live on the real unit (two samples): ``` peek 0xCB640 4 -> 00 00 00 00 (0 -> All Diagnostics Passed) ``` ## 3. Why Session→Quit re-shows the box The box is **not a boot-only alert**. It is created in the TM's session-start path and re-reads the persistent mask every time that path runs: ``` 07E5E676 CALLA 0x07EE0D48 ; create_process(VTE, ...) -- start the session 07E5E6B6 CALLA 0x07FAC9EC ; XMapWindow(session window) 07E5E6BC CALLA 0x07E94986 ; <-- build list + create box window + draw + map ``` `0x07E5E6BC` is unconditional: every session start reaches it. The Session/Quit action sets the TM quit flag `@0xB70E0`: ``` 07E891D8 MOVE @0xAECDF,A11,0x0 ; confirmation required? 07E891DE JRNE 0x07E891EC 07E891E0 MOVK 0x1,A11 07E891E2 MOVE A11,@0xB70E0,0x1 ; <-- quit flag ``` (The confirmation path `FUN_07e895e2` sets the same flag at `0x07E895F8`.) The TM event loop then exits: ``` 07E5E6DC MOVE @0xB70E0,A11,0x1 07E5E6E2 JRNE 0x07E5F762 ... 07E5F762 CALLA 0x07E5CD00 ; close display / sleep / restart ``` `0x07E5CD00` ends with `0x07E5CD90 CALLA 0x07EAF18A` — the kernel/OS restart entry. That entry is **after** the diagnostics call, and the restart sets `A10 = 1` so the boot block's `0x07EAF182 JRNE 0x07EAF198` skips `0x07EAF184 CALLA 0x07E7C20A`: ``` 07EAF180 MOVE A10,A10 07EAF182 JRNE 0x07EAF198 ; skip diagnostics on restart 07EAF184 CALLA 0x07E7C20A ; boot diagnostics (initial boot only) ... 07EAF192 MOVI 0x1,A10 ``` Therefore Session→Quit **does not re-run the diagnostics check and does not clear `@0xCB640`**. It restarts the OS, the restarted `SESSIONMGR_PROC` runs the same session-start code, and `0x07E5E6BC` recreates the box from the mask that was already in RAM. On the real unit the mask is `0` (`All Diagnostics Passed`), so the same box comes back. On a plain Expose the TM does not rebuild the list; it only repaints it (`0x07E5FAB8` checks that the event window is `@0xB7C60`, then calls the draw routine `0x07E94EB0`). That is why the box stays put across ordinary repaints, but the *re-creation* after Quit is the session-start builder. ## 4. Live read format The box text is **not** stored as ASCII in RAM. The readable state is: | what | bit address | format | |---|---|---| | status mask | **`0xCB640`** | 32-bit little-endian; `0` = All Passed; bit 15 (`0x8000`) = Ethernet Port Error - 24; bit 8 = Video RAM Error - 22; … | | message list | **`0x19F150`** | 20 bytes/entry; string pointer at entry **+0x40 bits (+8 bytes)**; entry *i* pointer at `0x19F150 + i*0xA0 + 0x40`; null pointer terminates | | language | **`0x19FF10`** | 16-bit field; 0 = English (source: 2-bit field at `@0xAEC E8`, copied at `0x07E94990`–`0x07E94998`) | | RAM table copy | **`0x19E390`** | 22 × 20-byte records, same layout as ROM `0x3FF2AA90` | | box window id | **`0xB7C60`** | 32-bit X resource id | Example live reads (`dwt/exploit.py`-style `peek`, read-only): ``` peek 0xCB640 4 -> 00 00 00 00 mask = 0 peek 0x19F190 4 -> a0 b9 4a 3f list[0] = 0x3F4AB9A0 peek 0x3F4AB9A0 24-> "All Diagnostics Passed" peek 0xB7C60 4 -> 2d 00 10 00 window 0x0010002d ``` `0x19F190` is `0x19F150 + 0x40`; no count is stored globally — the builder returns it in `A8`, and the draw routine walks the list until the null pointer. ## 5. What `DIAGNOSTIC MAILBOX` actually is `DIAGNOSTIC MAILBOX` is a **debug dump of a separate diagnostics structure**, not the bottom box's source. * The format string is `0x3FAD4890` (Ghidra `0x07F5A912`), only referenced from the dump routine `FUN_rom_07f5a026` (`0x07F5A026`). * It reads the pointer **`@0x27C190`** and prints `@+0x00, +0x20, … +0x100` as `test_type`, `test_mode`, `test_result`, `error_ext0..6`, `diag_hld`, `memory_bss`, `test_cnt`, `test_f_cnt`, `memory_lth`, `video_dydx`, `num_of_lnks`, and a memory-error link table. * **No code ever arms it.** The only instruction that writes `0x27C190` writes zero: ``` 07F5A38E SUB A9,A9 07F5A394 MOVE A9,@0x27C190,0x1 ; clears the pointer ``` A separate routine (`0x07F59FC8`) fills a fixed buffer at `@0x27C1F0`, but the dump pointer is never pointed at it. On the real unit: ``` peek 0x27C190 4 -> 00 00 00 00 ``` So the mailbox is a dead/debug report dump; the bottom box never reads it. The old candidate `0x16F0` (level-1 dispatcher slot) is likewise not referenced by `0x07E94986`/`0x07E94A08`. ## 6. Evidence ### Real unit (read-only; 2026-10-18) | check | value | |---|---| | `@0xCB640` | `0x00000000` (twice, 2 s apart) | | `@0xB7C60` | `0x0010002d` (twice) | | `@0x19F190` | `0x3F4AB9A0` (twice) | | `@0x19F230` | `0` (sentinel) | | `@0x19FF10` (16-bit) | `0` (English) | | `@0x19E3D0` / `@0x19E8D0` / `@0x19EF10` | `0x3F4AAAF0` / `0x3F4AB090` / `0x3F4AB9A0` | | `@0x27C190` | `0` | | string at `0x3F4AB9A0` | `All Diagnostics Passed` | | screenshot | `dwt/evidence/real-unit-msgbox-allpassed.png` | ### MAME (skip-level1, RAM poke only — ROM untouched) * Breakpoint on the builder entry `0x3F4A4C30` fires at **frame 569** with `d@0xCB640 = 0`. * Write `@0xCB640 = 0x8000` at frame 568, continue to frame 1200: `list[0] = 0x3F4AB090`, and the frame shows **`Ethernet Port Error - 24`** (`dwt/evidence/mame-msgbox-ether24-frame1200.png`). * Write `@0xCB640 = 0x1` -> `list[0] = 0x3F4ABB20` (`ROM Checksum Error - 12`). * Write `@0xCB640 = 0x10000000` -> `list[0] = 0x3F4ABC98` (`Image Board Error - 43`). * Write the quit flag `@0xB70E0 = 1` at frame 1200: `0x3F578C50` (`0x07EAF18A`, OS restart) is reached at frame 3054 with `@0xCB640` still `0x8000`; the boot diagnostics breakpoint `0x3F3E1050` does **not** fire again. (In the skip-level1 emulator the restarted X server comes back at the root weave but the TM does not recreate its window within 8500 frames — see caveat.) * Control frame with mask 0: `dwt/evidence/mame-msgbox-allpassed-frame3000.png`. ## 7. Caveats * The **MAME skip-level1 restart** reproduces the OS restart and the mask persistence, but not the TM's return. The real unit does return to the TM with the box (the owner's observation and `dwt/evidence/real-unit-msgbox-allpassed.png`). The final rebuild step is therefore static (`0x07E5E6BC` is unconditional in the session-start path) plus the real-unit observation, not an end-to-end emulator trace. * The exact "Session → Quit" menu item may be the `Abort X Session` item or the `Quit Control` button; both are session-ending actions. The quit flag `@0xB70E0` and the `0x07E5CD00 → 0x07EAF18A` restart are the path proven here. A Quit that only closes the VTE window would leave the box window untouched and the Expose redraw (`0x07E5FAB8 → 0x07E94EB0`) would repaint the same list; the end result (same text from the same mask) is identical. * The box can hold **several** messages: the builder appends one record per set mask bit and terminates with a null pointer. The window height is derived from the count in `0x07E94880`. * `UNEXPECTED DIAGNOSTIC ERROR RECEIVED` and `Memory Path Error - xx` are table entries but are not selected by the box builder's current bit branches; they are used by the diagnostics reporter. ## 8. Reproduce the MAME checks ```sh # box builder location / mask at build time VT1200_SKIP_LEVEL1=1 BOX_FRAMES=600 \ /home/arti/code/k-space/mame0289/vt1200 vt1200 \ -rompath harness/mame/roms -video none -sound none -nothrottle -skip_gameinfo \ -cfg_directory .vt1200-scratch/msgbox/cfg \ -nvram_directory .vt1200-scratch/msgbox/nvram \ -debug -debugger none -debuglog \ -autoboot_script .vt1200-scratch/msgbox/probe_box.lua -autoboot_delay 0 \ -seconds_to_run 30 # grep BOXBUILD debug.log -> BOXBUILD fr=569 ... mask=00000000 # force a failing bit just before the build MASK_VAL=0x8000 BOX_FRAMES=1250 VT1200_DUMP_FRAME=1200 \ VT1200_DUMP_DIR=$PWD/.vt1200-scratch/msgbox VT1200_SKIP_LEVEL1=1 \ /home/arti/code/k-space/mame0289/vt1200 vt1200 ... \ -autoboot_script .vt1200-scratch/msgbox/probe_box_mask.lua ... # frame 1200 shows "Ethernet Port Error - 24"; RAM @0x19F190 = 0x3F4AB090 ``` The probe scripts live in `.vt1200-scratch/msgbox/` (scratch, not source of truth). The ROM is untouched: `md5 b46a3e442ccb86134d2356bd70d22fd2`.