Files
vt1200/dwt/gui/xtext.asm
T

308 lines
9.1 KiB
NASM

; xtext.asm -- open a window on the live DWT X server and draw text in it.
;
; 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, so
; XOpenDisplay returns an unusable Display. A fresh process works.
;
; This is xhello.asm plus the text path:
; XLoadFont(d,"fixed") 3FD4AE80
; XCreateGC(d,win,mask,&values) 3F997000
; XSetForeground(d,gc,1) 3FD99A60
; XMapWindow(d,win) 3FD645B0
; XSync(d,0) / XDrawString(...) loop 3FD9F6B0 / 3FDA0000
;
; The GC is created with a zero value-mask, so the server fills it from the
; screen's default GC (which carries the server's default font, "fixed"). The
; draw is repeated with an XSync between iterations so that it lands after the
; WM has framed/reparented/mapped the window; a single early draw can be lost
; when the window is reparented.
;
; Calling convention (the one the firmware itself uses; see the WM at
; 07F57044 and the TM at 07E5D2B4):
;
; MOVE A14,-*SP,1 ; reserve the slot the callee restores A14 from
; MOVI argN,A0 / MOVE A0,*A14+,1 ; last argument first, upward via A14
; ...
; MOVI arg0,A0 / MOVE A0,*A14+,1 ; first argument last
; CALLA target
;
; The callee's `rets 2` pops the return address and the reserved slot, so SP is
; restored by the call itself; A14 is restored from that slot. Do NOT keep the
; entry SP/A14 in RAM and restore them after each call: the app's own stack and
; Xlib data structures use the same free heap, and a clobbered saved-SP cell
; turns the next call into a wild push. That exact pattern crashed the first
; version of this payload at XCreateGC.
;
; Xlib clobbers the CPU's SETF field state, so the ABI's 32-bit field 1 is
; re-established after every call. The Display pointer and the window/GC ids
; are kept in callee-saved registers (a11/a10/a12).
;
; Markers live in 224 bytes of zero padding at the end of .text (01842000h),
; NOT in the free heap: the first version's cells at 01895000h were overwritten
; by the OS heap (the string "Exiting\n" landed on them).
;
; 01842000 stage (1 start, 2 display, 3 window, 4 font, 5 GC, 6 setfg,
; 7 map, 8 synced/drawn, 9 flushed, 0FFh failed)
; 01842020 display pointer
; 01842040 font id returned by XLoadFont
; 01842060 window id
; 01842080 GC id returned by XCreateGC
; 018420A0 XSetForeground return
; 018420C0 XMapWindow return
; 018420E0 last XSync return
; 01842100 first XDrawString return
; 01842120 second XDrawString return
; 01842140 final XSync return
; 01841760 strlen("0::0") -- must be 4
;
; Scratch: 01894000 argument area
.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, @01842000h, 1 ; 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 ; arg0
calla 3FB458D0h ; strlen
setf 16, 0, 0
setf 32, 0, 1
move a8, @01842160h, 1 ; MARK strlen
movi 4, a0, L
cmp a0, a8
jrne failed
movi 2, a0, L
move a0, @01842000h, 1 ; stage = 2
; ---- display = XOpenDisplay("0::0") ---------------------------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 3FACE948h, a0, L
move a0, *a14+, 1 ; arg0 = name
calla 3F9C2570h ; XOpenDisplay
setf 16, 0, 0
setf 32, 0, 1
move a8, a11 ; Display * (callee-saved)
move a11, @01842020h, 1 ; MARK display
move a11, a11
jreq failed
; ---- root = *(*(display+0x480)+0x40) --------------------------
move *a11(0480h), a10, 1
move *a10(040h), a10, 1
movi 3, a0, L
move a0, @01842000h, 1 ; stage = 3
; ---- window = XCreateSimpleWindow(d,root,100,100,400,200,2,1,0) --
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1 ; background = 0 (black)
movi 1, a0, L
move a0, *a14+, 1 ; border = 1 (white)
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 ; window id
move a10, @01842060h, 1 ; MARK window
move a10, a10
jreq failed
movi 4, a0, L
move a0, @01842000h, 1 ; stage = 4
; ---- font = XLoadFont(display, "fixed") -----------------------
move a14, -*sp, 1
movi 01894000h, a14, L
movi FONTNAME, a0, L
move a0, *a14+, 1 ; arg1 = name
move a11, *a14+, 1 ; arg0 = display
calla 3FD4AE80h ; XLoadFont
setf 16, 0, 0
setf 32, 0, 1
move a8, a9 ; Font (callee-saved)
move a9, @01842040h, 1 ; MARK font
move a9, a9
jreq failed
movi 5, a0, L
move a0, @01842000h, 1 ; stage = 5
; ---- gc = XCreateGC(d, window, 0, NULL) ----------------------
; mask 0 -> server default GC values (no value-list to misparse).
move a14, -*sp, 1
movi 01894000h, a14, L
movi 0, a0, L
move a0, *a14+, 1 ; arg3 = values
move a0, *a14+, 1 ; arg2 = mask 0
move a10, *a14+, 1 ; arg1 = drawable
move a11, *a14+, 1 ; arg0 = display
calla 3F997000h ; XCreateGC
setf 16, 0, 0
setf 32, 0, 1
move a8, a12 ; GC (callee-saved)
move a12, @01842080h, 1 ; MARK gc
move a12, a12
jreq failed
; ---- XSetForeground(display, gc, 1) --------------------------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 1, a0, L
move a0, *a14+, 1 ; arg2 = pixel 1 (white)
move a12, *a14+, 1 ; arg1 = gc
move a11, *a14+, 1 ; arg0 = display
calla 3FD99A60h ; XSetForeground
setf 16, 0, 0
setf 32, 0, 1
move a8, @018420A0h, 1 ; MARK setfg
movi 6, a0, L
move a0, @01842000h, 1 ; stage = 6
; ---- XMapWindow(display, window) -----------------------------
move a14, -*sp, 1
movi 01894000h, a14, L
move a10, *a14+, 1 ; window
move a11, *a14+, 1 ; display
calla 3FD645B0h ; XMapWindow
setf 16, 0, 0
setf 32, 0, 1
move a8, @018420C0h, 1 ; MARK map
movi 7, a0, L
move a0, @01842000h, 1 ; stage = 7
; ---- sync + draw, repeated: the WM needs time to frame/map -----
movi 4, a9, L
draw_loop:
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 (flush + round trip)
setf 16, 0, 0
setf 32, 0, 1
move a8, @018420E0h, 1 ; MARK last sync
; ---- XDrawString(display, window, gc, 20, 80, msg1, 12) ------
move a14, -*sp, 1
movi 01894000h, a14, L
movi 12, a0, L
move a0, *a14+, 1 ; arg6 = length
movi MSG1, a0, L
move a0, *a14+, 1 ; arg5 = string
movi 80, a0, L
move a0, *a14+, 1 ; arg4 = y
movi 20, a0, L
move a0, *a14+, 1 ; arg3 = x
move a12, *a14+, 1 ; arg2 = gc
move a10, *a14+, 1 ; arg1 = window
move a11, *a14+, 1 ; arg0 = display
calla 3FDA0000h ; XDrawString
setf 16, 0, 0
setf 32, 0, 1
move a8, @01842100h, 1 ; MARK draw1
; ---- XDrawString(display, window, gc, 20, 120, msg2, 10) ----
move a14, -*sp, 1
movi 01894000h, a14, L
movi 10, a0, L
move a0, *a14+, 1 ; arg6 = length
movi MSG2, a0, L
move a0, *a14+, 1 ; arg5 = string
movi 120, a0, L
move a0, *a14+, 1 ; arg4 = y
movi 20, a0, L
move a0, *a14+, 1 ; arg3 = x
move a12, *a14+, 1 ; arg2 = gc
move a10, *a14+, 1 ; arg1 = window
move a11, *a14+, 1 ; arg0 = display
calla 3FDA0000h ; XDrawString
setf 16, 0, 0
setf 32, 0, 1
move a8, @01842120h, 1 ; MARK draw2
; DSJS has a short range; trampoline to the long backward jump.
dsjs a9, draw_next
jruc draw_done
draw_next:
jruc draw_loop
draw_done:
movi 8, a0, L
move a0, @01842000h, 1 ; stage = 8
; ---- final XSync flushes the last PolyText8 -----------------
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
move a8, @01842140h, 1 ; MARK final sync
movi 9, a0, L
move a0, @01842000h, 1 ; stage = 9 (text drawn and flushed)
jruc done
failed:
movi 0FFh, a0, L
move a0, @01842000h, 1
done:
mmfm sp, a0,a1,a2,a3,a4,a5,a6,a7
movi 0, a8, L
rets
MSG1: .byte "HELLO VT1200", 0
MSG2: .byte "text works", 0
FONTNAME: .byte "-DEC-Terminal-Medium-R-Normal--14-140-75-75-C-8-ISO8859-1", 0
; 224 bytes of padding: marker cells 01842000h..0184217Fh live here.
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.end