317 lines
9.2 KiB
C
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
|