// 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