65816-llvm-mos/runtime/include/iigs/toolbox.h
Scott Duensing 07544f49f2 Checkpoint
2026-05-02 16:48:56 -05:00

317 lines
9.2 KiB
C

// IIgs toolbox helpers — wrappers for commonly-used Apple IIgs system
// calls.
//
// Toolbox dispatch on the IIgs goes through the Tool Locator at
// $E10000. Each routine is identified by a 16-bit "tool number"
// (high byte = function within set, low byte = tool set), loaded
// into X, and called via JSL $E10000.
//
// GS/OS dispatch goes through $E100A8 with X holding the call
// number and a parameter-block pointer pushed on the stack.
//
// Calling convention:
// - Args go on the stack (push order: rightmost first), then the
// caller pushes a result-space slot (16 or 32 bits) BEFORE
// the args if the routine returns something non-void.
// - The result is read off the same stack slot AFTER JSL.
// - Tool number lives in X immediately before JSL.
// - Tools clobber A, X, Y, P; the runtime spills around the call.
//
// Single-arg / no-arg wrappers are `static inline`. Multi-arg
// wrappers are declared `extern` here and implemented in
// runtime/src/iigsToolbox.s — backend constraints don't allow
// memory-operand inline asm so the multi-arg pushes need real
// .s code.
#ifndef IIGS_TOOLBOX_H
#define IIGS_TOOLBOX_H
#ifdef __cplusplus
extern "C" {
#endif
// ===== Tool numbers (high byte = function, low byte = tool set) =====
// Tool sets:
// 01 = Tool Locator 02 = Memory Manager 03 = Misc Tools
// 04 = QuickDraw II 06 = Event Manager 0E = Window Manager
// 1B = Menu Manager 29 = Standard File
// =====================================================================
// Tool Locator (Set $01)
// =====================================================================
static inline void TBoxTLStartUp(void) {
__asm__ volatile (
"ldx #0x0201\n"
"jsl 0xe10000\n"
:
:
: "a", "x", "y", "memory"
);
}
static inline void TBoxTLShutDown(void) {
__asm__ volatile (
"ldx #0x0301\n"
"jsl 0xe10000\n"
:
:
: "a", "x", "y", "memory"
);
}
// =====================================================================
// Memory Manager (Set $02)
// =====================================================================
// MMStartUp — call as the first MM routine. Returns the caller's
// 16-bit userId; save it for later DisposeAll calls.
static inline unsigned short TBoxMMStartUp(void) {
unsigned short id;
__asm__ volatile (
"pha\n" // result space
"ldx #0x0202\n"
"jsl 0xe10000\n"
"pla\n"
: "=a"(id)
:
: "x", "y", "memory"
);
return id;
}
// MMShutDown — releases all MM resources owned by `userId`.
static inline void TBoxMMShutDown(unsigned short userId) {
__asm__ volatile (
"pha\n"
"ldx #0x0302\n"
"jsl 0xe10000\n"
:
: "a"(userId)
: "x", "y", "memory"
);
}
// NewHandle / DisposeHandle live in iigsToolbox.s — the parameter
// blocks are 4-arg with mixed widths and need explicit asm.
extern unsigned long TBoxNewHandle(unsigned long size,
unsigned short userId,
unsigned short attr,
unsigned long addr);
extern void TBoxDisposeHandle(unsigned long handle);
// =====================================================================
// Misc Tools (Set $03)
// =====================================================================
// SysBeep — short beep through the speaker.
static inline void TBoxBeep(void) {
__asm__ volatile (
"ldx #0x0303\n"
"jsl 0xe10000\n"
:
:
: "a", "x", "y", "memory"
);
}
// WriteCString — Misc Tool $0B; writes a NUL-terminated string to
// the text screen. Note: actual GS uses Text Tools or stdio;
// this is the legacy entry point.
static inline void TBoxWriteCString(const char *s) {
__asm__ volatile (
"pha\n"
"ldx #0x290B\n"
"jsl 0xe10000\n"
:
: "a"(s)
: "x", "y", "memory"
);
}
// ReadAsciiTime — fills a 20-byte buffer with the current time
// formatted as "DDD MMM dd hh:mm:ss yyyy".
static inline void TBoxReadAsciiTime(char *buf20) {
__asm__ volatile (
"pha\n"
"ldx #0x0F03\n"
"jsl 0xe10000\n"
:
: "a"(buf20)
: "x", "y", "memory"
);
}
// =====================================================================
// QuickDraw II (Set $04)
// =====================================================================
// QDStartUp / QDShutDown. Multi-arg startup lives in iigsToolbox.s.
extern void TBoxQDStartUp(unsigned short masterSCB,
unsigned short pageSize,
unsigned short userId);
static inline void TBoxQDShutDown(void) {
__asm__ volatile (
"ldx #0x0304\n"
"jsl 0xe10000\n"
:
:
: "a", "x", "y", "memory"
);
}
// MoveTo — move the pen to absolute (h, v).
extern void TBoxMoveTo(short h, short v);
// DrawString — draw a Pascal-style length-prefixed string at the
// current pen position. First byte of `pstr` must be the length.
static inline void TBoxDrawString(const char *pstr) {
__asm__ volatile (
"pha\n"
"ldx #0x2C04\n"
"jsl 0xe10000\n"
:
: "a"(pstr)
: "x", "y", "memory"
);
}
// PaintRect / FrameRect / EraseRect — rect is a 16-bit pointer to a
// 4-word Rect (top, left, bottom, right).
static inline void TBoxPaintRect(const short *rect) {
__asm__ volatile (
"pha\n"
"ldx #0x5104\n"
"jsl 0xe10000\n"
:
: "a"(rect)
: "x", "y", "memory"
);
}
static inline void TBoxFrameRect(const short *rect) {
__asm__ volatile (
"pha\n"
"ldx #0x4F04\n"
"jsl 0xe10000\n"
:
: "a"(rect)
: "x", "y", "memory"
);
}
static inline void TBoxEraseRect(const short *rect) {
__asm__ volatile (
"pha\n"
"ldx #0x5004\n"
"jsl 0xe10000\n"
:
: "a"(rect)
: "x", "y", "memory"
);
}
// =====================================================================
// Event Manager (Set $06)
// =====================================================================
// EMStartUp — initialises Event Manager with default queue and
// 640x200 mouse clamp. Args other than userId are hardcoded; if
// you need custom clamp, write your own wrapper.
extern void TBoxEMStartUp(unsigned short userId);
static inline void TBoxEMShutDown(void) {
__asm__ volatile (
"ldx #0x0306\n"
"jsl 0xe10000\n"
:
:
: "a", "x", "y", "memory"
);
}
// SystemTask — gives time to background tasks. Call regularly in
// event loops.
static inline void TBoxSystemTask(void) {
__asm__ volatile (
"ldx #0x0306\n"
"jsl 0xe10000\n"
:
:
: "a", "x", "y", "memory"
);
}
// GetNextEvent — fills the EventRecord pointed at by `theEvent`
// with the next event matching `eventMask`. Returns nonzero if an
// event was returned.
//
// EventRecord layout (16 bytes): what(2) message(4) when(4) where(4)
// modifiers(2).
extern unsigned short TBoxGetNextEvent(unsigned short eventMask, void *theEvent);
// =====================================================================
// Window Manager (Set $0E)
// =====================================================================
// NewWindow — allocate and display a new window. paramList points
// to a NewWindow parameter block (in-bank 16-bit pointer). Returns
// a 32-bit window pointer.
extern void *TBoxNewWindow(const void *paramList);
// CloseWindow — tear down a window. Takes a 32-bit window pointer.
extern void TBoxCloseWindow(void *winPtr);
// =====================================================================
// GS/OS (dispatcher at $E100A8)
// =====================================================================
// Quit — clean program shutdown via GS/OS. pConditionTbl = 0
// (no resume condition). Does not return.
static inline void TBoxQuit(void) {
__asm__ volatile (
"pea 0\n" // pConditionTbl
"pea 0\n" // pParm
"ldx #0x2029\n" // GS/OS Quit
"jsl 0xe100a8\n"
:
:
: "a", "x", "y", "memory"
);
while (1) {} // unreachable
}
// =====================================================================
// Helpers — direct hardware polling (no toolbox)
// =====================================================================
// ReadKey — poll the IIgs keyboard latch at $C000 directly.
// Returns the ASCII byte (0 if no key ready). Strobes $C010 to
// clear the latch. Does NOT use Event Manager — for a real GS
// app, use TBoxGetNextEvent and pull from the queue instead.
static inline char TBoxReadKey(void) {
char r = 0;
__asm__ volatile (
"sep #0x20\n" // 8-bit A
"lda 0xc000\n"
"bpl 1f\n"
"sta 0xc010\n" // strobe
"and #0x7f\n"
"bra 2f\n"
"1:\n"
"lda #0\n"
"2:\n"
"rep #0x20\n"
"and #0x00ff\n"
: "=a"(r)
:
: "memory"
);
return r;
}
#ifdef __cplusplus
}
#endif
#endif // IIGS_TOOLBOX_H