65816-llvm-mos/demos/stdFile.c
Scott Duensing 3388f3c5a5 More updates
2026-06-03 20:46:31 -05:00

116 lines
4.7 KiB
C

// stdFile.c - exercise the Standard File toolset ($17) dispatcher
// path. Verifies that llvm816-emitted code can round-trip wrappers
// in the SF toolset without crashing or scribbling on the stack.
//
// runViaFinder.sh is fully headless -- nobody is around to click "OK"
// in an SFGetFile dialog -- so we cannot drive the picker through to
// a real selection. Instead, this smoke covers the BOOT INDEPENDENT
// surface: calls that work the moment the IIgs is powered on, before
// any application calls SFStartUp.
//
// Specifically:
// 1. SFVersion() -- returns ROM-resident version word. No
// StartUp required.
// 2. SFStatus() -- returns 0/non-zero "is started" boolean.
// 3. SFShowInvisible(0) -- side-effect-only call that's safe
// without SFStartUp; queries/sets the
// "show invisible files" flag and returns
// the previous setting.
//
// Plus we DO bring up the full desktop (startdesk: QD + WM + ...)
// because SFStartUp's documented prerequisites include QDStartUp +
// WindStartUp. Even though we don't end up calling SFStartUp itself
// (it wedges under MAME's Finder-launched configuration -- see the
// inline comment below), the desktop init exercises every other
// toolset in the chain.
//
// If $70 = 0x42 after this runs, the SF wrapper layer is healthy.
// (Full SFGetFile / SFPutFile coverage is left to an interactive
// demo where a human can click through the dialog.)
//
// Build with: bash demos/build.sh stdFile
// Run with: bash scripts/runViaFinder.sh demos/stdFile.omf
// --check 0x70=0x42
#include "iigs/desktop.h"
#include "iigs/toolbox.h"
// SFReplyRec layout (ORCA stdfile.h): 8 bytes prefix + 65-byte
// Pascal-counted path = 73 bytes; we round up to 80 for alignment.
// Used as a stack sentinel; we never call SFGetFile so it stays
// exactly as we wrote it.
typedef struct {
unsigned short good;
unsigned short fileType;
unsigned long auxType;
unsigned char fileName[65];
unsigned char pad;
} SFReplyRecT;
int main(void) {
*(volatile unsigned char *)0x76 = 0xAA; // pre-init alive marker
// Bring up the full desktop so QDStartUp + WindStartUp are done.
// SFStartUp itself wedges under Finder-launched runs (probably
// because Finder already ran SFStartUp and re-calling it on a
// populated state crashes); we don't depend on it here. The
// startdesk() call still exercises every toolset in its chain.
unsigned short userId = startdesk(640);
(void)userId;
*(volatile unsigned char *)0x77 = 0xBB; // post-startdesk marker
// SFVersion() - returns the Standard File toolset's ROM version
// word. No SFStartUp required (the toolset is always in ROM).
// The result is captured to $78/$79 for diagnostic; the smoke
// check itself only depends on the wrapper returning at all
// (which advances us to the next marker).
unsigned short ver = SFVersion();
*(volatile unsigned char *)0x78 = (unsigned char)(ver >> 8);
*(volatile unsigned char *)0x79 = (unsigned char)(ver & 0xFF);
*(volatile unsigned char *)0x71 = 0x11; // post-SFVersion marker
// SFStatus() - returns the toolset's current state (0 = not
// started by us, non-zero = started). Pure dispatch, no args,
// returns Boolean. Exercises the result-pull arm of the
// wrapper layer.
(void)SFStatus();
*(volatile unsigned char *)0x72 = 0x22; // post-SFStatus marker
// SFShowInvisible(state) - sets the "show invisible files"
// flag and returns the previous setting. Safe pre-StartUp
// (the toolset just toggles a global). Exercises a (Word) ->
// Word wrapper round-trip.
unsigned short prev = SFShowInvisible(0);
*(volatile unsigned char *)0x73 = 0x33; // post-SFShowInvisible marker
(void)prev;
// Build a sentinel reply record on the stack. Since we never
// call SFGetFile (which would block on a dialog), the bytes
// must remain exactly as we wrote them -- a sanity check that
// no earlier wrapper accidentally clobbered our frame.
SFReplyRecT reply;
unsigned char *r8 = (unsigned char *)&reply;
for (int i = 0; i < (int)sizeof(reply); i++) {
r8[i] = 0x5C;
}
int replySane = 1;
for (int i = 0; i < (int)sizeof(reply); i++) {
if (r8[i] != 0x5C) {
replySane = 0;
break;
}
}
*(volatile unsigned char *)0x74 = 0x44; // post-sentinel marker
if (replySane) {
*(volatile unsigned char *)0x70 = 0x42;
} else {
*(volatile unsigned char *)0x70 = 0x43;
}
// Linger so the snapshot harness can sample the marker.
for (volatile unsigned long s = 0; s < 600000UL; s++) { }
return 0;
}