65816-llvm-mos/runtime/src/iigsToolbox.s
Scott Duensing 07544f49f2 Checkpoint
2026-05-02 16:48:56 -05:00

223 lines
7.3 KiB
ArmAsm

; iigsToolbox.s — multi-arg toolbox wrappers that can't be done as
; inline asm because the W65816 backend's inline-asm constraints
; can't take memory operands.
;
; C ABI on this target:
; - Arg 0 (i16): in A
; - Arg 0 (i32): low half in A, high half in X
; - Arg N>0 (i16):in stack at (4 + 2*(N-1)), S — args pushed
; rightmost-first, JSL adds 3 bytes of retaddr
; (4,S = arg1 lo)
; - i16 return: A
; - i32 return: A (low) + X (high)
;
; Toolbox calls expect:
; - Args on stack in toolbox order (rightmost pushed first), then
; a result slot of appropriate width pushed BEFORE the args (so
; the result ends up at the highest stack address after pushes).
; - Tool number in X.
; - JSL $E10000.
; - After JSL, pop result then args in reverse.
;
; All wrappers preserve nothing (toolbox clobbers A, X, Y, P).
.text
.globl TBoxNewHandle
.globl TBoxDisposeHandle
.globl TBoxQDStartUp
.globl TBoxMoveTo
.globl TBoxEMStartUp
.globl TBoxGetNextEvent
.globl TBoxNewWindow
.globl TBoxCloseWindow
; =====================================================================
; unsigned long TBoxNewHandle(u32 size, u16 userId, u16 attr, u32 addr)
; Entry: A = size lo, X = size hi
; 4,S = userId, 6,S = attr, 8,S = addr lo, 10,S = addr hi
; Tool layout (push order, leftmost=outermost on stack):
; [result lo][result hi][size lo][size hi][userId][attr][addr lo][addr hi]
; Wait: NewHandle args per Apple GS docs are
; (Long blockSize, Word userId, Word attributes, Long memAttr)
; pushed leftmost-first, so:
; PEA result hi, PEA result lo
; PUSH blockSize hi, PUSH blockSize lo (long, lo first then hi? no — let me check)
;
; Actually GS toolbox push order: each parameter is pushed in
; declaration order, low word first then high word for longs.
; Result space is pushed FIRST (and is read LAST after the pop
; sequence reverses everything). So:
; PEA 0 ; result hi
; PEA 0 ; result lo
; PHA size lo
; PHB? no:
; per https://www.brutaldeluxe.fr/products/crossdevtools/cadius/
; Push order: parameters in order, longs as lo then hi.
; For NewHandle(blockSize=Long, userId=Word, attr=Word, memLoc=Long):
; pea 0 ; result lo
; pea 0 ; result hi
; pha ; blockSize lo
; phx ; blockSize hi (since size hi is in X)
; pha userId
; pha attr
; pha addrLo
; pha addrHi
; ldx #$0902 ; jsl $E10000
; ; result is now on stack: pop hi then lo into A:X return
;
; Note: the IIgs toolbox actually expects result space to be HIGHER
; on stack (pushed first) so that pops in reverse give result last.
; =====================================================================
TBoxNewHandle:
; Stash size lo (in A) and size hi (in X) before we use the
; stack — both must be pushed AFTER the result slot.
sta 0xe0 ; size lo to scratch
stx 0xe2 ; size hi to scratch
; Push 4-byte result space (will be popped at end).
pea 0 ; result lo
pea 0 ; result hi
; Push blockSize: lo first then hi.
lda 0xe0 ; size lo
pha
lda 0xe2 ; size hi
pha
; Push userId (was at 4,S originally; pushes since added: 4 result + 4 size = 8; +4 for JSL retaddr offset baseline)
; Original 4,S; we've pha'd 8 bytes (result+size) on top of retaddr
; So userId is now at 4 + 8 = 12,S.
lda 12, s ; userId
pha
; attr was at 6,S originally; now at 6 + 8 + 2 (one more pha) = 16,S.
lda 16, s ; attr
pha
; addr lo was at 8,S originally; with all our pushes (4 result + 4
; size + 2 user + 2 attr = 12), now at 8 + 12 = 20,S.
lda 20, s ; addr lo
pha
; addr hi was at 10,S originally; +14 = 24,S.
lda 24, s ; addr hi
pha
ldx #0x0902
jsl 0xe10000
; Pop result: hi then lo. Returns u32 in A:X (low in A, hi in X).
pla ; result hi
tax
pla ; result lo → A
rtl
; =====================================================================
; void TBoxDisposeHandle(unsigned long handle)
; Entry: A = handle lo, X = handle hi
; =====================================================================
TBoxDisposeHandle:
pha ; handle lo
phx ; handle hi
ldx #0x1002
jsl 0xe10000
rtl
; =====================================================================
; void TBoxQDStartUp(u16 masterSCB, u16 pageSize, u16 userId)
; Entry: A = masterSCB, 4,S = pageSize, 6,S = userId
; Tool: PEA userId, PEA pageSize, PHA masterSCB, JSL X=$0204
; =====================================================================
TBoxQDStartUp:
sta 0xe0 ; stash masterSCB
lda 6, s ; userId (originally 6,S, no pushes yet)
pha ; userId pushed; subsequent loads need +2
lda 6, s ; pageSize was at 4,S; +2 = 6,S
pha
lda 0xe0 ; masterSCB
pha
ldx #0x0204
jsl 0xe10000
rtl
; =====================================================================
; void TBoxMoveTo(short h, short v)
; Entry: A = h, 4,S = v
; =====================================================================
TBoxMoveTo:
pha ; h
lda 6, s ; v (originally 4,S; +2 after pha)
pha
ldx #0x3A04
jsl 0xe10000
rtl
; =====================================================================
; void TBoxEMStartUp(u16 userId)
; Entry: A = userId
; Default queueSize=0, mouse clamp 0..639 / 0..199
; Tool: PEA queueSize, PEA xMin, PEA xMax, PEA yMin, PEA yMax, PHA userId
; =====================================================================
TBoxEMStartUp:
pea 0 ; queueSize = use default
pea 0 ; xMin
pea 0x27F ; xMax = 639
pea 0 ; yMin
pea 0xC7 ; yMax = 199
pha ; userId (still in A from entry)
ldx #0x0206
jsl 0xe10000
rtl
; =====================================================================
; unsigned short TBoxGetNextEvent(u16 eventMask, void *theEvent)
; Entry: A = eventMask, 4,S = theEvent
; Tool: PHA result(word), PHA eventMask, PHA theEvent, JSL X=$0A06
; =====================================================================
TBoxGetNextEvent:
sta 0xe0 ; stash eventMask
pea 0 ; result space (16-bit)
lda 0xe0 ; eventMask
pha
lda 8, s ; theEvent (originally 4,S; +4 after pea+pha)
pha
ldx #0x0A06
jsl 0xe10000
pla ; result → A
rtl
; =====================================================================
; void *TBoxNewWindow(const void *paramList)
; Entry: A = paramList
; Tool: PEA result hi, PEA result lo, PHA paramList, JSL X=$090E
; Returns 32-bit window ptr in A:X (low in A, hi in X).
; =====================================================================
TBoxNewWindow:
sta 0xe0 ; stash paramList
pea 0 ; result hi
pea 0 ; result lo
lda 0xe0 ; paramList
pha
ldx #0x090E
jsl 0xe10000
pla ; result lo → A
plx ; result hi → X
rtl
; =====================================================================
; void TBoxCloseWindow(void *winPtr)
; Entry: A = winPtr lo, X = winPtr hi
; =====================================================================
TBoxCloseWindow:
pha ; winPtr lo
phx ; winPtr hi
ldx #0x0B0E
jsl 0xe10000
rtl