docs(xie): the ROM's XImage entry points and the 1-bit format #11

Merged
arti merged 1 commits from opencode.siil.arti.ee/vt1200:fix/issue-4-ximage into master 2026-11-13 11:56:26 +02:00
17 changed files with 2330 additions and 2 deletions

No files matched your search

Binary file not shown.
Binary file not shown.
+626
View File
@@ -0,0 +1,626 @@
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 1
0001 ; xshow.asm -- create a 1-bit XImage and XPutImage it o
0002 ;
0003 ; Run as a first-class process created by the COFF load
0004 ; in the rdebug dispatcher's context: a connect made fr
0005 ; accepted at the service layer but the server never re
0006 ;
0007 ; The image is a 32x32 XYBitmap (format 0), depth 1, cr
0008 ; XCreateImage and drawn with XPutImage. Its data is a
0009 ; cells, written into .data at build time, so the PNG s
0010 ; or nothing -- there is nothing to misread.
0011 ;
0012 ; XImage entry points used here (Ghidra address -> bit
0013 ; 7F34092 XCreateImage(d,visual,depth,format,offset,d
0014 ; 7FA06E XPutImage(d,drawable,gc,image,sx,sy,dx,dy,w
0015 ; 7F341B0 XDestroyImage(image)
0016 ; 7FAAAD6 XGetImage(d,drawable,x,y,w,h,plane_mask,for
0017 ; (XGetImage is documented from disassembly; this probe
0018 ;
0019 ; Calling convention: reserve one slot with `move a14,-
0020 ; last-to-first upward through a14, then `calla`. The
0021 ; the return address and the reserved slot, and restore
0022 ; sp/a14 from RAM markers (xtext.asm records that exact
0023 ;
0024 ; Xlib clobbers the CPU's SETF field state, so field 1
0025 ; established after every call. a10/a11/a12 survive ev
0026 ; a9 (the GC) survives XCreateImage and XPutImage; a7 (
0027 ; XPutImage. XDestroyImage saves only a11/a13, so it r
0028 ;
0029 ; Markers:
0030 ; 01890100 display 01890120 window 01890140 stage
0031 ; 01890180 gc 018901A0 XPutImage return 01
0032 ; These are the xhello-compatible cells the runner repo
0033 ; cells sit in the heap and were overwritten after its
0034 ; are mirrored into .bss at 018D8000h (below), which no
0035 ; 018D8000 stage 018D8020 display 018D8040 window
0036 ; 018D8080 image 018D80A0 putret 018D80C0 syncret
0037 ; Stage: 1 start, 2 display, 3 window, 4 mapped, 5 gc,
0038 ; 8 synced; 091h..097h = the step that failed.
0039 ;
0040 ; Scratch argument area: 01894000h (the app's own stack
0041
0042 00000000 .text
0043 00000000 _start:
0044 00000000 0550 setf 16, 0, 0
0045 00000010 0740 setf 32, 0, 1
0046 00000020 098F mmtm sp, a0,a1,a2,a3,a4,a5,a6,a7
00000030 FF00
0047
0048 00000040 09E0 movi 1, a0, L
00000050 00000001
0049 00000070 0780 move a0, @01890140h, 1 ; stage = 1
00000080 01890140
0050 000000A0 0780 move a0, @m_stage, 1
000000B0 00000000+
0051
0052 ; ---- convention check: strlen("0::0") == 4 ---------
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 2
0053 000000D0 A3CF move a14, -*sp, 1
0054 000000E0 09EE movi 01894000h, a14, L
000000F0 01894000
0055 00000110 09E0 movi 3FACE948h, a0, L ; ROM "0::0"
00000120 3FACE948
0056 00000140 920E move a0, *a14+, 1
0057 00000150 0D5F calla 3FB458D0h ; strlen
00000160 3FB458D0
0058 00000180 0550 setf 16, 0, 0
0059 00000190 0740 setf 32, 0, 1
0060 000001A0 0788 move a8, @m_strlen, 1
000001B0 000000E0+
0061 000001D0 09E0 movi 4, a0, L
000001E0 00000004
0062 00000200 4808 cmp a0, a8
0063 00000210 CB00 jrne fail_abi
00000220 0171
0064
0065 ; ---- display = XOpenDisplay("0::0") ----------------
0066 00000230 A3CF move a14, -*sp, 1
0067 00000240 09EE movi 01894000h, a14, L
00000250 01894000
0068 00000270 09E0 movi 3FACE948h, a0, L
00000280 3FACE948
0069 000002A0 920E move a0, *a14+, 1
0070 000002B0 0D5F calla 3F9C2570h ; XOpenDisplay
000002C0 3F9C2570
0071 000002E0 0550 setf 16, 0, 0
0072 000002F0 0740 setf 32, 0, 1
0073 00000300 4D0B move a8, a11
0074 00000310 078B move a11, @01890100h, 1 ; MARK display
00000320 01890100
0075 00000340 078B move a11, @m_display, 1
00000350 00000020+
0076 00000370 4D6B move a11, a11
0077 00000380 CA00 jreq fail_open
00000390 015E
0078 000003A0 09E0 movi 2, a0, L
000003B0 00000002
0079 000003D0 0780 move a0, @01890140h, 1 ; stage = 2
000003E0 01890140
0080 00000400 0780 move a0, @m_stage, 1
00000410 00000000+
0081
0082 ; ---- root = *(*(display+0x480)+0x40) ---------------
0083 00000430 B76A move *a11(0480h), a10, 1
00000440 0480
0084 00000450 B74A move *a10(040h), a10, 1
00000460 0040
0085
0086 ; ---- window = XCreateSimpleWindow(d,root,100,100,400
0087 ; white background (pixel 1), black border, so a black
0088 00000470 A3CF move a14, -*sp, 1
0089 00000480 09EE movi 01894000h, a14, L
00000490 01894000
0090 000004B0 09E0 movi 1, a0, L
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 3
000004C0 00000001
0091 000004E0 920E move a0, *a14+, 1 ; background = 1 (white)
0092 000004F0 09E0 movi 0, a0, L
00000500 00000000
0093 00000520 920E move a0, *a14+, 1 ; border = 0 (black)
0094 00000530 09E0 movi 2, a0, L
00000540 00000002
0095 00000560 920E move a0, *a14+, 1 ; border width
0096 00000570 09E0 movi 200, a0, L
00000580 000000C8
0097 000005A0 920E move a0, *a14+, 1 ; height
0098 000005B0 09E0 movi 400, a0, L
000005C0 00000190
0099 000005E0 920E move a0, *a14+, 1 ; width
0100 000005F0 09E0 movi 100, a0, L
00000600 00000064
0101 00000620 920E move a0, *a14+, 1 ; y
0102 00000630 920E move a0, *a14+, 1 ; x
0103 00000640 934E move a10, *a14+, 1 ; parent = root
0104 00000650 936E move a11, *a14+, 1 ; display
0105 00000660 0D5F calla 3FD41B90h ; XCreateSimpleWindow
00000670 3FD41B90
0106 00000690 0550 setf 16, 0, 0
0107 000006A0 0740 setf 32, 0, 1
0108 000006B0 4D0A move a8, a10
0109 000006C0 078A move a10, @01890120h, 1 ; MARK window
000006D0 01890120
0110 000006F0 078A move a10, @m_window, 1
00000700 00000040+
0111 00000720 4D4A move a10, a10
0112 00000730 CA00 jreq fail_win
00000740 0127
0113 00000750 09E0 movi 3, a0, L
00000760 00000003
0114 00000780 0780 move a0, @01890140h, 1 ; stage = 3
00000790 01890140
0115 000007B0 0780 move a0, @m_stage, 1
000007C0 00000000+
0116
0117 ; ---- XMapWindow(display, window) -------------------
0118 000007E0 A3CF move a14, -*sp, 1
0119 000007F0 09EE movi 01894000h, a14, L
00000800 01894000
0120 00000820 934E move a10, *a14+, 1
0121 00000830 936E move a11, *a14+, 1
0122 00000840 0D5F calla 3FD645B0h ; XMapWindow
00000850 3FD645B0
0123 00000870 0550 setf 16, 0, 0
0124 00000880 0740 setf 32, 0, 1
0125 00000890 09E0 movi 4, a0, L
000008A0 00000004
0126 000008C0 0780 move a0, @01890140h, 1 ; stage = 4
000008D0 01890140
0127 000008F0 0780 move a0, @m_stage, 1
00000900 00000000+
0128
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 4
0129 ; ---- gc = XCreateGC(d, window, 0, NULL) ------------
0130 00000920 A3CF move a14, -*sp, 1
0131 00000930 09EE movi 01894000h, a14, L
00000940 01894000
0132 00000960 09E0 movi 0, a0, L
00000970 00000000
0133 00000990 920E move a0, *a14+, 1 ; values
0134 000009A0 920E move a0, *a14+, 1 ; mask = 0
0135 000009B0 934E move a10, *a14+, 1 ; drawable
0136 000009C0 936E move a11, *a14+, 1 ; display
0137 000009D0 0D5F calla 3F997000h ; XCreateGC
000009E0 3F997000
0138 00000A00 0550 setf 16, 0, 0
0139 00000A10 0740 setf 32, 0, 1
0140 00000A20 4D09 move a8, a9 ; GC
0141 00000A30 0789 move a9, @01890180h, 1 ; MARK gc
00000A40 01890180
0142 00000A60 0789 move a9, @m_gc, 1
00000A70 00000060+
0143 00000A90 4D29 move a9, a9
0144 00000AA0 CA00 jreq fail_gc
00000AB0 00F4
0145
0146 ; ---- XSetForeground(display, gc, 0) -- draw with pen
0147 00000AC0 A3CF move a14, -*sp, 1
0148 00000AD0 09EE movi 01894000h, a14, L
00000AE0 01894000
0149 00000B00 09E0 movi 0, a0, L
00000B10 00000000
0150 00000B30 920E move a0, *a14+, 1 ; pixel = 0
0151 00000B40 932E move a9, *a14+, 1 ; gc
0152 00000B50 936E move a11, *a14+, 1 ; display
0153 00000B60 0D5F calla 3FD99A60h ; XSetForeground
00000B70 3FD99A60
0154 00000B90 0550 setf 16, 0, 0
0155 00000BA0 0740 setf 32, 0, 1
0156 00000BB0 09E0 movi 5, a0, L
00000BC0 00000005
0157 00000BE0 0780 move a0, @01890140h, 1 ; stage = 5
00000BF0 01890140
0158 00000C10 0780 move a0, @m_stage, 1
00000C20 00000000+
0159
0160 ; ---- image = XCreateImage(d, NULL, 1, XYBitmap, 0,
0161 ; bitmap, 32, 32, 32, 0) ---
0162 00000C40 A3CF move a14, -*sp, 1
0163 00000C50 09EE movi 01894000h, a14, L
00000C60 01894000
0164 00000C80 09E0 movi 0, a0, L
00000C90 00000000
0165 00000CB0 920E move a0, *a14+, 1 ; bytes_per_line = 0 (let it comput
0166 00000CC0 09E0 movi 32, a0, L
00000CD0 00000020
0167 00000CF0 920E move a0, *a14+, 1 ; bitmap_pad = 32
0168 00000D00 09E0 movi 32, a0, L
00000D10 00000020
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 5
0169 00000D30 920E move a0, *a14+, 1 ; height
0170 00000D40 920E move a0, *a14+, 1 ; width
0171 00000D50 09E0 movi BITMAP, a0, L
00000D60 00000000"
0172 00000D80 920E move a0, *a14+, 1 ; data
0173 00000D90 09E0 movi 0, a0, L
00000DA0 00000000
0174 00000DC0 920E move a0, *a14+, 1 ; offset
0175 00000DD0 920E move a0, *a14+, 1 ; format = 0 (XYBitmap)
0176 00000DE0 09E0 movi 1, a0, L
00000DF0 00000001
0177 00000E10 920E move a0, *a14+, 1 ; depth = 1
0178 00000E20 4400 sub a0, a0
0179 00000E30 920E move a0, *a14+, 1 ; visual = NULL
0180 00000E40 936E move a11, *a14+, 1 ; display
0181 00000E50 0D5F calla 3F9A0490h ; XCreateImage
00000E60 3F9A0490
0182 00000E80 0550 setf 16, 0, 0
0183 00000E90 0740 setf 32, 0, 1
0184 00000EA0 4D07 move a8, a7 ; image (a7 survives XPutImage)
0185 00000EB0 0788 move a8, @01890160h, 1 ; MARK image
00000EC0 01890160
0186 00000EE0 0788 move a8, @m_image, 1
00000EF0 00000080+
0187 00000F10 4D08 move a8, a8
0188 00000F20 CA00 jreq fail_img
00000F30 00B0
0189 00000F40 09E0 movi 6, a0, L
00000F50 00000006
0190 00000F70 0780 move a0, @01890140h, 1 ; stage = 6
00000F80 01890140
0191 00000FA0 0780 move a0, @m_stage, 1
00000FB0 00000000+
0192
0193 ; ---- let the WM frame/reparent and map the window (x
0194 ; A draw issued before the reparent can be lost, so sy
0195 00000FD0 09EC movi 4, a12, L
00000FE0 00000004
0196 00001000 map_wait:
0197 00001000 A3CF move a14, -*sp, 1
0198 00001010 09EE movi 01894000h, a14, L
00001020 01894000
0199 00001040 09E0 movi 0, a0, L
00001050 00000000
0200 00001070 920E move a0, *a14+, 1 ; discard = 0
0201 00001080 936E move a11, *a14+, 1 ; display
0202 00001090 0D5F calla 3FD9F6B0h ; XSync
000010A0 3FD9F6B0
0203 000010C0 0550 setf 16, 0, 0
0204 000010D0 0740 setf 32, 0, 1
0205 000010E0 3DEC dsjs a12, map_wait
0206
0207 ; ---- XPutImage(d, win, gc, image, 0,0, 20,20, 32,32)
0208 000010F0 A3CF move a14, -*sp, 1
0209 00001100 09EE movi 01894000h, a14, L
00001110 01894000
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 6
0210 00001130 09E0 movi 32, a0, L
00001140 00000020
0211 00001160 920E move a0, *a14+, 1 ; h
0212 00001170 920E move a0, *a14+, 1 ; w
0213 00001180 09E0 movi 20, a0, L
00001190 00000014
0214 000011B0 920E move a0, *a14+, 1 ; dst_y
0215 000011C0 920E move a0, *a14+, 1 ; dst_x
0216 000011D0 4400 sub a0, a0
0217 000011E0 920E move a0, *a14+, 1 ; src_y
0218 000011F0 920E move a0, *a14+, 1 ; src_x
0219 00001200 92EE move a7, *a14+, 1 ; image
0220 00001210 932E move a9, *a14+, 1 ; gc
0221 00001220 934E move a10, *a14+, 1 ; drawable
0222 00001230 936E move a11, *a14+, 1 ; display
0223 00001240 0D5F calla 3F9D0370h ; XPutImage
00001250 3F9D0370
0224 00001270 0550 setf 16, 0, 0
0225 00001280 0740 setf 32, 0, 1
0226 00001290 0788 move a8, @018901A0h, 1 ; MARK putimage return
000012A0 018901A0
0227 000012C0 0788 move a8, @m_putret, 1
000012D0 000000A0+
0228 000012F0 09E0 movi 7, a0, L
00001300 00000007
0229 00001320 0780 move a0, @01890140h, 1 ; stage = 7
00001330 01890140
0230 00001350 0780 move a0, @m_stage, 1
00001360 00000000+
0231
0232 ; ---- control: the same image with h = 16 at dst_y =
0233 ; The PNG must show exactly 16 rows here (src rows 0..
0234 ; what proves the 32-row draw above is the image, not
0235 00001380 A3CF move a14, -*sp, 1
0236 00001390 09EE movi 01894000h, a14, L
000013A0 01894000
0237 000013C0 09E0 movi 16, a0, L
000013D0 00000010
0238 000013F0 920E move a0, *a14+, 1 ; h = 16
0239 00001400 09E0 movi 32, a0, L
00001410 00000020
0240 00001430 920E move a0, *a14+, 1 ; w = 32
0241 00001440 09E0 movi 60, a0, L
00001450 0000003C
0242 00001470 920E move a0, *a14+, 1 ; dst_y = 60
0243 00001480 09E0 movi 20, a0, L
00001490 00000014
0244 000014B0 920E move a0, *a14+, 1 ; dst_x = 20
0245 000014C0 4400 sub a0, a0
0246 000014D0 920E move a0, *a14+, 1 ; src_y = 0
0247 000014E0 920E move a0, *a14+, 1 ; src_x = 0
0248 000014F0 92EE move a7, *a14+, 1 ; image
0249 00001500 932E move a9, *a14+, 1 ; gc
0250 00001510 934E move a10, *a14+, 1 ; drawable
0251 00001520 936E move a11, *a14+, 1 ; display
0252 00001530 0D5F calla 3F9D0370h ; XPutImage
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 7
00001540 3F9D0370
0253 00001560 0550 setf 16, 0, 0
0254 00001570 0740 setf 32, 0, 1
0255
0256 ; ---- flush, twice: the request is only in the client
0257 00001580 A3CF move a14, -*sp, 1
0258 00001590 09EE movi 01894000h, a14, L
000015A0 01894000
0259 000015C0 09E0 movi 0, a0, L
000015D0 00000000
0260 000015F0 920E move a0, *a14+, 1
0261 00001600 936E move a11, *a14+, 1
0262 00001610 0D5F calla 3FD9F6B0h ; XSync
00001620 3FD9F6B0
0263 00001640 0550 setf 16, 0, 0
0264 00001650 0740 setf 32, 0, 1
0265 00001660 0788 move a8, @018901C0h, 1 ; MARK sync return
00001670 018901C0
0266 00001690 0788 move a8, @m_syncret, 1
000016A0 000000C0+
0267
0268 000016C0 A3CF move a14, -*sp, 1
0269 000016D0 09EE movi 01894000h, a14, L
000016E0 01894000
0270 00001700 09E0 movi 0, a0, L
00001710 00000000
0271 00001730 920E move a0, *a14+, 1
0272 00001740 936E move a11, *a14+, 1
0273 00001750 0D5F calla 3FD9F6B0h ; XSync
00001760 3FD9F6B0
0274 00001780 0550 setf 16, 0, 0
0275 00001790 0740 setf 32, 0, 1
0276 000017A0 0788 move a8, @018901C0h, 1
000017B0 018901C0
0277 000017D0 0788 move a8, @m_syncret, 1
000017E0 000000C0+
0278
0279 00001800 09E0 movi 8, a0, L
00001810 00000008
0280 00001830 0780 move a0, @01890140h, 1 ; stage = 8
00001840 01890140
0281 00001860 0780 move a0, @m_stage, 1
00001870 00000000+
0282
0283 ; ---- XDestroyImage(image) --------------------------
0284 00001890 A3CF move a14, -*sp, 1
0285 000018A0 09EE movi 01894000h, a14, L
000018B0 01894000
0286 000018D0 92EE move a7, *a14+, 1
0287 000018E0 0D5F calla 3F9A0D80h ; XDestroyImage
000018F0 3F9A0D80
0288 00001910 0550 setf 16, 0, 0
0289 00001920 0740 setf 32, 0, 1
0290 00001930 C01A jruc done
0291
0292 00001940 fail_abi:
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 8
0293 00001940 09E0 movi 091h, a0, L
00001950 00000091
0294 00001970 C010 jruc failed
0295 00001980 fail_open:
0296 00001980 09E0 movi 092h, a0, L
00001990 00000092
0297 000019B0 C00C jruc failed
0298 000019C0 fail_win:
0299 000019C0 09E0 movi 093h, a0, L
000019D0 00000093
0300 000019F0 C008 jruc failed
0301 00001A00 fail_gc:
0302 00001A00 09E0 movi 095h, a0, L
00001A10 00000095
0303 00001A30 C004 jruc failed
0304 00001A40 fail_img:
0305 00001A40 09E0 movi 096h, a0, L
00001A50 00000096
0306 00001A70 0300 jruc failed
0307 00001A80 failed:
0308 00001A80 0780 move a0, @01890140h, 1
00001A90 01890140
0309 00001AB0 0780 move a0, @m_stage, 1
00001AC0 00000000+
0310
0311 00001AE0 done:
0312 00001AE0 09AF mmfm sp, a0,a1,a2,a3,a4,a5,a6,a7
00001AF0 00FF
0313 00001B00 09E8 movi 0, a8, L
00001B10 00000000
0314 00001B30 0960 rets
0315
0316 00000000 .data
0317 ; 32 rows of 4 bytes, LSB-first pixels: a solid row at
0318 ; at y=31, and a one-pixel diagonal between them. The
0319 ; rows make the drawn height readable straight off the
0320 00000000 BITMAP:
0321 00000000 FF .byte 0FFh, 0FFh, 0FFh, 0FFh, 002h, 000h, 000h, 000h
00000008 FF
00000010 FF
00000018 FF
00000020 02
00000028 00
00000030 00
00000038 00
0322 00000040 04 .byte 004h, 000h, 000h, 000h, 008h, 000h, 000h, 000h
00000048 00
00000050 00
00000058 00
00000060 08
00000068 00
00000070 00
00000078 00
0323 00000080 10 .byte 010h, 000h, 000h, 000h, 020h, 000h, 000h, 000h
00000088 00
00000090 00
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 9
00000098 00
000000A0 20
000000A8 00
000000B0 00
000000B8 00
0324 000000C0 40 .byte 040h, 000h, 000h, 000h, 080h, 000h, 000h, 000h
000000C8 00
000000D0 00
000000D8 00
000000E0 80
000000E8 00
000000F0 00
000000F8 00
0325 00000100 00 .byte 000h, 001h, 000h, 000h, 000h, 002h, 000h, 000h
00000108 01
00000110 00
00000118 00
00000120 00
00000128 02
00000130 00
00000138 00
0326 00000140 00 .byte 000h, 004h, 000h, 000h, 000h, 008h, 000h, 000h
00000148 04
00000150 00
00000158 00
00000160 00
00000168 08
00000170 00
00000178 00
0327 00000180 00 .byte 000h, 010h, 000h, 000h, 000h, 020h, 000h, 000h
00000188 10
00000190 00
00000198 00
000001A0 00
000001A8 20
000001B0 00
000001B8 00
0328 000001C0 00 .byte 000h, 040h, 000h, 000h, 000h, 080h, 000h, 000h
000001C8 40
000001D0 00
000001D8 00
000001E0 00
000001E8 80
000001F0 00
000001F8 00
0329 00000200 00 .byte 000h, 000h, 001h, 000h, 000h, 000h, 002h, 000h
00000208 00
00000210 01
00000218 00
00000220 00
00000228 00
00000230 02
00000238 00
0330 00000240 00 .byte 000h, 000h, 004h, 000h, 000h, 000h, 008h, 000h
00000248 00
00000250 04
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 10
00000258 00
00000260 00
00000268 00
00000270 08
00000278 00
0331 00000280 00 .byte 000h, 000h, 010h, 000h, 000h, 000h, 020h, 000h
00000288 00
00000290 10
00000298 00
000002A0 00
000002A8 00
000002B0 20
000002B8 00
0332 000002C0 00 .byte 000h, 000h, 040h, 000h, 000h, 000h, 080h, 000h
000002C8 00
000002D0 40
000002D8 00
000002E0 00
000002E8 00
000002F0 80
000002F8 00
0333 00000300 00 .byte 000h, 000h, 000h, 001h, 000h, 000h, 000h, 002h
00000308 00
00000310 00
00000318 01
00000320 00
00000328 00
00000330 00
00000338 02
0334 00000340 00 .byte 000h, 000h, 000h, 004h, 000h, 000h, 000h, 008h
00000348 00
00000350 00
00000358 04
00000360 00
00000368 00
00000370 00
00000378 08
0335 00000380 00 .byte 000h, 000h, 000h, 010h, 000h, 000h, 000h, 020h
00000388 00
00000390 00
00000398 10
000003A0 00
000003A8 00
000003B0 00
000003B8 20
0336 000003C0 00 .byte 000h, 000h, 000h, 040h, 0FFh, 0FFh, 0FFh, 0FFh
000003C8 00
000003D0 00
000003D8 40
000003E0 FF
000003E8 FF
000003F0 FF
000003F8 FF
0337 00000400 BITMAP_END:
0338
0339 00000000 .bss m_stage, 32, 1
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 11
0340 00000020 .bss m_display, 32, 1
0341 00000040 .bss m_window, 32, 1
0342 00000060 .bss m_gc, 32, 1
0343 00000080 .bss m_image, 32, 1
0344 000000A0 .bss m_putret, 32, 1
0345 000000C0 .bss m_syncret, 32, 1
0346 000000E0 .bss m_strlen, 32, 1
0347
0348 .end
No Errors, No Warnings
+36
View File
@@ -0,0 +1,36 @@
*****************************************************
GSP COFF Linker, Version 2.00, 87.300
*****************************************************
Fri Nov 13 09:31:54 2026
OUTPUT FILE NAME: <XSHOW.out>
ENTRY POINT SYMBOL: 0
SECTION ALLOCATION MAP
output attributes/
section page origin length input sections
-------- ---- ---------- ---------- ----------------
.text 0 01840000 00001B40
01840000 00001B40 XSHOW.obj (.text)
.data 0 018D0000 00000400
018D0000 00000400 XSHOW.obj (.data)
.bss 0 018D8000 00000100 UNINITIALIZED
018D8000 00000100 XSHOW.obj (.bss)
GLOBAL SYMBOLS
address name address name
-------- ---- -------- ----
018D8000 .bss 01840000 .text
018D0000 .data 01841B40 etext
01840000 .text 018D0000 .data
018D0400 edata 018D0400 edata
018D8100 end 018D8000 .bss
01841B40 etext 018D8100 end
[6 symbols]
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""Print a region of an 8-bit PNG as ASCII, one screen row per line.
The evidence PNGs are captured by MAME under -video none, so there is no
ImageMagick/PIL dependency here: this decodes the PNG with zlib directly
(non-interlaced, 8-bit grey/RGB/RGBA only) and prints '#' for dark pixels.
Usage:
python3 dwt/gui/evidence/png_rows.py PNG X Y W H
"""
import struct
import sys
import zlib
def read_png(path):
data = open(path, "rb").read()
if data[:8] != b"\x89PNG\r\n\x1a\n":
raise SystemExit("not a PNG: " + path)
off, idat = 8, b""
w = h = bitdepth = colour = None
while off < len(data):
length = struct.unpack(">I", data[off:off + 4])[0]
kind = data[off + 4:off + 8]
chunk = data[off + 8:off + 8 + length]
off += 12 + length
if kind == b"IHDR":
w, h, bitdepth, colour, _, _, interlace = struct.unpack(">IIBBBBB", chunk)
if bitdepth != 8 or interlace != 0:
raise SystemExit("only 8-bit non-interlaced PNGs")
elif kind == b"IDAT":
idat += chunk
elif kind == b"IEND":
break
bpp = {0: 1, 2: 3, 4: 2, 6: 4}[colour]
stride = w * bpp
raw = zlib.decompress(idat)
out = bytearray(h * stride)
prev = bytearray(stride)
pos = 0
for y in range(h):
filt = raw[pos]
pos += 1
line = bytearray(raw[pos:pos + stride])
pos += stride
if filt == 1:
for i in range(bpp, stride):
line[i] = (line[i] + line[i - bpp]) & 0xFF
elif filt == 2:
for i in range(stride):
line[i] = (line[i] + prev[i]) & 0xFF
elif filt == 3:
for i in range(stride):
left = line[i - bpp] if i >= bpp else 0
line[i] = (line[i] + ((left + prev[i]) >> 1)) & 0xFF
elif filt == 4:
for i in range(stride):
left = line[i - bpp] if i >= bpp else 0
up = prev[i]
upleft = prev[i - bpp] if i >= bpp else 0
p = left + up - upleft
pa, pb, pc = abs(p - left), abs(p - up), abs(p - upleft)
pred = left if (pa <= pb and pa <= pc) else (up if pb <= pc else upleft)
line[i] = (line[i] + pred) & 0xFF
out[y * stride:(y + 1) * stride] = line
prev = line
return w, h, bpp, bytes(out)
def main():
path, x0, y0, cw, ch = sys.argv[1], *map(int, sys.argv[2:6])
w, _, bpp, px = read_png(path)
for y in range(y0, y0 + ch):
row = "".join("#" if px[(y * w + x) * bpp] < 128 else "." for x in range(x0, x0 + cw))
print("%4d %s" % (y, row))
if __name__ == "__main__":
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+75
View File
@@ -0,0 +1,75 @@
# xshow_frame2650.png, decoded with: python3 dwt/gui/evidence/png_rows.py dwt/gui/evidence/xshow_frame2650.png 118 118 40 64
# window content origin is screen (102,102): XPutImage dst (20,20) -> row 122,
# dst (20,60) -> row 162. Full 32-row image: 122..153. h=16 control: 162..177.
118 ........................................
119 ........................................
120 ........................................
121 ........................................
122 ....################################....
123 .....#..................................
124 ......#.................................
125 .......#................................
126 ........#...............................
127 .........#..............................
128 ..........#.............................
129 ...........#............................
130 ............#...........................
131 .............#..........................
132 ..............#.........................
133 ...............#........................
134 ................#.......................
135 .................#......................
136 ..................#.....................
137 ...................#....................
138 ....................#...................
139 .....................#..................
140 ......................#.................
141 .......................#................
142 ........................#...............
143 .........................#..............
144 ..........................#.............
145 ...........................#............
146 ............................#...........
147 .............................#..........
148 ..............................#.........
149 ...............................#........
150 ................................#.......
151 .................................#......
152 ..................................#.....
153 ....################################....
154 ........................................
155 ........................................
156 ........................................
157 ........................................
158 ........................................
159 ........................................
160 ........................................
161 ........................................
162 ....################################....
163 .....#..................................
164 ......#.................................
165 .......#................................
166 ........#...............................
167 .........#..............................
168 ..........#.............................
169 ...........#............................
170 ............#...........................
171 .............#..........................
172 ..............#.........................
173 ...............#........................
174 ................#.......................
175 .................#......................
176 ..................#.....................
177 ...................#....................
178 ........................................
179 ........................................
180 ........................................
181 ........................................
# second observation, 30 frames later: the same rows, byte-identical PNG
$ python3 dwt/gui/evidence/png_rows.py dwt/gui/evidence/xshow_frame2680.png 118 118 40 64 | diff - <(python3 dwt/gui/evidence/png_rows.py dwt/gui/evidence/xshow_frame2650.png 118 118 40 64)
(no output: identical)
$ md5sum dwt/gui/evidence/xshow_frame2650.png dwt/gui/evidence/xshow_frame2680.png
ab9d63844aa5a3dd9d281a6bee3c76c2 dwt/gui/evidence/xshow_frame2650.png
ab9d63844aa5a3dd9d281a6bee3c76c2 dwt/gui/evidence/xshow_frame2680.png
+37
View File
@@ -0,0 +1,37 @@
Warning: -video none doesn't make much sense without -seconds_to_run
ALSA lib seq_hw.c:540:(snd_seq_hw_open) open /dev/snd/seq failed: No such file or directory
vt1200: screen_update#1 frame=0 clip_y=0..0 screen=1280x901
XSHOW: payload dwt/loader/build/loader.bin (1220 B) -> bit 01880000
XSHOW: COFF dwt/gui/build/xshow.coff (1384 B) -> bit 01900000
XSHOW: file magic=0090 nscns=3 opthdr=28 entry=00000000 textstart=01840000
XSHOW: sec .text paddr=01840000 size=6976 bits (872 B) flags=0x20
XSHOW: sec .data paddr=018D0000 size=1024 bits (128 B) flags=0x40
XSHOW: sec .bss paddr=018D8000 size=256 bits (32 B) flags=0x80
XSHOW: .data first 16 bytes: FF FF FF FF 02 00 00 00 04 00 00 00 08 00 00 00
vt1200: screen_update#2 frame=0 clip_y=1..900 screen=1280x901
vt1200: scanline#1 line=1 enabled=1
vt1200: guard#1 frame=0 dump_frame=-1 dump_ram=-1
vt1200: screen_update#3 frame=1 clip_y=0..0 screen=1280x901
vt1200: scanline#2 line=0 enabled=1
vt1200: screen_update#4 frame=1 clip_y=1..1 screen=1280x901
vt1200: scanline#3 line=1 enabled=1
vt1200: scanline#4 line=2 enabled=1
XSHOW: loader poked 610 words, readback 0 bad at 01880000
XSHOW: COFF poked 692 words, readback 0 bad at 01900000
XSHOW: descriptor @01882C00 magic=4C44/5231 buf=01900000 len=1384 mode=0
XSHOW: will resume at 3F579970 after create_process
XSHOW: frame 2500: entered loader at 01880000 (caller SP=007F52B0)
XSHOW: f2540 cells stage=00000008 display=0093C910 window=00400001 gc=00987D70 image=00988130 putret=00000080 syncret=00000001
XSHOW: f2540 mirror stage=00000008 display=0093C910 window=00400001 gc=00987D70 image=00988130 putret=00000080 syncret=00000001 strlen=00000004
XSHOW: f2650 cells stage=00000008 display=0093C910 window=00400001 gc=00987D70 image=00988130 putret=00000080 syncret=00000001
XSHOW: f2650 mirror stage=00000008 display=0093C910 window=00400001 gc=00987D70 image=00988130 putret=00000080 syncret=00000001 strlen=00000004
XSHOW: snapshot /home/arti/.t3/worktrees/vt1200/fix-issue-4-ximage-4368fd1dbccf74ec/dwt/gui/evidence/xshow_frame2650.png ok=true
XSHOW: final cells stage=00000008 display=0093C910 window=00400001 gc=00987D70 image=00988130 putret=00000080 syncret=00000001
XSHOW: final mirror stage=00000008 display=0093C910 window=00400001 gc=00987D70 image=00988130 putret=00000080 syncret=00000001 strlen=00000004
XSHOW: loader status=0 entry=01840000 text=01840000/6976 bits
XSHOW: PC at exit = 3F5799D0
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
Average speed: 111.50% (37 seconds)
+348
View File
@@ -0,0 +1,348 @@
; xshow.asm -- create a 1-bit XImage and XPutImage it onto a mapped window.
;
; Run as a first-class process created by the COFF loader (create_process), NOT
; in the rdebug dispatcher's context: a connect made from the rdebug process is
; accepted at the service layer but the server never reads the X11 setup.
;
; The image is a 32x32 XYBitmap (format 0), depth 1, created by the ROM's own
; XCreateImage and drawn with XPutImage. Its data is a checkerboard of 8x8
; cells, written into .data at build time, so the PNG shows either the pattern
; or nothing -- there is nothing to misread.
;
; XImage entry points used here (Ghidra address -> bit address):
; 7F34092 XCreateImage(d,visual,depth,format,offset,data,w,h,pad,bpl) 3F9A0490
; 7FA06E XPutImage(d,drawable,gc,image,sx,sy,dx,dy,w,h) 3F9D0370
; 7F341B0 XDestroyImage(image) 3F9A0D80
; 7FAAAD6 XGetImage(d,drawable,x,y,w,h,plane_mask,format) 3FD556B0
; (XGetImage is documented from disassembly; this probe does not call it.)
;
; Calling convention: reserve one slot with `move a14,-*sp,1`, push arguments
; last-to-first upward through a14, then `calla`. The callee's `rets 2` pops
; the return address and the reserved slot, and restores a14. Do NOT reload
; sp/a14 from RAM markers (xtext.asm records that exact crash).
;
; Xlib clobbers the CPU's SETF field state, so field 1 (32-bit) is re-
; established after every call. a10/a11/a12 survive every call used here;
; a9 (the GC) survives XCreateImage and XPutImage; a7 (the image) survives
; XPutImage. XDestroyImage saves only a11/a13, so it runs last.
;
; Markers:
; 01890100 display 01890120 window 01890140 stage 01890160 image
; 01890180 gc 018901A0 XPutImage return 018901C0 last XSync
; These are the xhello-compatible cells the runner reports. xhello's own
; cells sit in the heap and were overwritten after its run, so the same values
; are mirrored into .bss at 018D8000h (below), which nothing else uses:
; 018D8000 stage 018D8020 display 018D8040 window 018D8060 gc
; 018D8080 image 018D80A0 putret 018D80C0 syncret 018D80E0 strlen
; Stage: 1 start, 2 display, 3 window, 4 mapped, 5 gc, 6 image, 7 putimage,
; 8 synced; 091h..097h = the step that failed.
;
; Scratch argument area: 01894000h (the app's own stack is elsewhere).
.text
_start:
setf 16, 0, 0
setf 32, 0, 1
mmtm sp, a0,a1,a2,a3,a4,a5,a6,a7
movi 1, a0, L
move a0, @01890140h, 1 ; stage = 1
move a0, @m_stage, 1
; ---- convention check: strlen("0::0") == 4 --------------------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 3FACE948h, a0, L ; ROM "0::0"
move a0, *a14+, 1
calla 3FB458D0h ; strlen
setf 16, 0, 0
setf 32, 0, 1
move a8, @m_strlen, 1
movi 4, a0, L
cmp a0, a8
jrne fail_abi
; ---- display = XOpenDisplay("0::0") ---------------------------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 3FACE948h, a0, L
move a0, *a14+, 1
calla 3F9C2570h ; XOpenDisplay
setf 16, 0, 0
setf 32, 0, 1
move a8, a11
move a11, @01890100h, 1 ; MARK display
move a11, @m_display, 1
move a11, a11
jreq fail_open
movi 2, a0, L
move a0, @01890140h, 1 ; stage = 2
move a0, @m_stage, 1
; ---- root = *(*(display+0x480)+0x40) --------------------------
move *a11(0480h), a10, 1
move *a10(040h), a10, 1
; ---- window = XCreateSimpleWindow(d,root,100,100,400,200,2,0,1)
; white background (pixel 1), black border, so a black bitmap shows.
move a14, -*sp, 1
movi 01894000h, a14, L
movi 1, a0, L
move a0, *a14+, 1 ; background = 1 (white)
movi 0, a0, L
move a0, *a14+, 1 ; border = 0 (black)
movi 2, a0, L
move a0, *a14+, 1 ; border width
movi 200, a0, L
move a0, *a14+, 1 ; height
movi 400, a0, L
move a0, *a14+, 1 ; width
movi 100, a0, L
move a0, *a14+, 1 ; y
move a0, *a14+, 1 ; x
move a10, *a14+, 1 ; parent = root
move a11, *a14+, 1 ; display
calla 3FD41B90h ; XCreateSimpleWindow
setf 16, 0, 0
setf 32, 0, 1
move a8, a10
move a10, @01890120h, 1 ; MARK window
move a10, @m_window, 1
move a10, a10
jreq fail_win
movi 3, a0, L
move a0, @01890140h, 1 ; stage = 3
move a0, @m_stage, 1
; ---- XMapWindow(display, window) -----------------------------
move a14, -*sp, 1
movi 01894000h, a14, L
move a10, *a14+, 1
move a11, *a14+, 1
calla 3FD645B0h ; XMapWindow
setf 16, 0, 0
setf 32, 0, 1
movi 4, a0, L
move a0, @01890140h, 1 ; stage = 4
move a0, @m_stage, 1
; ---- gc = XCreateGC(d, window, 0, NULL) ----------------------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1 ; values
move a0, *a14+, 1 ; mask = 0
move a10, *a14+, 1 ; drawable
move a11, *a14+, 1 ; display
calla 3F997000h ; XCreateGC
setf 16, 0, 0
setf 32, 0, 1
move a8, a9 ; GC
move a9, @01890180h, 1 ; MARK gc
move a9, @m_gc, 1
move a9, a9
jreq fail_gc
; ---- XSetForeground(display, gc, 0) -- draw with pen 0 (black) --
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1 ; pixel = 0
move a9, *a14+, 1 ; gc
move a11, *a14+, 1 ; display
calla 3FD99A60h ; XSetForeground
setf 16, 0, 0
setf 32, 0, 1
movi 5, a0, L
move a0, @01890140h, 1 ; stage = 5
move a0, @m_stage, 1
; ---- image = XCreateImage(d, NULL, 1, XYBitmap, 0,
; bitmap, 32, 32, 32, 0) -------------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1 ; bytes_per_line = 0 (let it compute)
movi 32, a0, L
move a0, *a14+, 1 ; bitmap_pad = 32
movi 32, a0, L
move a0, *a14+, 1 ; height
move a0, *a14+, 1 ; width
movi BITMAP, a0, L
move a0, *a14+, 1 ; data
movi 0, a0, L
move a0, *a14+, 1 ; offset
move a0, *a14+, 1 ; format = 0 (XYBitmap)
movi 1, a0, L
move a0, *a14+, 1 ; depth = 1
sub a0, a0
move a0, *a14+, 1 ; visual = NULL
move a11, *a14+, 1 ; display
calla 3F9A0490h ; XCreateImage
setf 16, 0, 0
setf 32, 0, 1
move a8, a7 ; image (a7 survives XPutImage)
move a8, @01890160h, 1 ; MARK image
move a8, @m_image, 1
move a8, a8
jreq fail_img
movi 6, a0, L
move a0, @01890140h, 1 ; stage = 6
move a0, @m_stage, 1
; ---- let the WM frame/reparent and map the window (xtext) -----
; A draw issued before the reparent can be lost, so sync first.
movi 4, a12, L
map_wait:
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1 ; discard = 0
move a11, *a14+, 1 ; display
calla 3FD9F6B0h ; XSync
setf 16, 0, 0
setf 32, 0, 1
dsjs a12, map_wait
; ---- XPutImage(d, win, gc, image, 0,0, 20,20, 32,32) ---------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 32, a0, L
move a0, *a14+, 1 ; h
move a0, *a14+, 1 ; w
movi 20, a0, L
move a0, *a14+, 1 ; dst_y
move a0, *a14+, 1 ; dst_x
sub a0, a0
move a0, *a14+, 1 ; src_y
move a0, *a14+, 1 ; src_x
move a7, *a14+, 1 ; image
move a9, *a14+, 1 ; gc
move a10, *a14+, 1 ; drawable
move a11, *a14+, 1 ; display
calla 3F9D0370h ; XPutImage
setf 16, 0, 0
setf 32, 0, 1
move a8, @018901A0h, 1 ; MARK putimage return
move a8, @m_putret, 1
movi 7, a0, L
move a0, @01890140h, 1 ; stage = 7
move a0, @m_stage, 1
; ---- control: the same image with h = 16 at dst_y = 60 --------
; The PNG must show exactly 16 rows here (src rows 0..15): that is
; what proves the 32-row draw above is the image, not the window.
move a14, -*sp, 1
movi 01894000h, a14, L
movi 16, a0, L
move a0, *a14+, 1 ; h = 16
movi 32, a0, L
move a0, *a14+, 1 ; w = 32
movi 60, a0, L
move a0, *a14+, 1 ; dst_y = 60
movi 20, a0, L
move a0, *a14+, 1 ; dst_x = 20
sub a0, a0
move a0, *a14+, 1 ; src_y = 0
move a0, *a14+, 1 ; src_x = 0
move a7, *a14+, 1 ; image
move a9, *a14+, 1 ; gc
move a10, *a14+, 1 ; drawable
move a11, *a14+, 1 ; display
calla 3F9D0370h ; XPutImage
setf 16, 0, 0
setf 32, 0, 1
; ---- flush, twice: the request is only in the client buffer ---
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1
move a11, *a14+, 1
calla 3FD9F6B0h ; XSync
setf 16, 0, 0
setf 32, 0, 1
move a8, @018901C0h, 1 ; MARK sync return
move a8, @m_syncret, 1
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1
move a11, *a14+, 1
calla 3FD9F6B0h ; XSync
setf 16, 0, 0
setf 32, 0, 1
move a8, @018901C0h, 1
move a8, @m_syncret, 1
movi 8, a0, L
move a0, @01890140h, 1 ; stage = 8
move a0, @m_stage, 1
; ---- XDestroyImage(image) ------------------------------------
move a14, -*sp, 1
movi 01894000h, a14, L
move a7, *a14+, 1
calla 3F9A0D80h ; XDestroyImage
setf 16, 0, 0
setf 32, 0, 1
jruc done
fail_abi:
movi 091h, a0, L
jruc failed
fail_open:
movi 092h, a0, L
jruc failed
fail_win:
movi 093h, a0, L
jruc failed
fail_gc:
movi 095h, a0, L
jruc failed
fail_img:
movi 096h, a0, L
jruc failed
failed:
move a0, @01890140h, 1
move a0, @m_stage, 1
done:
mmfm sp, a0,a1,a2,a3,a4,a5,a6,a7
movi 0, a8, L
rets
.data
; 32 rows of 4 bytes, LSB-first pixels: a solid row at y=0, a solid row
; at y=31, and a one-pixel diagonal between them. The top and bottom
; rows make the drawn height readable straight off the PNG.
BITMAP:
.byte 0FFh, 0FFh, 0FFh, 0FFh, 002h, 000h, 000h, 000h
.byte 004h, 000h, 000h, 000h, 008h, 000h, 000h, 000h
.byte 010h, 000h, 000h, 000h, 020h, 000h, 000h, 000h
.byte 040h, 000h, 000h, 000h, 080h, 000h, 000h, 000h
.byte 000h, 001h, 000h, 000h, 000h, 002h, 000h, 000h
.byte 000h, 004h, 000h, 000h, 000h, 008h, 000h, 000h
.byte 000h, 010h, 000h, 000h, 000h, 020h, 000h, 000h
.byte 000h, 040h, 000h, 000h, 000h, 080h, 000h, 000h
.byte 000h, 000h, 001h, 000h, 000h, 000h, 002h, 000h
.byte 000h, 000h, 004h, 000h, 000h, 000h, 008h, 000h
.byte 000h, 000h, 010h, 000h, 000h, 000h, 020h, 000h
.byte 000h, 000h, 040h, 000h, 000h, 000h, 080h, 000h
.byte 000h, 000h, 000h, 001h, 000h, 000h, 000h, 002h
.byte 000h, 000h, 000h, 004h, 000h, 000h, 000h, 008h
.byte 000h, 000h, 000h, 010h, 000h, 000h, 000h, 020h
.byte 000h, 000h, 000h, 040h, 0FFh, 0FFh, 0FFh, 0FFh
BITMAP_END:
.bss m_stage, 32, 1
.bss m_display, 32, 1
.bss m_window, 32, 1
.bss m_gc, 32, 1
.bss m_image, 32, 1
.bss m_putret, 32, 1
.bss m_syncret, 32, 1
.bss m_strlen, 32, 1
.end
+301
View File
@@ -0,0 +1,301 @@
-- xshow.lua -- run dwt/gui/build/xshow.coff through the COFF loader and report
-- whether the 1-bit XImage reached the screen.
--
-- Same debugger-assisted path as dwt/loader/loader.lua (no network, no rdebug,
-- no sudo): at frame XSHOW_AT it pokes the loader at bit 0x01880000, the COFF
-- at XSHOW_BUF (default 0x01900000), the descriptor at 0x01882C00, and sets
-- PC = 0x01880000. The loader copies the sections and calls create_process().
--
-- Env:
-- XSHOW_AT injection frame (default 2500)
-- XSHOW_END inspection/exit frame (default 2700)
-- XSHOW_SNAP frame to snapshot (default XSHOW_END)
-- XSHOW_COFF COFF (default dwt/gui/build/xshow.coff)
-- XSHOW_BIN loader payload (default dwt/loader/build/loader.bin)
-- XSHOW_BUF COFF buffer bit address (default 0x01900000)
-- XSHOW_OUT evidence dir (default dwt/gui/evidence)
-- XSHOW_NOSNAP 1 = do not write a PNG
--
-- Marker cells (the payload writes both blocks):
-- 01890100/120/140/160/180/1A0/1C0 xhello-compatible cells (heap; may be
-- overwritten after the app finishes)
-- 018D8000/20/40/60/80/A0/C0/E0 .bss mirror: stage, display, window,
-- gc, image, putret, syncret, strlen
local function hex(v, w) return string.format("%0" .. (w or 8) .. "X", v) end
local machine = manager.machine
local cpu = machine.devices[':maincpu']
local dbg = machine.debugger
local prog = cpu.spaces['program']
if not dbg then
print("XSHOW: debugger not enabled; pass -debug")
machine:exit()
return
end
local AT = tonumber(os.getenv("XSHOW_AT") or "2500")
local ENDF = tonumber(os.getenv("XSHOW_END") or "2700")
local SNAP = tonumber(os.getenv("XSHOW_SNAP") or tostring(ENDF))
local BIN = os.getenv("XSHOW_BIN") or "dwt/loader/build/loader.bin"
local COFF = os.getenv("XSHOW_COFF") or "dwt/gui/build/xshow.coff"
local BUF = tonumber(os.getenv("XSHOW_BUF") or "0x01900000")
local OUT = os.getenv("XSHOW_OUT") or "dwt/gui/evidence"
local NOSNAP = os.getenv("XSHOW_NOSNAP") == "1"
local LOADER_BASE = 0x01880000
local DESC = 0x01882C00
local RESULT = 0x01882D00
local function slurp(p)
local f, err = io.open(p, "rb")
if not f then error("cannot open " .. p .. ": " .. tostring(err)) end
local s = f:read("*a")
f:close()
return s
end
local function u16(s, o)
return s:byte(o + 1) + s:byte(o + 2) * 256
end
local function u32(s, o)
return s:byte(o + 1) + s:byte(o + 2) * 256
+ s:byte(o + 3) * 65536 + s:byte(o + 4) * 16777216
end
local function parse_coff(d)
local c = { data = d }
c.magic = u16(d, 0)
c.nscns = u16(d, 2)
c.opthdr = u16(d, 16)
c.sections = {}
if c.opthdr > 0 then
c.optmagic = u16(d, 20)
c.entry = u32(d, 20 + 16)
c.textstart = u32(d, 20 + 20)
c.datastart = u32(d, 20 + 24)
end
local base = 20 + c.opthdr
for i = 0, c.nscns - 1 do
local o = base + i * 40
local name = d:sub(o + 1, o + 8):gsub("%z", "")
c.sections[#c.sections + 1] = {
name = name,
paddr = u32(d, o + 8),
size = u32(d, o + 16), -- bits
scnptr = u32(d, o + 20),
flags = u32(d, o + 36),
}
end
return c
end
local function poke_bytes(bitaddr, data)
local n = math.floor((#data + 1) / 2)
for i = 0, n - 1 do
local lo = data:byte(i * 2 + 1) or 0
local hi = data:byte(i * 2 + 2) or 0
prog:write_u16(bitaddr + i * 16, lo + hi * 256)
end
return n
end
local function verify_bytes(bitaddr, data)
local n = math.floor((#data + 1) / 2)
local bad = 0
for i = 0, n - 1 do
local lo = data:byte(i * 2 + 1) or 0
local hi = data:byte(i * 2 + 2) or 0
if prog:read_u16(bitaddr + i * 16) ~= lo + hi * 256 then
bad = bad + 1
end
end
return n, bad
end
local function w32(a, v) prog:write_u32(a, v) end
local function r32(a)
local ok, v = pcall(function() return prog:read_u32(a) end)
if ok then return v end
return 0xDEADBEEF
end
local loader = slurp(BIN)
local coff = slurp(COFF)
local app = parse_coff(coff)
print(string.format("XSHOW: payload %s (%d B) -> bit %s", BIN, #loader, hex(LOADER_BASE)))
print(string.format("XSHOW: COFF %s (%d B) -> bit %s", COFF, #coff, hex(BUF)))
print(string.format("XSHOW: file magic=%04X nscns=%d opthdr=%d entry=%s textstart=%s",
app.magic, app.nscns, app.opthdr, hex(app.entry or 0), hex(app.textstart or 0)))
for _, s in ipairs(app.sections) do
print(string.format("XSHOW: sec %-8s paddr=%s size=%d bits (%d B) flags=%#x",
s.name, hex(s.paddr), s.size, math.floor(s.size / 8), s.flags))
end
-- The .data bytes the probe will hand to XCreateImage, read out of the COFF.
for _, s in ipairs(app.sections) do
if s.name == ".data" and s.scnptr ~= 0 and s.size > 0 then
local nb = math.floor(s.size / 8)
local bytes = coff:sub(s.scnptr + 1, s.scnptr + nb)
local first = {}
for i = 1, math.min(16, #bytes) do first[#first + 1] = string.format("%02X", bytes:byte(i)) end
print(string.format("XSHOW: .data first %d bytes: %s", #first, table.concat(first, " ")))
end
end
local frames = 0
local injected = false
local inspected = false
local snapped = false
local function markers()
return {
stage = r32(0x01890140),
display = r32(0x01890100),
window = r32(0x01890120),
image = r32(0x01890160),
gc = r32(0x01890180),
putret = r32(0x018901A0),
syncret = r32(0x018901C0),
}
end
local function mirror()
return {
stage = r32(0x018D8000),
display = r32(0x018D8020),
window = r32(0x018D8040),
gc = r32(0x018D8060),
image = r32(0x018D8080),
putret = r32(0x018D80A0),
syncret = r32(0x018D80C0),
strlen = r32(0x018D80E0),
}
end
local function report(tag)
local m = markers()
local r = mirror()
print(string.format(
"XSHOW: %s cells stage=%s display=%s window=%s gc=%s image=%s putret=%s syncret=%s",
tag, hex(m.stage), hex(m.display), hex(m.window), hex(m.gc), hex(m.image),
hex(m.putret), hex(m.syncret)))
print(string.format(
"XSHOW: %s mirror stage=%s display=%s window=%s gc=%s image=%s putret=%s syncret=%s strlen=%s",
tag, hex(r.stage), hex(r.display), hex(r.window), hex(r.gc), hex(r.image),
hex(r.putret), hex(r.syncret), hex(r.strlen)))
end
-- Dump the XImage fields the ROM's own code reads (byte offsets are the
-- standard 32-bit XImage layout; 0x120/0x140/0x160 = depth/bpl/bpp).
local IMG_FIELDS = {
{ "width", 0x000 }, { "height", 0x020 }, { "xoffset", 0x040 },
{ "format", 0x060 }, { "data", 0x080 }, { "byte_order", 0x0A0 },
{ "bitmap_unit", 0x0C0 }, { "bitmap_bit_order", 0x0E0 },
{ "bitmap_pad", 0x100 }, { "depth", 0x120 }, { "bytes_per_line", 0x140 },
{ "bits_per_pixel", 0x160 },
}
local function dump_image(ptr, tag)
if ptr == 0 then return end
local parts = {}
for _, f in ipairs(IMG_FIELDS) do
parts[#parts + 1] = string.format("%s=%s", f[1], hex(r32(ptr + f[2])))
end
print(string.format("XSHOW: %s image@%s %s", tag, hex(ptr), table.concat(parts, " ")))
end
local function dump_dpy(ptr, tag)
if ptr == 0 then return end
print(string.format(
"XSHOW: %s dpy@%s byte_order=%s bitmap_unit=%s scanline_pad=%s bitmap_bit_order=%s",
tag, hex(ptr), hex(r32(ptr + 0x1A0)), hex(r32(ptr + 0x1C0)),
hex(r32(ptr + 0x1E0)), hex(r32(ptr + 0x200))))
-- XPutImage's bits_per_pixel check walks dpy->pixmap_formats: count at
-- +0x220, pointer at +0x240, entry stride 0x80 bits, depth at +0x20,
-- bits_per_pixel at +0x40.
local n = r32(ptr + 0x220)
local list = r32(ptr + 0x240)
print(string.format("XSHOW: %s pixmap_formats n=%d list=%s", tag, n, hex(list)))
for i = 0, math.min(n, 8) - 1 do
local e = list + i * 0x80
print(string.format("XSHOW: %s fmt[%d] depth=%s bits_per_pixel=%s pad=%s",
tag, i, hex(r32(e + 0x20)), hex(r32(e + 0x40)), hex(r32(e + 0x60))))
end
end
local function inject()
poke_bytes(LOADER_BASE, loader)
local _, bad = verify_bytes(LOADER_BASE, loader)
print(string.format("XSHOW: loader poked %d words, readback %d bad at %s",
math.floor((#loader + 1) / 2), bad, hex(LOADER_BASE)))
poke_bytes(BUF, coff)
local _, cbad = verify_bytes(BUF, coff)
print(string.format("XSHOW: COFF poked %d words, readback %d bad at %s",
math.floor((#coff + 1) / 2), cbad, hex(BUF)))
w32(DESC + 0x00, 0)
prog:write_u16(DESC + 0x00, 0x4C44) -- "LD"
prog:write_u16(DESC + 0x10, 0x5231) -- "R1"
w32(DESC + 0x20, BUF)
w32(DESC + 0x40, #coff)
w32(DESC + 0x60, 0) -- mode 0: debug-resume
print(string.format("XSHOW: descriptor @%s magic=%04X/%04X buf=%s len=%d mode=%d",
hex(DESC), prog:read_u16(DESC + 0x00), prog:read_u16(DESC + 0x10),
hex(r32(DESC + 0x20)), r32(DESC + 0x40), r32(DESC + 0x60)))
local orig_pc = cpu.state['PC'].value
w32(0x01882A20, orig_pc) -- LD_ORIG_PC
print(string.format("XSHOW: will resume at %s after create_process", hex(orig_pc)))
cpu.state['A8'].value = 0
cpu.state['PC'].value = LOADER_BASE
injected = true
print(string.format("XSHOW: frame %d: entered loader at %s (caller SP=%s)",
frames, hex(LOADER_BASE), hex(cpu.state['SP'].value)))
end
local function snapshot(path)
local screen = nil
for _, s in pairs(machine.screens) do screen = s break end
if not screen then
print("XSHOW: no screen device")
return
end
local ok, err = pcall(function() return screen:snapshot(path) end)
print(string.format("XSHOW: snapshot %s ok=%s %s", path, tostring(ok), tostring(err or "")))
end
emu.register_frame_done(function()
frames = frames + 1
if frames == AT and not injected then inject() end
if injected and not inspected and frames >= AT + 40 then
inspected = true
report("f" .. frames)
end
if injected and frames == SNAP and not snapped then
snapped = true
report("f" .. frames)
if not NOSNAP then snapshot(OUT .. "/xshow_frame" .. frames .. ".png") end
end
if frames >= ENDF then
if injected then
report("final")
local st = r32(RESULT + 0x000)
print(string.format("XSHOW: loader status=%d entry=%s text=%s/%d bits",
st, hex(r32(RESULT + 0x020)),
hex(r32(RESULT + 0x040)), r32(RESULT + 0x060)))
print(string.format("XSHOW: PC at exit = %s", hex(cpu.state['PC'].value)))
local m = markers()
dump_image(m.image, "final")
dump_dpy(m.display, "final")
end
machine:exit()
end
end, "vt1200-xshow")
dbg.visible_cpu = cpu
dbg.execution_state = 'run'
Binary file not shown.
Binary file not shown.
+626
View File
@@ -0,0 +1,626 @@
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 1
0001 ; xshow.asm -- create a 1-bit XImage and XPutImage it o
0002 ;
0003 ; Run as a first-class process created by the COFF load
0004 ; in the rdebug dispatcher's context: a connect made fr
0005 ; accepted at the service layer but the server never re
0006 ;
0007 ; The image is a 32x32 XYBitmap (format 0), depth 1, cr
0008 ; XCreateImage and drawn with XPutImage. Its data is a
0009 ; cells, written into .data at build time, so the PNG s
0010 ; or nothing -- there is nothing to misread.
0011 ;
0012 ; XImage entry points used here (Ghidra address -> bit
0013 ; 7F34092 XCreateImage(d,visual,depth,format,offset,d
0014 ; 7FA06E XPutImage(d,drawable,gc,image,sx,sy,dx,dy,w
0015 ; 7F341B0 XDestroyImage(image)
0016 ; 7FAAAD6 XGetImage(d,drawable,x,y,w,h,plane_mask,for
0017 ; (XGetImage is documented from disassembly; this probe
0018 ;
0019 ; Calling convention: reserve one slot with `move a14,-
0020 ; last-to-first upward through a14, then `calla`. The
0021 ; the return address and the reserved slot, and restore
0022 ; sp/a14 from RAM markers (xtext.asm records that exact
0023 ;
0024 ; Xlib clobbers the CPU's SETF field state, so field 1
0025 ; established after every call. a10/a11/a12 survive ev
0026 ; a9 (the GC) survives XCreateImage and XPutImage; a7 (
0027 ; XPutImage. XDestroyImage saves only a11/a13, so it r
0028 ;
0029 ; Markers:
0030 ; 01890100 display 01890120 window 01890140 stage
0031 ; 01890180 gc 018901A0 XPutImage return 01
0032 ; These are the xhello-compatible cells the runner repo
0033 ; cells sit in the heap and were overwritten after its
0034 ; are mirrored into .bss at 018D8000h (below), which no
0035 ; 018D8000 stage 018D8020 display 018D8040 window
0036 ; 018D8080 image 018D80A0 putret 018D80C0 syncret
0037 ; Stage: 1 start, 2 display, 3 window, 4 mapped, 5 gc,
0038 ; 8 synced; 091h..097h = the step that failed.
0039 ;
0040 ; Scratch argument area: 01894000h (the app's own stack
0041
0042 00000000 .text
0043 00000000 _start:
0044 00000000 0550 setf 16, 0, 0
0045 00000010 0740 setf 32, 0, 1
0046 00000020 098F mmtm sp, a0,a1,a2,a3,a4,a5,a6,a7
00000030 FF00
0047
0048 00000040 09E0 movi 1, a0, L
00000050 00000001
0049 00000070 0780 move a0, @01890140h, 1 ; stage = 1
00000080 01890140
0050 000000A0 0780 move a0, @m_stage, 1
000000B0 00000000+
0051
0052 ; ---- convention check: strlen("0::0") == 4 ---------
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 2
0053 000000D0 A3CF move a14, -*sp, 1
0054 000000E0 09EE movi 01894000h, a14, L
000000F0 01894000
0055 00000110 09E0 movi 3FACE948h, a0, L ; ROM "0::0"
00000120 3FACE948
0056 00000140 920E move a0, *a14+, 1
0057 00000150 0D5F calla 3FB458D0h ; strlen
00000160 3FB458D0
0058 00000180 0550 setf 16, 0, 0
0059 00000190 0740 setf 32, 0, 1
0060 000001A0 0788 move a8, @m_strlen, 1
000001B0 000000E0+
0061 000001D0 09E0 movi 4, a0, L
000001E0 00000004
0062 00000200 4808 cmp a0, a8
0063 00000210 CB00 jrne fail_abi
00000220 0171
0064
0065 ; ---- display = XOpenDisplay("0::0") ----------------
0066 00000230 A3CF move a14, -*sp, 1
0067 00000240 09EE movi 01894000h, a14, L
00000250 01894000
0068 00000270 09E0 movi 3FACE948h, a0, L
00000280 3FACE948
0069 000002A0 920E move a0, *a14+, 1
0070 000002B0 0D5F calla 3F9C2570h ; XOpenDisplay
000002C0 3F9C2570
0071 000002E0 0550 setf 16, 0, 0
0072 000002F0 0740 setf 32, 0, 1
0073 00000300 4D0B move a8, a11
0074 00000310 078B move a11, @01890100h, 1 ; MARK display
00000320 01890100
0075 00000340 078B move a11, @m_display, 1
00000350 00000020+
0076 00000370 4D6B move a11, a11
0077 00000380 CA00 jreq fail_open
00000390 015E
0078 000003A0 09E0 movi 2, a0, L
000003B0 00000002
0079 000003D0 0780 move a0, @01890140h, 1 ; stage = 2
000003E0 01890140
0080 00000400 0780 move a0, @m_stage, 1
00000410 00000000+
0081
0082 ; ---- root = *(*(display+0x480)+0x40) ---------------
0083 00000430 B76A move *a11(0480h), a10, 1
00000440 0480
0084 00000450 B74A move *a10(040h), a10, 1
00000460 0040
0085
0086 ; ---- window = XCreateSimpleWindow(d,root,100,100,400
0087 ; white background (pixel 1), black border, so a black
0088 00000470 A3CF move a14, -*sp, 1
0089 00000480 09EE movi 01894000h, a14, L
00000490 01894000
0090 000004B0 09E0 movi 1, a0, L
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 3
000004C0 00000001
0091 000004E0 920E move a0, *a14+, 1 ; background = 1 (white)
0092 000004F0 09E0 movi 0, a0, L
00000500 00000000
0093 00000520 920E move a0, *a14+, 1 ; border = 0 (black)
0094 00000530 09E0 movi 2, a0, L
00000540 00000002
0095 00000560 920E move a0, *a14+, 1 ; border width
0096 00000570 09E0 movi 200, a0, L
00000580 000000C8
0097 000005A0 920E move a0, *a14+, 1 ; height
0098 000005B0 09E0 movi 400, a0, L
000005C0 00000190
0099 000005E0 920E move a0, *a14+, 1 ; width
0100 000005F0 09E0 movi 100, a0, L
00000600 00000064
0101 00000620 920E move a0, *a14+, 1 ; y
0102 00000630 920E move a0, *a14+, 1 ; x
0103 00000640 934E move a10, *a14+, 1 ; parent = root
0104 00000650 936E move a11, *a14+, 1 ; display
0105 00000660 0D5F calla 3FD41B90h ; XCreateSimpleWindow
00000670 3FD41B90
0106 00000690 0550 setf 16, 0, 0
0107 000006A0 0740 setf 32, 0, 1
0108 000006B0 4D0A move a8, a10
0109 000006C0 078A move a10, @01890120h, 1 ; MARK window
000006D0 01890120
0110 000006F0 078A move a10, @m_window, 1
00000700 00000040+
0111 00000720 4D4A move a10, a10
0112 00000730 CA00 jreq fail_win
00000740 0127
0113 00000750 09E0 movi 3, a0, L
00000760 00000003
0114 00000780 0780 move a0, @01890140h, 1 ; stage = 3
00000790 01890140
0115 000007B0 0780 move a0, @m_stage, 1
000007C0 00000000+
0116
0117 ; ---- XMapWindow(display, window) -------------------
0118 000007E0 A3CF move a14, -*sp, 1
0119 000007F0 09EE movi 01894000h, a14, L
00000800 01894000
0120 00000820 934E move a10, *a14+, 1
0121 00000830 936E move a11, *a14+, 1
0122 00000840 0D5F calla 3FD645B0h ; XMapWindow
00000850 3FD645B0
0123 00000870 0550 setf 16, 0, 0
0124 00000880 0740 setf 32, 0, 1
0125 00000890 09E0 movi 4, a0, L
000008A0 00000004
0126 000008C0 0780 move a0, @01890140h, 1 ; stage = 4
000008D0 01890140
0127 000008F0 0780 move a0, @m_stage, 1
00000900 00000000+
0128
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 4
0129 ; ---- gc = XCreateGC(d, window, 0, NULL) ------------
0130 00000920 A3CF move a14, -*sp, 1
0131 00000930 09EE movi 01894000h, a14, L
00000940 01894000
0132 00000960 09E0 movi 0, a0, L
00000970 00000000
0133 00000990 920E move a0, *a14+, 1 ; values
0134 000009A0 920E move a0, *a14+, 1 ; mask = 0
0135 000009B0 934E move a10, *a14+, 1 ; drawable
0136 000009C0 936E move a11, *a14+, 1 ; display
0137 000009D0 0D5F calla 3F997000h ; XCreateGC
000009E0 3F997000
0138 00000A00 0550 setf 16, 0, 0
0139 00000A10 0740 setf 32, 0, 1
0140 00000A20 4D09 move a8, a9 ; GC
0141 00000A30 0789 move a9, @01890180h, 1 ; MARK gc
00000A40 01890180
0142 00000A60 0789 move a9, @m_gc, 1
00000A70 00000060+
0143 00000A90 4D29 move a9, a9
0144 00000AA0 CA00 jreq fail_gc
00000AB0 00F4
0145
0146 ; ---- XSetForeground(display, gc, 0) -- draw with pen
0147 00000AC0 A3CF move a14, -*sp, 1
0148 00000AD0 09EE movi 01894000h, a14, L
00000AE0 01894000
0149 00000B00 09E0 movi 0, a0, L
00000B10 00000000
0150 00000B30 920E move a0, *a14+, 1 ; pixel = 0
0151 00000B40 932E move a9, *a14+, 1 ; gc
0152 00000B50 936E move a11, *a14+, 1 ; display
0153 00000B60 0D5F calla 3FD99A60h ; XSetForeground
00000B70 3FD99A60
0154 00000B90 0550 setf 16, 0, 0
0155 00000BA0 0740 setf 32, 0, 1
0156 00000BB0 09E0 movi 5, a0, L
00000BC0 00000005
0157 00000BE0 0780 move a0, @01890140h, 1 ; stage = 5
00000BF0 01890140
0158 00000C10 0780 move a0, @m_stage, 1
00000C20 00000000+
0159
0160 ; ---- image = XCreateImage(d, NULL, 1, XYBitmap, 0,
0161 ; bitmap, 32, 32, 32, 0) ---
0162 00000C40 A3CF move a14, -*sp, 1
0163 00000C50 09EE movi 01894000h, a14, L
00000C60 01894000
0164 00000C80 09E0 movi 0, a0, L
00000C90 00000000
0165 00000CB0 920E move a0, *a14+, 1 ; bytes_per_line = 0 (let it comput
0166 00000CC0 09E0 movi 32, a0, L
00000CD0 00000020
0167 00000CF0 920E move a0, *a14+, 1 ; bitmap_pad = 32
0168 00000D00 09E0 movi 32, a0, L
00000D10 00000020
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 5
0169 00000D30 920E move a0, *a14+, 1 ; height
0170 00000D40 920E move a0, *a14+, 1 ; width
0171 00000D50 09E0 movi BITMAP, a0, L
00000D60 00000000"
0172 00000D80 920E move a0, *a14+, 1 ; data
0173 00000D90 09E0 movi 0, a0, L
00000DA0 00000000
0174 00000DC0 920E move a0, *a14+, 1 ; offset
0175 00000DD0 920E move a0, *a14+, 1 ; format = 0 (XYBitmap)
0176 00000DE0 09E0 movi 1, a0, L
00000DF0 00000001
0177 00000E10 920E move a0, *a14+, 1 ; depth = 1
0178 00000E20 4400 sub a0, a0
0179 00000E30 920E move a0, *a14+, 1 ; visual = NULL
0180 00000E40 936E move a11, *a14+, 1 ; display
0181 00000E50 0D5F calla 3F9A0490h ; XCreateImage
00000E60 3F9A0490
0182 00000E80 0550 setf 16, 0, 0
0183 00000E90 0740 setf 32, 0, 1
0184 00000EA0 4D07 move a8, a7 ; image (a7 survives XPutImage)
0185 00000EB0 0788 move a8, @01890160h, 1 ; MARK image
00000EC0 01890160
0186 00000EE0 0788 move a8, @m_image, 1
00000EF0 00000080+
0187 00000F10 4D08 move a8, a8
0188 00000F20 CA00 jreq fail_img
00000F30 00B0
0189 00000F40 09E0 movi 6, a0, L
00000F50 00000006
0190 00000F70 0780 move a0, @01890140h, 1 ; stage = 6
00000F80 01890140
0191 00000FA0 0780 move a0, @m_stage, 1
00000FB0 00000000+
0192
0193 ; ---- let the WM frame/reparent and map the window (x
0194 ; A draw issued before the reparent can be lost, so sy
0195 00000FD0 09EC movi 4, a12, L
00000FE0 00000004
0196 00001000 map_wait:
0197 00001000 A3CF move a14, -*sp, 1
0198 00001010 09EE movi 01894000h, a14, L
00001020 01894000
0199 00001040 09E0 movi 0, a0, L
00001050 00000000
0200 00001070 920E move a0, *a14+, 1 ; discard = 0
0201 00001080 936E move a11, *a14+, 1 ; display
0202 00001090 0D5F calla 3FD9F6B0h ; XSync
000010A0 3FD9F6B0
0203 000010C0 0550 setf 16, 0, 0
0204 000010D0 0740 setf 32, 0, 1
0205 000010E0 3DEC dsjs a12, map_wait
0206
0207 ; ---- XPutImage(d, win, gc, image, 0,0, 20,20, 32,32)
0208 000010F0 A3CF move a14, -*sp, 1
0209 00001100 09EE movi 01894000h, a14, L
00001110 01894000
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 6
0210 00001130 09E0 movi 32, a0, L
00001140 00000020
0211 00001160 920E move a0, *a14+, 1 ; h
0212 00001170 920E move a0, *a14+, 1 ; w
0213 00001180 09E0 movi 20, a0, L
00001190 00000014
0214 000011B0 920E move a0, *a14+, 1 ; dst_y
0215 000011C0 920E move a0, *a14+, 1 ; dst_x
0216 000011D0 4400 sub a0, a0
0217 000011E0 920E move a0, *a14+, 1 ; src_y
0218 000011F0 920E move a0, *a14+, 1 ; src_x
0219 00001200 92EE move a7, *a14+, 1 ; image
0220 00001210 932E move a9, *a14+, 1 ; gc
0221 00001220 934E move a10, *a14+, 1 ; drawable
0222 00001230 936E move a11, *a14+, 1 ; display
0223 00001240 0D5F calla 3F9D0370h ; XPutImage
00001250 3F9D0370
0224 00001270 0550 setf 16, 0, 0
0225 00001280 0740 setf 32, 0, 1
0226 00001290 0788 move a8, @018901A0h, 1 ; MARK putimage return
000012A0 018901A0
0227 000012C0 0788 move a8, @m_putret, 1
000012D0 000000A0+
0228 000012F0 09E0 movi 7, a0, L
00001300 00000007
0229 00001320 0780 move a0, @01890140h, 1 ; stage = 7
00001330 01890140
0230 00001350 0780 move a0, @m_stage, 1
00001360 00000000+
0231
0232 ; ---- control: the same image with h = 16 at dst_y =
0233 ; The PNG must show exactly 16 rows here (src rows 0..
0234 ; what proves the 32-row draw above is the image, not
0235 00001380 A3CF move a14, -*sp, 1
0236 00001390 09EE movi 01894000h, a14, L
000013A0 01894000
0237 000013C0 09E0 movi 16, a0, L
000013D0 00000010
0238 000013F0 920E move a0, *a14+, 1 ; h = 16
0239 00001400 09E0 movi 32, a0, L
00001410 00000020
0240 00001430 920E move a0, *a14+, 1 ; w = 32
0241 00001440 09E0 movi 60, a0, L
00001450 0000003C
0242 00001470 920E move a0, *a14+, 1 ; dst_y = 60
0243 00001480 09E0 movi 20, a0, L
00001490 00000014
0244 000014B0 920E move a0, *a14+, 1 ; dst_x = 20
0245 000014C0 4400 sub a0, a0
0246 000014D0 920E move a0, *a14+, 1 ; src_y = 0
0247 000014E0 920E move a0, *a14+, 1 ; src_x = 0
0248 000014F0 92EE move a7, *a14+, 1 ; image
0249 00001500 932E move a9, *a14+, 1 ; gc
0250 00001510 934E move a10, *a14+, 1 ; drawable
0251 00001520 936E move a11, *a14+, 1 ; display
0252 00001530 0D5F calla 3F9D0370h ; XPutImage
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 7
00001540 3F9D0370
0253 00001560 0550 setf 16, 0, 0
0254 00001570 0740 setf 32, 0, 1
0255
0256 ; ---- flush, twice: the request is only in the client
0257 00001580 A3CF move a14, -*sp, 1
0258 00001590 09EE movi 01894000h, a14, L
000015A0 01894000
0259 000015C0 09E0 movi 0, a0, L
000015D0 00000000
0260 000015F0 920E move a0, *a14+, 1
0261 00001600 936E move a11, *a14+, 1
0262 00001610 0D5F calla 3FD9F6B0h ; XSync
00001620 3FD9F6B0
0263 00001640 0550 setf 16, 0, 0
0264 00001650 0740 setf 32, 0, 1
0265 00001660 0788 move a8, @018901C0h, 1 ; MARK sync return
00001670 018901C0
0266 00001690 0788 move a8, @m_syncret, 1
000016A0 000000C0+
0267
0268 000016C0 A3CF move a14, -*sp, 1
0269 000016D0 09EE movi 01894000h, a14, L
000016E0 01894000
0270 00001700 09E0 movi 0, a0, L
00001710 00000000
0271 00001730 920E move a0, *a14+, 1
0272 00001740 936E move a11, *a14+, 1
0273 00001750 0D5F calla 3FD9F6B0h ; XSync
00001760 3FD9F6B0
0274 00001780 0550 setf 16, 0, 0
0275 00001790 0740 setf 32, 0, 1
0276 000017A0 0788 move a8, @018901C0h, 1
000017B0 018901C0
0277 000017D0 0788 move a8, @m_syncret, 1
000017E0 000000C0+
0278
0279 00001800 09E0 movi 8, a0, L
00001810 00000008
0280 00001830 0780 move a0, @01890140h, 1 ; stage = 8
00001840 01890140
0281 00001860 0780 move a0, @m_stage, 1
00001870 00000000+
0282
0283 ; ---- XDestroyImage(image) --------------------------
0284 00001890 A3CF move a14, -*sp, 1
0285 000018A0 09EE movi 01894000h, a14, L
000018B0 01894000
0286 000018D0 92EE move a7, *a14+, 1
0287 000018E0 0D5F calla 3F9A0D80h ; XDestroyImage
000018F0 3F9A0D80
0288 00001910 0550 setf 16, 0, 0
0289 00001920 0740 setf 32, 0, 1
0290 00001930 C01A jruc done
0291
0292 00001940 fail_abi:
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 8
0293 00001940 09E0 movi 091h, a0, L
00001950 00000091
0294 00001970 C010 jruc failed
0295 00001980 fail_open:
0296 00001980 09E0 movi 092h, a0, L
00001990 00000092
0297 000019B0 C00C jruc failed
0298 000019C0 fail_win:
0299 000019C0 09E0 movi 093h, a0, L
000019D0 00000093
0300 000019F0 C008 jruc failed
0301 00001A00 fail_gc:
0302 00001A00 09E0 movi 095h, a0, L
00001A10 00000095
0303 00001A30 C004 jruc failed
0304 00001A40 fail_img:
0305 00001A40 09E0 movi 096h, a0, L
00001A50 00000096
0306 00001A70 0300 jruc failed
0307 00001A80 failed:
0308 00001A80 0780 move a0, @01890140h, 1
00001A90 01890140
0309 00001AB0 0780 move a0, @m_stage, 1
00001AC0 00000000+
0310
0311 00001AE0 done:
0312 00001AE0 09AF mmfm sp, a0,a1,a2,a3,a4,a5,a6,a7
00001AF0 00FF
0313 00001B00 09E8 movi 0, a8, L
00001B10 00000000
0314 00001B30 0960 rets
0315
0316 00000000 .data
0317 ; 32 rows of 4 bytes, LSB-first pixels: a solid row at
0318 ; at y=31, and a one-pixel diagonal between them. The
0319 ; rows make the drawn height readable straight off the
0320 00000000 BITMAP:
0321 00000000 FF .byte 0FFh, 0FFh, 0FFh, 0FFh, 002h, 000h, 000h, 000h
00000008 FF
00000010 FF
00000018 FF
00000020 02
00000028 00
00000030 00
00000038 00
0322 00000040 04 .byte 004h, 000h, 000h, 000h, 008h, 000h, 000h, 000h
00000048 00
00000050 00
00000058 00
00000060 08
00000068 00
00000070 00
00000078 00
0323 00000080 10 .byte 010h, 000h, 000h, 000h, 020h, 000h, 000h, 000h
00000088 00
00000090 00
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 9
00000098 00
000000A0 20
000000A8 00
000000B0 00
000000B8 00
0324 000000C0 40 .byte 040h, 000h, 000h, 000h, 080h, 000h, 000h, 000h
000000C8 00
000000D0 00
000000D8 00
000000E0 80
000000E8 00
000000F0 00
000000F8 00
0325 00000100 00 .byte 000h, 001h, 000h, 000h, 000h, 002h, 000h, 000h
00000108 01
00000110 00
00000118 00
00000120 00
00000128 02
00000130 00
00000138 00
0326 00000140 00 .byte 000h, 004h, 000h, 000h, 000h, 008h, 000h, 000h
00000148 04
00000150 00
00000158 00
00000160 00
00000168 08
00000170 00
00000178 00
0327 00000180 00 .byte 000h, 010h, 000h, 000h, 000h, 020h, 000h, 000h
00000188 10
00000190 00
00000198 00
000001A0 00
000001A8 20
000001B0 00
000001B8 00
0328 000001C0 00 .byte 000h, 040h, 000h, 000h, 000h, 080h, 000h, 000h
000001C8 40
000001D0 00
000001D8 00
000001E0 00
000001E8 80
000001F0 00
000001F8 00
0329 00000200 00 .byte 000h, 000h, 001h, 000h, 000h, 000h, 002h, 000h
00000208 00
00000210 01
00000218 00
00000220 00
00000228 00
00000230 02
00000238 00
0330 00000240 00 .byte 000h, 000h, 004h, 000h, 000h, 000h, 008h, 000h
00000248 00
00000250 04
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 10
00000258 00
00000260 00
00000268 00
00000270 08
00000278 00
0331 00000280 00 .byte 000h, 000h, 010h, 000h, 000h, 000h, 020h, 000h
00000288 00
00000290 10
00000298 00
000002A0 00
000002A8 00
000002B0 20
000002B8 00
0332 000002C0 00 .byte 000h, 000h, 040h, 000h, 000h, 000h, 080h, 000h
000002C8 00
000002D0 40
000002D8 00
000002E0 00
000002E8 00
000002F0 80
000002F8 00
0333 00000300 00 .byte 000h, 000h, 000h, 001h, 000h, 000h, 000h, 002h
00000308 00
00000310 00
00000318 01
00000320 00
00000328 00
00000330 00
00000338 02
0334 00000340 00 .byte 000h, 000h, 000h, 004h, 000h, 000h, 000h, 008h
00000348 00
00000350 00
00000358 04
00000360 00
00000368 00
00000370 00
00000378 08
0335 00000380 00 .byte 000h, 000h, 000h, 010h, 000h, 000h, 000h, 020h
00000388 00
00000390 00
00000398 10
000003A0 00
000003A8 00
000003B0 00
000003B8 20
0336 000003C0 00 .byte 000h, 000h, 000h, 040h, 0FFh, 0FFh, 0FFh, 0FFh
000003C8 00
000003D0 00
000003D8 40
000003E0 FF
000003E8 FF
000003F0 FF
000003F8 FF
0337 00000400 BITMAP_END:
0338
0339 00000000 .bss m_stage, 32, 1
GSP COFF Assembler, Version 2.00, 87.300 Fri Nov 13 09:31:54 2026
(c) Copyright 1985, 1987, Texas Instruments Inc.
PAGE 11
0340 00000020 .bss m_display, 32, 1
0341 00000040 .bss m_window, 32, 1
0342 00000060 .bss m_gc, 32, 1
0343 00000080 .bss m_image, 32, 1
0344 000000A0 .bss m_putret, 32, 1
0345 000000C0 .bss m_syncret, 32, 1
0346 000000E0 .bss m_strlen, 32, 1
0347
0348 .end
No Errors, No Warnings
+36
View File
@@ -0,0 +1,36 @@
*****************************************************
GSP COFF Linker, Version 2.00, 87.300
*****************************************************
Fri Nov 13 09:31:54 2026
OUTPUT FILE NAME: <XSHOW.out>
ENTRY POINT SYMBOL: 0
SECTION ALLOCATION MAP
output attributes/
section page origin length input sections
-------- ---- ---------- ---------- ----------------
.text 0 01840000 00001B40
01840000 00001B40 XSHOW.obj (.text)
.data 0 018D0000 00000400
018D0000 00000400 XSHOW.obj (.data)
.bss 0 018D8000 00000100 UNINITIALIZED
018D8000 00000100 XSHOW.obj (.bss)
GLOBAL SYMBOLS
address name address name
-------- ---- -------- ----
018D8000 .bss 01840000 .text
018D0000 .data 01841B40 etext
01840000 .text 018D0000 .data
018D0400 edata 018D0400 edata
018D8100 end 018D8000 .bss
01841B40 etext 018D8100 end
[6 symbols]
Binary file not shown.
+166 -2
View File
@@ -108,6 +108,162 @@ tools/smart34010/dis34 -l -o -b 3FD645B0 -s 0x16C8B6 vt1200_v22.bin
(The `-s` values are file offsets: `(bit_address >> 3) - 0x07E40000`, the ROM's
byte base.)
#### 2.2.1 XImage — the bitmap path
The table above ends at the drawing calls. The image entry points are separate,
and none of them is a request except `XPutImage`/`XGetImage`; `XCreateImage` and
`XDestroyImage` are client-side. Addresses were derived by disassembling
`vt1200_v22.bin` with `tools/smart34010/dis34` and then confirmed live (see
§2.2.2). Bit addresses again; Ghidra = bits / 8.
| Xlib function | Ghidra | bits | shape seen |
|---|---|---|---|
| `XCreateImage(d,visual,depth,format,offset,data,w,h,bitmap_pad,bytes_per_line)` | `0x07F34092` | `0x3F9A0490` | 10 args; `calloc(1,0x58)` (0x3F703D90), fills the struct, `_XInitImageFuncPtrs` (0x3F9A6AA0) |
| `XPutImage(d,drawable,gc,image,src_x,src_y,dst_x,dst_y,w,h)` | `0x07F3A06E` | `0x3F9D0370` | 10 args; clips, checks `bits_per_pixel`, calls the workhorse below |
| `XDestroyImage(image)` | `0x07F341B0` | `0x3F9A0D80` | 1 arg; `free(image->data)`, `free(image->obdata)` if set, `free(image)` |
| `XGetImage(d,drawable,x,y,w,h,plane_mask,format)` | `0x07FAAAD6` | `0x3FD556B0` | 8 args; request opcode **73 (0x49)**, length 5 |
Supporting routines, named so a trace can be followed:
| routine | Ghidra | bits | what it is |
|---|---|---|---|
| PutImage request builder | `0x07F39D8E` | `0x3F9CEC70` | writes opcode **72 (0x48)** at request byte 0, length 6 at byte 2, `format = image->format` at byte 1, then drawable/gc/width/height/dst-x/dst-y/depth; dispatches the pixel copy |
| 1-bit pixel copier | `0x07F3965A` | `0x3F9CB2D0` | used when `depth == 1` **or** `format != ZPixmap`; appends the rows and bumps the request length |
| ZPixmap pixel copier | `0x07F39B18` | `0x3F9CD8C0` | used when `depth != 1` and `format == ZPixmap` |
| PutImage workhorse | `0x07F39E68` | `0x3F9CF340` | clipping, request-band splitting when the image does not fit the client buffer, then the request builder |
| `_XInitImageFuncPtrs` | `0x07F34D54` | `0x3F9A6AA0` | fills `image->f` (get_pixel at `image+0x200`, …) |
| image-field reporter | `0x07F34DA4` | `0x3F9A6D20` | prints `Bad image %s: %d found in routine: %s` (string `0x3F9A7348`) |
**Drift check.** Pin each name to its bytes before trusting the table (`-s` is
the file offset, `(bit_address >> 3) - 0x07E40000`):
```
tools/smart34010/dis34 -l -o -b 3F9D0370 -s 0xFA06E vt1200_v22.bin
# expect: mmtm sp, a5,a7,a9,a10,a11,a12,a13 -> XPutImage
tools/smart34010/dis34 -l -o -b 3F9CEE00 -s 0xF9DC0 vt1200_v22.bin
# expect: movi 0x48 (opcode 72), movb a7,*a11, movk 6 -> PutImage request
tools/smart34010/dis34 -l -o -b 3FD55830 -s 0x16AB06 vt1200_v22.bin
# expect: movi 0x49 (opcode 73), movb a11,*a10, movk 5 -> GetImage request
tools/smart34010/dis34 -l -o -b 3F9A0490 -s 0xF4092 vt1200_v22.bin
# expect: mmtm sp, a3,a5,a7,a9,a10,a11,a13 -> XCreateImage (movi 0x58 follows)
tools/smart34010/dis34 -l -o -b 3F9A0D80 -s 0xF41B0 vt1200_v22.bin
# expect: mmtm sp, a11,a13 -> XDestroyImage
```
**XImage layout.** 32-bit fields; byte offsets as the ROM writes them in
`XCreateImage`, and as read back from a live image in §2.2.2:
| off | field | off | field | off | field |
|---|---|---|---|---|---|
| `0x00` | width | `0x18` | bitmap_unit | `0x30` | red_mask |
| `0x04` | height | `0x1C` | bitmap_bit_order | `0x34` | green_mask |
| `0x08` | xoffset | `0x20` | bitmap_pad | `0x38` | blue_mask |
| `0x0C` | format | `0x24` | depth | `0x3C` | obdata |
| `0x10` | data | `0x28` | bytes_per_line | `0x40` | f.get_pixel … |
| `0x14` | byte_order | `0x2C` | bits_per_pixel | | |
**The format contract, from the code** (not from Xlib headers):
* `XCreateImage` **inherits the orders from the Display**: `image->byte_order =
*(dpy+0x1A0)`, `bitmap_unit = *(dpy+0x1C0)`, `bitmap_bit_order =
*(dpy+0x200)` (`0x3F9A0650`, `0x3F9A0680`, `0x3F9A06B0`). A client does not
have to know or guess them.
* `bits_per_pixel` starts at **1**. Only `format == ZPixmap (2)` replaces it, via
a lookup in the display's pixmap-format list (`dpy+0x220` count, `dpy+0x240`
pointer, entry stride `0x80` bits, depth at entry+`0x20`, bpp at entry+`0x40`;
no match falls back to `depth`). So **XYBitmap (0) and XYPixmap (1) are always
transported as 1 bit per pixel**, whatever `depth` says.
* `bytes_per_line` is computed from `width`/`offset`/`bitmap_pad` when the caller
passes 0 (`0x3F9A09C0`–`0x3F9A0C40`).
* `XCreateImage` itself rejects nothing — no depth, format or order check.
* `XPutImage` refuses exactly one case (`0x3F9D07B0`–`0x3F9D0B70`): `format ==
ZPixmap` **and** `depth != 1` **and** `image->bits_per_pixel` differs from the
display's bits-per-pixel for that depth. It then prints the ROM's own message
and **returns without sending the request**; the caller sees no error.
* Everything else — `depth == 1`, and every non-ZPixmap format — takes the 1-bit
path and never reaches that check.
**The two ROM messages, and what they actually mean here.**
* `XPutImage: bits_per_pixel conversion unimplemented.` — string
`0x3F9D0E80`, printed at `0x3F9D0B40` into Xlib's error stream (`@0x00DAD00`).
It is literal: there is no `bits_per_pixel` conversion path in this Xlib. It
fires only for a ZPixmap image of depth ≠ 1 whose `bits_per_pixel` does not
match the server's; the request is dropped, not rejected over the wire, and
the process continues. A 1-bit `XYBitmap` can never trigger it.
* `XGetImage: Can't get requested memory` — string `0x3FD567A0`, printed at
`0x3FD55D30`. It is the **client-side malloc for the reply data** failing: the
call at `0x3FD55C70` allocates `4 × reply.length` bytes and, on NULL, prints
this and returns NULL (`0x3FD55D60`). It says nothing about the server.
**Minimum image sequence** (same calling convention as §4): `XCreateGC`
(`0x3F997000`, mask 0 is enough) → `XCreateImage` → optional
`XSetForeground` → `XPutImage` → `XSync` (`0x3FD9F6B0`) →
`XDestroyImage`. Map and sync the window once before the put, exactly as for
text: the WM reparents the window, and a draw issued before that can be lost.
The probe in §2.2.2 is this sequence.
#### 2.2.2 The image path, measured
`dwt/gui/xshow.asm` (built with `dwt/loader/build.sh`, run through the COFF
loader — no network, no rdebug) opens its own connection as a `create_process`
child, creates a 400×200 window at 100,100, creates a 32×32 **XYBitmap**
(`depth = 1`, `format = 0`, LSBFirst both ways, `bitmap_unit = 32`,
`bitmap_pad = 32`, `bytes_per_line = 0` so `XCreateImage` computes it), uploads
it with `XPutImage` at window (20,20), syncs twice, and destroys it. A second
`XPutImage` of the same image with `h = 16` at (20,60) is the control.
Measured values from the run (frame 2650, VR150, `VT1200_SKIP_LEVEL1=1`):
```
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 is "synced"; the checklist stages 1–7 are start, display, window,
mapped, gc, image, putimage. The picture: `dwt/gui/evidence/xshow_frame2650.png`.
Pixel rows (decoded from that PNG with
`python3 dwt/gui/evidence/png_rows.py dwt/gui/evidence/xshow_frame2650.png 118 118 40 64`,
saved as `dwt/gui/evidence/xshow_pixels.txt`) show the full 32-row image at
screen 122..153 and the 16-row control at 162..177:
```
122 ....################################....
123 .....#..................................
... (one diagonal pixel per row)
152 ..................................#.....
153 ....################################....
...
162 ....################################....
163 .....#..................................
... (control stops after 16 rows)
177 ...................#....................
```
The same payload run snapshot 30 frames later (`xshow_frame2680.png`, frame
2680) is byte-identical to the 2650 capture (md5
`ab9d63844aa5a3dd9d281a6bee3c76c2`), so the picture is the window's state and
not a transient.
What this proves, and what it does not:
* **Measured:** the ROM's own `XCreateImage` builds the struct described above
from the ten arguments and the display's orders; `XPutImage` of a 1-bit
`XYBitmap` paints exactly `w × h` pixels at the requested destination, honours
a smaller `h`, and returns normally; `XDestroyImage` runs without harm. 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 (it needs a real GET round trip and its allocation
path). Orders other than LSBFirst are *supposed* to work: the 1-bit copier
picks a normalization routine from a runtime table keyed by
`(bitmap_unit, bitmap_bit_order, byte_order)` for both the image and the
display (`0x3F9CB7C0`–`0x3F9CBB20`), but only LSBFirst/32 was run. A
non-1-bit ZPixmap is untested because the server has no such visual; only the
mismatch message above is established.
### 2.3 X server internals that matter
| what | Ghidra | bits |
@@ -204,8 +360,9 @@ it is mapped should call `0x3FD64F60`.
To draw text add `XLoadFont(d,"fixed")` (`0x3FD4AE80`), `XCreateGC`
(`0x3F997000`) with `GCFont=0x4000`, `XSetForeground` (`0x3FD99A60`) and
`XDrawString` (`0x3FDA0000`). No event loop is needed for a static window; the
server keeps it after the client goes idle.
`XDrawString` (`0x3FDA0000`). To draw a bitmap add `XCreateImage` +
`XPutImage` (§2.2.1); §2.2.2 is the measured example. No event loop is needed
for a static window; the server keeps it after the client goes idle.
Globals: only the `Display *` is per-app. There is **no global "current
display" to initialise**; `XOpenDisplay` allocates and returns it. Window ids,
@@ -349,6 +506,13 @@ live.
| `dwt/gui/probe.lua`, `probe2.lua`, `probe3.lua` | frame snapshots + marker/PC telemetry + accept breakpoint |
| `dwt/gui/run/mame.log` | boot, markers (`strlen=4`, `stage=2`, `disp=0`, `xclients=1`) |
| `dwt/gui/run/gui_frame15571.png` | post-injection frame: normal Terminal Manager, no new window |
| `dwt/gui/xshow.asm` | the XImage probe (§2.2.2): XCreateImage + 2×XPutImage + XDestroyImage |
| `dwt/gui/xshow.lua`, `dwt/gui/build/xshow.coff` | the COFF-loader runner and the linked image it loads |
| `dwt/gui/build/xshow.bin`, `.lst`, `.map` | assembled `.text`, listing, map |
| `dwt/gui/evidence/xshow_frame2650.png` | 32-row diagonal at window (20,20); 16-row control at (20,60) |
| `dwt/gui/evidence/xshow_frame2680.png` | the same picture 30 frames later (byte-identical PNG) |
| `dwt/gui/evidence/xshow_pixels.txt`, `png_rows.py` | the PNG's rows as ASCII, and the dependency-free decoder that produced them |
| `dwt/gui/evidence/xshow_run.log` | the run: stage 8, the live XImage fields, the display's pixmap formats |
## 10. Transport settled: a `create_process` child opens a window