mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
dwt: trace the bottom diagnostics message box to @0xCB640 and the RAM message table
This commit is contained in:
1 parent
225394e1ae
commit
f3d26ad687
5 files changed
+391
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
@@ -0,0 +1,369 @@
|
||||
# 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`.
|
||||
@@ -388,3 +388,25 @@ The build name must be <= 8 characters: `tftpc_real` silently fails (no
|
||||
|
||||
Evidence: `dwt/loader/evidence/real-unit-xtext/` (loads, markers, server logs,
|
||||
screenshots, emulator runs, `xtext_probe.lua`).
|
||||
|
||||
### Bottom diagnostics box: live state (2026-10-18, read-only)
|
||||
|
||||
The separate bottom X window is owned by the Terminal Manager; its window id is
|
||||
the global at bit `0xB7C60`. The text is selected from the status mask at bit
|
||||
`0xCB640` and a pointer list at bit `0x19F150` (20-byte entries, string pointer
|
||||
at +8 bytes). Live reads, two samples 2 s apart:
|
||||
|
||||
```
|
||||
peek 0xCB640 4 -> 00 00 00 00 mask 0 -> "All Diagnostics Passed"
|
||||
peek 0xB7C60 4 -> 2d 00 10 00 box window 0x0010002d
|
||||
peek 0x19F190 4 -> a0 b9 4a 3f list[0] -> 0x3F4AB9A0
|
||||
peek 0x19F230 4 -> 00 00 00 00 null terminator
|
||||
peek 0x19FF10 2 -> 00 00 language 0 (English)
|
||||
peek 0x19E8D0 4 -> 90 b0 4a 3f record 8: "Ethernet Port Error - 24"
|
||||
peek 0x27C190 4 -> 00 00 00 00 DIAGNOSTIC MAILBOX pointer is NULL
|
||||
peek 0x3F4AB9A0 -> "All Diagnostics Passed"
|
||||
```
|
||||
|
||||
The mask bit mapping (bit 15 = Ethernet Port Error - 24, bit 8 = Video RAM
|
||||
Error - 22, ...) was verified dynamically in MAME by setting `@0xCB640` before
|
||||
the builder at frame 569. Full trace: `dwt/notes/MESSAGEBOX.md`.
|
||||
Reference in new issue
Block a user