# 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`. - **`&symbol` bank=0** — proper backend fix landed. `LDAi16imm_bank` AsmPrinter pseudo lowers to `lda $BE`; crt0 stores `PBR` to $BE + zero to $BF at startup, so the high half of every `&symbol` pointer carries the actual load bank at runtime. Toolbox pointer args now Just Work without per-wrapper PBR overrides. ### `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 `QDStartUp` argument-order mistake in `runtime/src/desktop.c`, fixed 2026-05-16. - **Window not visually painted:** `WindStartUp` does NOT paint the desktop on its own; `RefreshDesktop(NULL)` is required. Adding the call to `startdesk()` works for `qdProbe.c` but 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.s` GS/OS wrappers and `genToolbox.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.sh` wasn't rebuilding `iigsToolbox.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 **)dpHandle` for proper block-address extraction. - `helloText` used `TextStartUp + WriteCString` directly which crashed to the IIgs monitor; fixed by adding `SetOutputDevice(1, 0)` to wire stdout to the text screen. - `helloText`'s event loop hung forever because `EMStartUp` wasn'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.