Files

ROM import tables

One file per ROM revision. Addresses are bit addresses and are not assumed stable across firmware revisions; v2.2 is the first target.

vt1200-v22.syms is the per-ROM entry table. Every entry is validated by scripts/m4/validate-syms.sh against the v2.2 image (md5 b46a3e442ccb86134d2356bd70d22fd2): it must be in the ROM bit range 3F200000h..3FFFFFFFh, 16-bit aligned, and disassemble to a plausible function prologue (MMTM/MOVE/SETF/CMP/ADDI). scripts/tests/m4/symbols.sh runs the gate and also pins the XMapWindow/XRaiseWindow correction.

The table is consumed through scripts/m2/gen-rom-imports.sh, which emits an ABI-preserving jauc <address>h stub for every <name> <bit-address> line. The 30-entry v2.2 table is the M4 table: the four M3 connection/window entries plus the drawing, event, XImage, XG, blitter and image-client entries. scripts/m2/gen-rom-imports.sh emits every entry; each client links only the stubs it calls.

Do not assume an address here is validated just because it is listed. Each entry below names its evidence. Nothing is guessed: XCreateImage, XPutImage, XGetImage, XDestroyImage, the two error-handler setters, XCreatePixmap, XSetInputFocus and blit_copy were extracted from the ROM disassembly before being added.

XLoadFont and XCopyArea are not in the pinned termtris xlib.h (that header has 15 entries). They are inherited from the M4 plan (task-5-brief.md) and are ROM-validated here by their request builders: the XLoadFont body at 0x3FD4AE80 builds movi 0x2d (OpenFont opcode 45) and the XCopyArea body at 0x3FD3E220 builds movi 0x3e (CopyArea opcode 62); both write the opcode with movb to the request buffer. The same addresses/opcodes are listed in the vendored DWT GUI_APPS.md table. scripts/m4/validate-syms.sh now checks both builders. Do not cite the termtris header for them.

XMapWindow correction

The M3 table used 0x3FD645B0 under the name XMapWindow. That address is XRaiseWindow: its body builds X11 request opcode 12 (ConfigureWindow) with value-mask 0x40 (CWStackMode) and value 0 (Above). The true XMapWindow is 0x3FD64F60, whose body builds request opcode 8 (MapWindow). The termtris VT1200 xlib.h already used 0x3FD64F60.

scripts/m3/validate-syms.sh and scripts/m3/dis-roundtrip.sh now expect 0x3FD64F60, and scripts/tests/m4/symbols.sh fails if a table maps XMapWindow to 0x3FD645B0 (reported as XRaiseWindow/wrong). A client that wants map-and-raise calls XMapWindow and then XRaiseWindow.

The vendored DWT reverse-engineering notes (vendor/vt1200/dwt/notes/GUI_APPS.md, vendor/vt1200/dwt/notes/CROSS.md, vendor/vt1200/dwt/gui/xhello.asm) still label 0x3FD645B0 as XMapWindow. Those are historical notes and were deliberately left untouched: the address is XRaiseWindow, and the corrected table here is authoritative. scripts/m4/validate-syms.sh and scripts/tests/m4/symbols.sh pin the correction.

v2.2 entries validated

The table below has 30 entries: 12 connection/window/event, 1 blitter helper, 8 drawing/GC, 6 XImage/error-handler and 3 C runtime entries. scripts/m4/validate-syms.sh walks all 30 and prints the count.

Connection, windows, events

entry bit address evidence
XOpenDisplay 0x3F9C2570 termtris xlib.h; xhello.asm calls it; MAME child connects
XCreateSimpleWindow 0x3FD41B90 termtris xlib.h; nine-argument create, window id nonzero
XCreatePixmap 0x3FD416E0 CreatePixmap request opcode 0x35; five arguments (display, drawable, width, height, depth); M4 image client's aligned 1-bit pixmap
XMapWindow 0x3FD64F60 request opcode 8 (MapWindow); termtris xlib.h
XRaiseWindow 0x3FD645B0 request opcode 12 (ConfigureWindow), CWStackMode=Above
XSync 0x3FD9F6B0 termtris xlib.h; called after mapping
XFlush 0x3F9B1030 termtris xlib.h
XPending 0x3FD67620 termtris xlib.h
XNextEvent 0x3F9C1CF0 termtris xlib.h; event loop proof
XSelectInput 0x3FD97D50 termtris xlib.h (ChangeWindowAttributes)
XGetInputFocus 0x3FD55210 termtris xlib.h
XSetInputFocus 0x3FD536B0 SetInputFocus request opcode 0x2a; the ROM body reads 0xffe0/0xffc0/0xffa0 and supplies CurrentTime; sibling of XGetInputFocus opcode 0x2b

Blitter copy helper

entry bit address evidence
blit_copy 0x3FB44400 _XPutImage's copy entry (0x3F9CBFE0 calls 0x3FB44400); TMS34010 blitter memcpy with the ROM order (source, destination, byte count) and a normal MMTM prologue. The M4 image client primes it once per draw with a 4-byte self-copy because a loader-created process starts with a zeroed blitter window/pitch context. Validated by scripts/m4/validate-syms.sh and the _blit_copy JAUC/CALLA checks in dis-roundtrip.sh.

Drawing and GC

entry bit address evidence
XCreateGC 0x3F997000 termtris xlib.h; request opcode 55
XSetForeground 0x3FD99A60 termtris xlib.h; caches in GC
XFillRectangle 0x3F99E8F0 termtris xlib.h; request opcode 70
XDrawString 0x3FDA0000 termtris xlib.h; request opcode 74 (PolyText8)
XLoadFont 0x3FD4AE80 ROM body builds movi 0x2d (OpenFont opcode 45) and movb to the request buffer; dwt/notes/GUI_APPS.md table; not in the termtris xlib.h; checked by validate-syms.sh
XCopyArea 0x3FD3E220 ROM body builds movi 0x3e (CopyArea opcode 62) and movb to the request buffer; dwt/notes/GUI_APPS.md table; not in the termtris xlib.h; checked by validate-syms.sh; the M4 image client copies its aligned pixmap with it
XLookupString 0x3F9A9C30 termtris xlib.h; key translation
sleep 0x3FB33A20 termtris xlib.h; called directly

XImage and error handlers (ROM-validated)

entry bit address evidence
XCreateImage 0x3F9A0490 installed as XImage.f.create_image by the ROM initializer at 0x3F9A6AA0; calloc(1, 0x58) = sizeof(XImage) == 88 and field initialization; called by XGetImage with ten arguments at 0x3FD56190
XPutImage 0x3F9CEC70 prologue MMTM sp, a5,a7,a9,a10,a11,a13; body builds request opcode 0x48 at 0x3F9CEE00; references XPutImage: bits_per_pixel conversion unimplemented. at 0x3F9D0E80
XGetImage 0x3FD556B0 prologue MMTM sp, a7,a9,a10,a11,a13; body builds request opcode 0x49 at 0x3FD55830; error path references XGetImage: Can't get requested memory at 0x3FD567A0
XDestroyImage 0x3F9A0D80 ROM private _XDestroyImage, installed as XImage.f.destroy_image by the same initializer; real Xlib defines XDestroyImage as a macro over this pointer. The stub name is _XDestroyImage
XSetErrorHandler 0x3FD45700 stores the handler in the per-process XG block at +0x60; default 0x3F9BD9F0 (_XDefaultError); session manager, WM, and VTE call it with an error-event handler
XSetIOErrorHandler 0x3FD458F0 stores the handler in the XG block at +0x40; default 0x3F9BCD40 (_XDefaultIOError); same callers pass an I/O-error handler

The error-handler setters operate on the per-process XG block, the same block that scripts/m4/xgfix.c installs before XOpenDisplay. Ghidra byte addresses are reproduced as ROM bit addresses (bit = byte << 3); the reconstructed ROM image starts at bit 0x3F200000.

C runtime

entry bit address evidence
strlen 0x3FB458D0 xhello.asm ABI check (strlen("0::0") == 4)
malloc 0x3F701230 ROM allocator; called by XCreateImage/XGetImage
free 0x3F702440 ROM free; called by XDestroyImage

M3/M4 regression checks

scripts/m3/validate-syms.sh independently checks the four M3 entries (XOpenDisplay, XCreateSimpleWindow, XMapWindow, XSync) and now expects XMapWindow 0x3FD64F60. scripts/tests/m3/run.sh runs it before every MAME run, so the compiled client cannot pass with a stale stub. The M3 and M4 validators are separate scripts (the M3 one is a four-entry regression; the M4 one walks the whole 30-entry table), but they use the same range/alignment/prologue rules and the same corrected address. The M4 table also carries XCreatePixmap, XSetInputFocus, blit_copy, XImage, XGetImage/XDestroyImage and both error-handler setters; symbols.sh rejects the historical XMapWindow 0x3FD645B0 mapping and an unaligned XPutImage.

The build resolves these as absolute symbols (or ABI-preserving stubs). Do not bake them into the compiler: keep them in a per-ROM linker script.