dwt/notes/GUI_APPS.md gains §2.2.1 (the XImage entry points, the XImage
layout the ROM actually uses, and the format contract) and §2.2.2 (the
measured run). The probe is dwt/gui/xshow.asm + dwt/gui/xshow.lua; the run
log, the PNG and a dependency-free pixel dump are under dwt/gui/evidence/.
Entry points
Bit addresses; Ghidra = bits / 8. Derived with tools/smart34010/dis34 and
then exercised live (see the run below).
dwt/notes/GUI_APPS.md §2.2.1 carries the same dis34 invocations (and the
two more that pin XCreateImage/XDestroyImage) so the names can be re-checked.
The format contract
XCreateImage inherits byte_order, bitmap_unit and bitmap_bit_order
from the Display (dpy+0x1A0, +0x1C0, +0x200), so a client does not have
to guess them. bits_per_pixel starts at 1; only format == ZPixmap (2)
replaces it from the display's pixmap-format list. XYBitmap (0) and XYPixmap
(1) are always 1 bit per pixel.
The only refusal in XPutImage is a ZPixmap of depth != 1 whose image->bits_per_pixel differs from the server's for that depth. It prints
the ROM's own message and returns without sending the request.
XPutImage: bits_per_pixel conversion unimplemented. (0x3F9D0E80, printed at 0x3F9D0B40) is literal: there is no conversion path. It cannot fire for a
1-bit XYBitmap.
XGetImage: Can't get requested memory (0x3FD567A0, printed at 0x3FD55D30) is the client-side malloc for the reply data failing
(0x3FD55C70 allocates 4 * reply.length), not a server refusal.
The run
Probe: a create_process child (COFF loader, no network, no rdebug) opens its
own connection, creates a 400x200 window at 100,100, creates a 32x32 XYBitmap
(depth=1, format=0, LSBFirst, bitmap_unit=32, bitmap_pad=32, bytes_per_line=0 so XCreateImage computes 4), puts it at window (20,20),
syncs twice, destroys it. A second XPutImage of the same image with h=16 at
(20,60) is the control.
Stage 8 = synced (1 start, 2 display, 3 window, 4 mapped, 5 gc, 6 image,
7 putimage). The window shows the full 32-row image at screen 122..153 and the
16-row control at 162..177:
The row check is reproducible without ImageMagick/PIL:
The run was repeated with a snapshot 30 frames later (xshow_frame2680.png);
the decoded rows are identical and the two PNGs have the same md5
(ab9d63844aa5a3dd9d281a6bee3c76c2), so the picture is the window's state and
not a transient.
Measured, and not
Measured: the ROM's XCreateImage builds the struct above from the ten
arguments + the display's orders; a 1-bit XYBitmap is painted exactly w x h
pixels at the requested destination; a smaller h is honoured; XDestroyImage
runs and the process survives. The display advertises exactly one pixmap format
(depth 1, bpp 1, pad 32).
Inferred / not measured:XGetImage is documented from disassembly only —
the probe does not call it. Orders other than LSBFirst are supposed to work
(the 1-bit copier picks a normalization routine keyed by (bitmap_unit, bitmap_bit_order, byte_order) for image and display, 0x3F9CB7C0–0x3F9CBB20), but only LSBFirst/32 was run. A non-1-bit ZPixmap is
untested: the server has no such visual, so only the bpp-mismatch path above is
established statically.
ROM untouched: md5 b46a3e442ccb86134d2356bd70d22fd2. The run uses the
documented VT1200_SKIP_LEVEL1=1 divergence and private cfg/nvram directories.
Closes #4
`dwt/notes/GUI_APPS.md` gains **§2.2.1** (the XImage entry points, the XImage
layout the ROM actually uses, and the format contract) and **§2.2.2** (the
measured run). The probe is `dwt/gui/xshow.asm` + `dwt/gui/xshow.lua`; the run
log, the PNG and a dependency-free pixel dump are under `dwt/gui/evidence/`.
## Entry points
Bit addresses; Ghidra = bits / 8. Derived with `tools/smart34010/dis34` and
then exercised live (see the run below).
| Xlib function | bits | Ghidra | shape |
|---|---|---|---|
| `XCreateImage(d,visual,depth,format,offset,data,w,h,pad,bpl)` | `0x3F9A0490` | `0x07F34092` | 10 args, `calloc(1,0x58)`, fills the struct |
| `XPutImage(d,drawable,gc,image,sx,sy,dx,dy,w,h)` | `0x3F9D0370` | `0x07F3A06E` | 10 args; request opcode **72 (0x48)**, length 6 |
| `XDestroyImage(image)` | `0x3F9A0D80` | `0x07F341B0` | 1 arg; free(data), free(obdata), free(image) |
| `XGetImage(d,drawable,x,y,w,h,plane_mask,format)` | `0x3FD556B0` | `0x07FAAAD6` | 8 args; request opcode **73 (0x49)**, length 5 |
The request bytes are pinned mechanically:
```
$ tools/smart34010/dis34 -l -o -b 3F9CEE00 -s 0xF9DC0 vt1200_v22.bin | head -3
3f9cee00: movi 0x48, a7 ; 09c7 0048
3f9cee20: movb a7, *a11 ; 8ceb
3f9cee30: movk 6, a5 ; 18c5
$ tools/smart34010/dis34 -l -o -b 3FD55830 -s 0x16AB06 vt1200_v22.bin | head -3
3fd55830: movi 0x49, a11 ; 09cb 0049
3fd55850: movb a11, *a10 ; 8d6a
3fd55860: movk 5, a7 ; 18a7
```
`dwt/notes/GUI_APPS.md` §2.2.1 carries the same `dis34` invocations (and the
two more that pin `XCreateImage`/`XDestroyImage`) so the names can be re-checked.
## The format contract
* `XCreateImage` inherits `byte_order`, `bitmap_unit` and `bitmap_bit_order`
from the Display (`dpy+0x1A0`, `+0x1C0`, `+0x200`), so a client does not have
to guess them. `bits_per_pixel` starts at **1**; only `format == ZPixmap` (2)
replaces it from the display's pixmap-format list. **XYBitmap (0) and XYPixmap
(1) are always 1 bit per pixel.**
* The only refusal in `XPutImage` is a ZPixmap of depth != 1 whose
`image->bits_per_pixel` differs from the server's for that depth. It prints
the ROM's own message and returns **without sending the request**.
* `XPutImage: bits_per_pixel conversion unimplemented.` (`0x3F9D0E80`, printed at
`0x3F9D0B40`) is literal: there is no conversion path. It cannot fire for a
1-bit XYBitmap.
* `XGetImage: Can't get requested memory` (`0x3FD567A0`, printed at
`0x3FD55D30`) is the **client-side malloc for the reply data** failing
(`0x3FD55C70` allocates `4 * reply.length`), not a server refusal.
## The run
Probe: a `create_process` child (COFF loader, no network, no rdebug) opens its
own connection, creates a 400x200 window at 100,100, creates a 32x32 **XYBitmap**
(`depth=1`, `format=0`, LSBFirst, `bitmap_unit=32`, `bitmap_pad=32`,
`bytes_per_line=0` so `XCreateImage` computes 4), puts it at window (20,20),
syncs twice, destroys it. A second `XPutImage` of the same image with `h=16` at
(20,60) is the control.
```
$ HOME=/tmp/opencode/task4-home VT1200_SKIP_LEVEL1=1 VT1200_MONITOR=VR150 \
XSHOW_AT=2500 XSHOW_END=2700 XSHOW_SNAP=2650 XSHOW_OUT=$PWD/dwt/gui/evidence \
/home/arti/code/k-space/mame0289/vt1200 vt1200 -rompath harness/mame/roms \
-video none -sound none -nothrottle -skip_gameinfo \
-nvram_directory /tmp/opencode/task4-run/nvram \
-cfg_directory /tmp/opencode/task4-run/cfg \
-debug -debugger none -autoboot_script dwt/gui/xshow.lua -autoboot_delay 0
XSHOW: f2650 mirror stage=00000008 display=0093C910 window=00400001 gc=00987D70 image=00988130 putret=00000080 syncret=00000001 strlen=00000004
XSHOW: final image@00988130 width=00000020 height=00000020 xoffset=00000000 format=00000000 data=018D0000 byte_order=00000000 bitmap_unit=00000020 bitmap_bit_order=00000000 bitmap_pad=00000020 depth=00000001 bytes_per_line=00000004 bits_per_pixel=00000001
XSHOW: final dpy@0093C910 byte_order=00000000 bitmap_unit=00000020 scanline_pad=00000020 bitmap_bit_order=00000000
XSHOW: final pixmap_formats n=1 list=00367D90
XSHOW: final fmt[0] depth=00000001 bits_per_pixel=00000001 pad=00000020
```
Stage 8 = synced (1 start, 2 display, 3 window, 4 mapped, 5 gc, 6 image,
7 putimage). The window shows the full 32-row image at screen 122..153 and the
16-row control at 162..177:

The row check is reproducible without ImageMagick/PIL:
```
$ python3 dwt/gui/evidence/png_rows.py dwt/gui/evidence/xshow_frame2650.png 118 118 40 64
122 ....################################....
123 .....#..................................
...
152 ..................................#.....
153 ....################################....
...
162 ....################################....
163 .....#..................................
...
177 ...................#....................
```
The run was repeated with a snapshot 30 frames later (`xshow_frame2680.png`);
the decoded rows are identical and the two PNGs have the same md5
(`ab9d63844aa5a3dd9d281a6bee3c76c2`), so the picture is the window's state and
not a transient.
## Measured, and not
**Measured:** the ROM's `XCreateImage` builds the struct above from the ten
arguments + the display's orders; a 1-bit XYBitmap is painted exactly `w x h`
pixels at the requested destination; a smaller `h` is honoured; `XDestroyImage`
runs and the process survives. The display advertises exactly one pixmap format
(depth 1, bpp 1, pad 32).
**Inferred / not measured:** `XGetImage` is documented from disassembly only —
the probe does not call it. Orders other than LSBFirst are *supposed* to work
(the 1-bit copier picks a normalization routine keyed by
`(bitmap_unit, bitmap_bit_order, byte_order)` for image and display,
`0x3F9CB7C0`–`0x3F9CBB20`), but only LSBFirst/32 was run. A non-1-bit ZPixmap is
untested: the server has no such visual, so only the bpp-mismatch path above is
established statically.
ROM untouched: `md5 b46a3e442ccb86134d2356bd70d22fd2`. The run uses the
documented `VT1200_SKIP_LEVEL1=1` divergence and private cfg/nvram directories.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #4
dwt/notes/GUI_APPS.mdgains §2.2.1 (the XImage entry points, the XImagelayout the ROM actually uses, and the format contract) and §2.2.2 (the
measured run). The probe is
dwt/gui/xshow.asm+dwt/gui/xshow.lua; the runlog, the PNG and a dependency-free pixel dump are under
dwt/gui/evidence/.Entry points
Bit addresses; Ghidra = bits / 8. Derived with
tools/smart34010/dis34andthen exercised live (see the run below).
XCreateImage(d,visual,depth,format,offset,data,w,h,pad,bpl)0x3F9A04900x07F34092calloc(1,0x58), fills the structXPutImage(d,drawable,gc,image,sx,sy,dx,dy,w,h)0x3F9D03700x07F3A06EXDestroyImage(image)0x3F9A0D800x07F341B0XGetImage(d,drawable,x,y,w,h,plane_mask,format)0x3FD556B00x07FAAAD6The request bytes are pinned mechanically:
dwt/notes/GUI_APPS.md§2.2.1 carries the samedis34invocations (and thetwo more that pin
XCreateImage/XDestroyImage) so the names can be re-checked.The format contract
XCreateImageinheritsbyte_order,bitmap_unitandbitmap_bit_orderfrom the Display (
dpy+0x1A0,+0x1C0,+0x200), so a client does not haveto guess them.
bits_per_pixelstarts at 1; onlyformat == ZPixmap(2)replaces it from the display's pixmap-format list. XYBitmap (0) and XYPixmap
(1) are always 1 bit per pixel.
XPutImageis a ZPixmap of depth != 1 whoseimage->bits_per_pixeldiffers from the server's for that depth. It printsthe ROM's own message and returns without sending the request.
XPutImage: bits_per_pixel conversion unimplemented.(0x3F9D0E80, printed at0x3F9D0B40) is literal: there is no conversion path. It cannot fire for a1-bit XYBitmap.
XGetImage: Can't get requested memory(0x3FD567A0, printed at0x3FD55D30) is the client-side malloc for the reply data failing(
0x3FD55C70allocates4 * reply.length), not a server refusal.The run
Probe: a
create_processchild (COFF loader, no network, no rdebug) opens itsown connection, creates a 400x200 window at 100,100, creates a 32x32 XYBitmap
(
depth=1,format=0, LSBFirst,bitmap_unit=32,bitmap_pad=32,bytes_per_line=0soXCreateImagecomputes 4), puts it at window (20,20),syncs twice, destroys it. A second
XPutImageof the same image withh=16at(20,60) is the control.
Stage 8 = synced (1 start, 2 display, 3 window, 4 mapped, 5 gc, 6 image,
7 putimage). The window shows the full 32-row image at screen 122..153 and the
16-row control at 162..177:
The row check is reproducible without ImageMagick/PIL:
The run was repeated with a snapshot 30 frames later (
xshow_frame2680.png);the decoded rows are identical and the two PNGs have the same md5
(
ab9d63844aa5a3dd9d281a6bee3c76c2), so the picture is the window's state andnot a transient.
Measured, and not
Measured: the ROM's
XCreateImagebuilds the struct above from the tenarguments + the display's orders; a 1-bit XYBitmap is painted exactly
w x hpixels at the requested destination; a smaller
his honoured;XDestroyImageruns and the process survives. The display advertises exactly one pixmap format
(depth 1, bpp 1, pad 32).
Inferred / not measured:
XGetImageis documented from disassembly only —the probe does not call it. Orders other than LSBFirst are supposed to work
(the 1-bit copier picks a normalization routine keyed by
(bitmap_unit, bitmap_bit_order, byte_order)for image and display,0x3F9CB7C0–0x3F9CBB20), but only LSBFirst/32 was run. A non-1-bit ZPixmap isuntested: the server has no such visual, so only the bpp-mismatch path above is
established statically.
ROM untouched:
md5 b46a3e442ccb86134d2356bd70d22fd2. The run uses thedocumented
VT1200_SKIP_LEVEL1=1divergence and private cfg/nvram directories.561aeb24dbto2c2ba3bd5f