| .. | ||
| build.sh | ||
| frame.bin | ||
| frame.c | ||
| frame.map | ||
| frame.o | ||
| frame.omf | ||
| frame.reloc | ||
| heavyRelocs.bin | ||
| heavyRelocs.c | ||
| heavyRelocs.map | ||
| heavyRelocs.o | ||
| heavyRelocs.omf | ||
| heavyRelocs.reloc | ||
| helloBeep.bin | ||
| helloBeep.c | ||
| helloBeep.map | ||
| helloBeep.o | ||
| helloBeep.omf | ||
| helloBeep.reloc | ||
| helloText.bin | ||
| helloText.c | ||
| helloText.map | ||
| helloText.o | ||
| helloText.omf | ||
| helloText.reloc | ||
| helloWindow.bin | ||
| helloWindow.c | ||
| helloWindow.map | ||
| helloWindow.o | ||
| helloWindow.omf | ||
| helloWindow.reloc | ||
| launch.sh | ||
| layer2Stress.c | ||
| minicad.bin | ||
| minicad.c | ||
| minicad.map | ||
| minicad.o | ||
| minicad.omf | ||
| minicad.reloc | ||
| orcaFrame.bin | ||
| orcaFrame.c | ||
| orcaFrame.map | ||
| orcaFrame.o | ||
| orcaFrame.omf | ||
| orcaFrame.reloc | ||
| qdProbe.bin | ||
| qdProbe.c | ||
| qdProbe.map | ||
| qdProbe.o | ||
| qdProbe.omf | ||
| qdProbe.reloc | ||
| README.md | ||
| reversi.bin | ||
| reversi.c | ||
| reversi.map | ||
| reversi.o | ||
| reversi.omf | ||
| reversi.reloc | ||
| test.sh | ||
llvm816 GS/OS Demo Apps
Small Apple IIgs S16 applications that build with our LLVM/clang toolchain, wrap as OMF v2.1 ExpressLoad, and launch under real GS/OS 6.0.2 in MAME.
Building / running
bash demos/build.sh helloBeep # build the OMF
bash demos/launch.sh helloBeep # interactive run in MAME (visible window, audio)
bash demos/test.sh helloBeep # headless test (boots, runs, checks marker)
The launch script runs MAME with no timeout; close the MAME
window when done (Esc, then Cmd-Q). The test script injects a
keystroke after the demo has launched, then checks $00:0070
for the 0x99 end-of-run marker the demo writes before exit.
Demos
helloBeep.c
Three SysBeep() calls then exit. The toolbox SysBeep lives in
Misc Tools; no other startup needed (Loader handles MM + TL).
helloText.c
Initialises Event Manager (so GetNextEvent can read keystrokes)
and Text Tools (so WriteCString has an output device), writes
two greeting lines to the text screen, waits for any keypress via
GetNextEvent, beeps, exits. Uses these toolbox calls:
MMStartUp,NewHandle(DP allocation for Event Manager)EMStartUp,GetNextEvent(event-driven keyboard)TextStartUp,SetOutputDevice,WriteCString(text I/O)SysBeep
helloWindow.c
Initialises the full Window Manager startup chain (Memory, QD,
Event, Scheduler, Window), constructs an Apple-IIgs-Toolbox-Ref
NewWindow parm block, and calls NewWindow. When NewWindow
returns a real handle the demo calls SetPort, ShowWindow,
MoveTo, and DrawString to put a greeting in the window, then
waits for a keypress, beeps, and exits.
Three toolchain bugs needed fixing to make this work end-to-end under real GS/OS 6.0.2 (all now landed):
- omfEmit RESSPC=0 for code segments — BSS got no memory allocation; writes past the image end silently vanished. Now BSS is embedded as zeros in the LCONST data.
- Loader cRELOC at segPlacedBase=$0000 (not $1000 like our
text-base) — host probes need to compute runtime addresses as
link_addr - text_base + bank<<16. &symbolbank=0 — proper backend fix landed.LDAi16imm_bankAsmPrinter pseudo lowers tolda $BE; crt0 storesPBRto $BE- zero to $BF at startup, so the high half of every
&symbolpointer carries the actual load bank at runtime. Toolbox pointer args now Just Work without per-wrapper PBR overrides.
- zero to $BF at startup, so the high half of every
orcaFrame.c
First ORCA-style desktop application. Opens a Window Manager
window via startdesk() (full toolset chain), runs a TaskMaster
event loop until the close box / Q key / 1000-iteration watchdog
fires. Both 6.0.2 (sys602.po) and 6.0.4 (6.0.4 - System.Disk.po)
launch it cleanly; fTitle works on both.
frame.c
Full port of ORCA-C's Frame.cc sample. Builds the
Apple+File+Edit menu bar via the real ROM Menu Manager
(NewMenu / InsertMenu / FixAppleMenu / FixMenuBar /
DrawMenuBar) and renders the original "About Frame" dialog
(white-filled framed rect with the 1989 Byte Works copyright
text and an OK button).
minicad.c
Full port of ORCA-C's MiniCAD.cc sample. Apple+File+Edit+
Options menu bar + a windowed canvas with three seeded line-art
patterns (curve-stitching, sunburst, Star of David).
reversi.c
Full Othello game ported from ORCA-C's Reversi.cc. 100-byte
sentinel-bordered board, 8-direction capture detection, 1-ply
AI with corner/edge weighting, QD-rendered board with black/white
pieces.
qdProbe.c
Diagnostic — minimal QD/EM/WM init followed by RefreshDesktop
plus ZP/SHR markers. Used to prove that WindStartUp does NOT
auto-paint the desktop and that RefreshDesktop(NULL) is what
actually fills SHR with the dithered desktop pattern. Run via
scripts/probeQdStartup.sh.
Known limitations
- fTitle on stripped 6.0.2: orcaFrame uses fTitle and runs
fine on both 6.0.2 sys602.po and 6.0.4 System.Disk.po. Earlier
notes that fTitle required disk fonts were superseded — the
underlying bug was a
QDStartUpargument-order mistake inruntime/src/desktop.c, fixed 2026-05-16. - Window not visually painted:
WindStartUpdoes NOT paint the desktop on its own;RefreshDesktop(NULL)is required. Adding the call tostartdesk()works forqdProbe.cbut pushes the orca demos past the GS/OS Loader's silent-rejection threshold (see memory:loader-creloc-threshold). - GS/OS Loader cRELOC threshold: anywhere from 65-90 cRELOCs the Loader silently refuses to launch ExpressLoad OMFs. The threshold is not a clean reloc-count cutoff; OMF byte layout and reloc patch offsets both matter. The ORCA ports are slim to stay under it.
What got fixed during demo authoring
Substantive toolchain bugs surfaced and fixed:
iigsGsos.sGS/OS wrappers andgenToolbox.py's 890 toolbox wrappers were pushing 4-byte Long args low-word-first. ORCA-C's PushLong macro is high-word-first. Anything passing a Long arg through the toolbox dispatcher (NewHandle, NewWindow, fopen->gsosOpen, etc.) was reading garbage parm-block pointers. Fixed in both files plus the generator; regenerated 890 wrappers.runtime/build.shwasn't rebuildingiigsToolbox.s-- the .o was stale since May 4. Added the missing line.(short)(*(void **)dpHandle)was a double-dereference bug that read garbage at the master pointer's destination instead of the master pointer VALUE (= the DP address). Corrected to(unsigned short)(unsigned long)*(void **)dpHandlefor proper block-address extraction.helloTextusedTextStartUp + WriteCStringdirectly which crashed to the IIgs monitor; fixed by addingSetOutputDevice(1, 0)to wire stdout to the text screen.helloText's event loop hung forever becauseEMStartUpwasn't being called; fixed by adding it (with proper DP allocation).
ptr32 mode note
All address constants in the demos (text screen $00:0400, SHR
RAM $E1:2000, soft switches $00:C0xx, keyboard register $00:C000)
are plain C 32-bit pointers like (volatile unsigned char *)0xE12000UL.
In ptr32 mode the compiler emits LONG addressing automatically;
no switchToBank2-style inline asm or DBR juggling required.