ORCA/C demos seem to be working!

This commit is contained in:
Scott Duensing 2026-05-18 14:43:35 -05:00
parent 6bff7bea3f
commit 524a37fcf0
141 changed files with 9786 additions and 1952 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
*.png filter=lfs diff=lfs merge=lfs -text

13
benchmarks/bubbleSort.c Normal file
View file

@ -0,0 +1,13 @@
// Bubble-sort 16 ints. Exercises array indexed access, nested loops,
// and i16 compare/swap — patterns common in any sorted-collection code.
void bubbleSort(short *a, unsigned short n) {
for (unsigned short i = 0; i < n - 1; i++) {
for (unsigned short j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
short t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
}

11
benchmarks/djb2Hash.c Normal file
View file

@ -0,0 +1,11 @@
// djb2 string hash. Exercises i32 arithmetic in a tight pointer-walk
// loop — hash << 5 + hash + c. Hits the i32 shift inline path and the
// byte-load pattern in the same loop body. Real-world: every hash
// table keyed by strings uses something like this.
unsigned long djb2Hash(const char *s) {
unsigned long h = 5381;
while (*s) {
h = ((h << 5) + h) + (unsigned char)(*s++);
}
return h;
}

View file

@ -0,0 +1,9 @@
// i8 global-array indexed access — sister benchmark to globalArrSum
// that exercises the LDA8absX combine path.
unsigned char globalArr8[100];
unsigned short globalArr8Sum(unsigned short n) {
unsigned short s = 0;
for (unsigned short i = 0; i < n; i++) s += globalArr8[i];
return s;
}

View file

@ -0,0 +1,8 @@
// Fill the first n elements of a global i16 array. Exercises the
// store-side of the W65816UnLSR + STA_AbsX combine for global-array
// loops.
unsigned short globalArrF[100];
void globalArrFill(unsigned short n) {
for (unsigned short i = 0; i < n; i++) globalArrF[i] = i + 1;
}

10
benchmarks/globalArrSum.c Normal file
View file

@ -0,0 +1,10 @@
// Sum the first n elements of a global i16 array. Exercises the
// `arr[i]` indexed-access pattern that the W65816UnLSR pass converts
// back to `lda <global>, X` after LSR turns it into pointer-walking.
unsigned short globalArr[100];
unsigned short globalArrSum(unsigned short n) {
unsigned short s = 0;
for (unsigned short i = 0; i < n; i++) s += globalArr[i];
return s;
}

14
benchmarks/strLen.c Normal file
View file

@ -0,0 +1,14 @@
// strLen: walk pointer until null byte. Exercises the [dp],Y byte-read
// path plus the conditional loop exit. Touches the same DPF0 setup
// pattern as strcpy/memcmp but with only ONE pointer per iter.
//
// The pragma prevents clang from recognising this as a builtin strlen
// and rewriting it as a call to libc (which our benches don't link).
__attribute__((no_builtin("strlen")))
unsigned short strLen(const char *s) {
const char *p = s;
while (*p) {
p++;
}
return (unsigned short)(p - s);
}

View file

@ -1,7 +1,7 @@
############################################################################### ###############################################################################
# # # #
# Calypsi ISO C compiler for 65816 version 5.16 # # Calypsi ISO C compiler for 65816 version 5.16 #
# 14/May/2026 11:06:07 # # 15/May/2026 00:38:15 #
# Command line: --speed -O 2 --64bit-doubles evalAt.c -o # # Command line: --speed -O 2 --64bit-doubles evalAt.c -o #
# /tmp/evalAt.calypsi.elf --list-file evalAt.calypsi.lst # # /tmp/evalAt.calypsi.elf --list-file evalAt.calypsi.lst #
# # # #

View file

@ -8,7 +8,7 @@ evalAt: ; @evalAt
tay tay
tsc tsc
sec sec
sbc #0x46 sbc #0x2e
tcs tcs
tya tya
pha pha
@ -24,7 +24,7 @@ evalAt: ; @evalAt
sta 0x3, s sta 0x3, s
pla pla
stx 0xc0 stx 0xc0
sta 0x19, s sta 0x1b, s
clc clc
adc #0x2 adc #0x2
sta 0x1f, s sta 0x1f, s
@ -33,44 +33,34 @@ evalAt: ; @evalAt
adc #0x0 adc #0x0
sta 0x21, s sta 0x21, s
lda 0x1f, s lda 0x1f, s
sta 0x45, s
lda 0x21, s
sta 0x43, s
lda 0x45, s
sta 0xe0 sta 0xe0
lda 0x43, s lda 0x21, s
sta 0xe2 sta 0xe2
ldy #0x0 ldy #0x0
lda [0xe0], y lda [0xe0], y
sta 0x1d, s sta 0x1f, s
lda 0x19, s
sta 0x41, s
pha pha
lda 0xc0 lda 0xc0
sta 0x41, s sta 0x2f, s
pla pla
lda 0x41, s lda 0x1b, s
sta 0xe0 sta 0xe0
lda 0x3f, s lda 0x2d, s
sta 0xe2 sta 0xe2
lda [0xe0], y lda [0xe0], y
sta 0x21, s sta 0x21, s
lda 0x4a, s lda 0x32, s
sta 0xb, s sta 0xb, s
lda #0x0 lda #0x0
sta 0xc4 sta 0xc4
sta 0xc6 sta 0xc6
lda 0x21, s lda 0x21, s
sta 0x3d, s
lda 0x1d, s
sta 0x3b, s
lda 0x3d, s
sta 0xe0 sta 0xe0
lda 0x3b, s lda 0x1f, s
sta 0xe2 sta 0xe2
lda [0xe0], y lda [0xe0], y
and #0xff and #0xff
sta 0x1b, s sta 0x1d, s
sep #0x20 sep #0x20
clc clc
adc #0xd0 adc #0xd0
@ -93,50 +83,46 @@ evalAt: ; @evalAt
inc a inc a
sta 0x21, s sta 0x21, s
bne .Ltmp0 bne .Ltmp0
lda 0x1d, s lda 0x1f, s
inc a inc a
sta 0x1d, s sta 0x1f, s
.Ltmp0: .Ltmp0:
lda #0x0 lda #0x0
sta 0x15, s sta 0x15, s
sta 0x13, s sta 0x13, s
sta 0x11, s sta 0x11, s
sta 0xf, s sta 0xf, s
lda 0x1d, s lda 0x1f, s
sta 0x17, s sta 0x17, s
.LBB0_2: ; %while.body .LBB0_2: ; %while.body
; =>This Inner Loop Header: Depth=1 ; =>This Inner Loop Header: Depth=1
sta 0x1d, s sta 0x1f, s
lda 0x19, s lda 0x1b, s
tax tax
pha pha
lda 0xc0 lda 0xc0
sta 0x3b, s sta 0x2d, s
pla pla
txa txa
sta 0xe0 sta 0xe0
lda 0x39, s lda 0x2b, s
sta 0xe2 sta 0xe2
lda 0x21, s lda 0x21, s
ldy #0x0 ldy #0x0
sta [0xe0], y sta [0xe0], y
lda 0x19, s lda 0x1b, s
clc clc
adc #0x2 adc #0x2
sta 0xd, s sta 0xd, s
lda 0xc0 lda 0xc0
sta 0x1f, s sta 0x19, s
adc #0x0 adc #0x0
sta 0x1f, s sta 0x19, s
lda 0xd, s lda 0xd, s
sta 0x37, s
lda 0x1f, s
tax
lda 0x37, s
sta 0xe0 sta 0xe0
txa lda 0x19, s
sta 0xe2 sta 0xe2
lda 0x1d, s lda 0x1f, s
sta [0xe0], y sta [0xe0], y
pea 0x4024 pea 0x4024
lda #0x0 lda #0x0
@ -157,24 +143,24 @@ evalAt: ; @evalAt
adc #0xc adc #0xc
tcs tcs
lda 0xe0 lda 0xe0
sta 0x1f, s sta 0x19, s
txa txa
sta 0x15, s sta 0x15, s
tya tya
sta 0x13, s sta 0x13, s
lda 0xf0 lda 0xf0
sta 0x11, s sta 0x11, s
lda 0x1b, s lda 0x1d, s
sep #0x20 sep #0x20
clc clc
adc #0xd0 adc #0xd0
rep #0x20 rep #0x20
and #0xff and #0xff
sta 0x1b, s sta 0x1d, s
ldx #0x0 ldx #0x0
lda 0x1b, s lda 0x1d, s
jsl __floatunsidf jsl __floatunsidf
sta 0x1b, s sta 0x1d, s
txa txa
sta 0xf, s sta 0xf, s
tya tya
@ -185,7 +171,7 @@ evalAt: ; @evalAt
lda 0x13, s lda 0x13, s
tax tax
phx phx
lda 0x21, s lda 0x23, s
pha pha
lda 0x19, s lda 0x19, s
pha pha
@ -193,7 +179,7 @@ evalAt: ; @evalAt
pha pha
lda 0x21, s lda 0x21, s
tax tax
lda 0x2b, s lda 0x25, s
jsl __adddf3 jsl __adddf3
sta 0xe0 sta 0xe0
tsc tsc
@ -217,7 +203,7 @@ evalAt: ; @evalAt
sta 0x21, s sta 0x21, s
txa txa
lda 0xd0 lda 0xd0
sta 0x1f, s sta 0x1d, s
lda 0x17, s lda 0x17, s
adc #0x0 adc #0x0
sta 0x17, s sta 0x17, s
@ -229,18 +215,14 @@ evalAt: ; @evalAt
sta 0xc4 sta 0xc4
lda 0x13, s lda 0x13, s
sta 0xc6 sta 0xc6
lda 0x1f, s
sta 0x35, s
lda 0x1d, s lda 0x1d, s
tax
lda 0x35, s
sta 0xe0 sta 0xe0
txa lda 0x1f, s
sta 0xe2 sta 0xe2
ldy #0x0 ldy #0x0
lda [0xe0], y lda [0xe0], y
and #0xff and #0xff
sta 0x1b, s sta 0x1d, s
sep #0x20 sep #0x20
clc clc
adc #0xd0 adc #0xd0
@ -259,17 +241,17 @@ evalAt: ; @evalAt
sta 0x21, s sta 0x21, s
lda 0x17, s lda 0x17, s
adc #0xffff adc #0xffff
sta 0x1d, s sta 0x1f, s
.LBB0_4: ; %while.cond7.preheader .LBB0_4: ; %while.cond7.preheader
lda 0xb, s lda 0xb, s
eor #0x8000 eor #0x8000
sta 0xb, s sta 0xb, s
lda 0x1b, s lda 0x1d, s
brl .LBB0_5 brl .LBB0_5
.LBB0_11: ; %if.then33 .LBB0_11: ; %if.then33
; in Loop: Header=BB0_5 Depth=1 ; in Loop: Header=BB0_5 Depth=1
lda 0xc6 lda 0xc6
sta 0x1b, s sta 0x1d, s
lda 0xc4 lda 0xc4
sta 0x15, s sta 0x15, s
lda 0xca lda 0xca
@ -278,7 +260,7 @@ evalAt: ; @evalAt
sta 0x11, s sta 0x11, s
lda 0x17, s lda 0x17, s
pha pha
lda 0x1f, s lda 0x1b, s
pha pha
lda 0x23, s lda 0x23, s
pha pha
@ -288,7 +270,7 @@ evalAt: ; @evalAt
pha pha
lda 0x1b, s lda 0x1b, s
pha pha
lda 0x27, s lda 0x29, s
tax tax
lda 0x21, s lda 0x21, s
jsl __muldf3 jsl __muldf3
@ -306,10 +288,10 @@ evalAt: ; @evalAt
tya tya
sta 0x1d, s sta 0x1d, s
lda 0xf0 lda 0xf0
sta 0x1b, s sta 0x19, s
lda 0x1d, s lda 0x1d, s
sta 0xc8 sta 0xc8
lda 0x1b, s lda 0x19, s
sta 0xca sta 0xca
lda 0x21, s lda 0x21, s
sta 0xc4 sta 0xc4
@ -317,7 +299,7 @@ evalAt: ; @evalAt
sta 0xc6 sta 0xc6
.LBB0_13: ; %cleanup .LBB0_13: ; %cleanup
; in Loop: Header=BB0_5 Depth=1 ; in Loop: Header=BB0_5 Depth=1
lda 0x19, s lda 0x1b, s
clc clc
adc #0x2 adc #0x2
sta 0x1f, s sta 0x1f, s
@ -326,17 +308,13 @@ evalAt: ; @evalAt
adc #0x0 adc #0x0
sta 0x21, s sta 0x21, s
lda 0x1f, s lda 0x1f, s
sta 0x25, s
lda 0x21, s
tax
lda 0x25, s
sta 0xe0 sta 0xe0
txa lda 0x21, s
sta 0xe2 sta 0xe2
ldy #0x0 ldy #0x0
lda [0xe0], y lda [0xe0], y
sta 0x1d, s sta 0x1f, s
lda 0x19, s lda 0x1b, s
tax tax
pha pha
lda 0xc0 lda 0xc0
@ -348,30 +326,27 @@ evalAt: ; @evalAt
sta 0xe2 sta 0xe2
lda [0xe0], y lda [0xe0], y
sta 0x21, s sta 0x21, s
lda 0x1d, s
tax
lda 0x21, s
sta 0xe0 sta 0xe0
txa lda 0x1f, s
sta 0xe2 sta 0xe2
lda [0xe0], y lda [0xe0], y
and #0xff and #0xff
.LBB0_5: ; %while.cond7 .LBB0_5: ; %while.cond7
; =>This Inner Loop Header: Depth=1 ; =>This Inner Loop Header: Depth=1
sta 0x1b, s sta 0x1d, s
sep #0x20 sep #0x20
clc clc
adc #0xd6 adc #0xd6
rep #0x20 rep #0x20
and #0xff and #0xff
sta 0x1f, s sta 0x19, s
lda 0x1f, s lda 0x19, s
pha pha
lda #0x2b lda #0x2b
jsl __lshrhi3 jsl __lshrhi3
ply ply
sta 0x17, s sta 0x17, s
lda 0x1f, s lda 0x19, s
cmp #0x6 cmp #0x6
bcc .LBB0_6 bcc .LBB0_6
; %bb.17: ; %while.cond7 ; %bb.17: ; %while.cond7
@ -382,58 +357,23 @@ evalAt: ; @evalAt
and #0x1 and #0x1
sta 0x17, s sta 0x17, s
lda #0x0 lda #0x0
sta 0x33, s sta 0x29, s
lda 0x17, s lda 0x17, s
ora 0x33, s ora 0x29, s
bne .LBB0_7 bne .LBB0_7
; %bb.18: ; %while.cond7 ; %bb.18: ; %while.cond7
brl .LBB0_14 brl .LBB0_14
.LBB0_7: ; %switch.lookup .LBB0_7: ; %switch.lookup
; in Loop: Header=BB0_5 Depth=1 ; in Loop: Header=BB0_5 Depth=1
lda #0x0 lda 0x19, s
asl a asl a
sta 0x17, s
lda 0x1f, s
asl a
lda #0x0
rol a
sta 0x31, s
lda 0x17, s
ora 0x31, s
sta 0x17, s
lda 0x1f, s
asl a
sta 0x1f, s
lda #.Lswitch.table.evalAt
sta 0x2f, s
lda 0x1f, s
clc
adc 0x2f, s
sta 0x1f, s
lda #0x0
sta 0x2d, s
lda 0x17, s
adc 0x2d, s
sta 0x17, s
lda 0x1f, s
sta 0x2b, s
lda 0x17, s
tax
lda 0x2b, s
sta 0xe0
txa
sta 0xe2
ldy #0x0
lda [0xe0 ], y
sta 0x1f, s
lda 0x1f, s
tax tax
lda .Lswitch.table.evalAt, x
sta 0x19, s
eor #0x8000 eor #0x8000
sta 0x1f, s sta 0x27, s
txa
sta 0x17, s
lda 0xb, s lda 0xb, s
cmp 0x1f, s cmp 0x27, s
bcc .LBB0_8 bcc .LBB0_8
; %bb.19: ; %switch.lookup ; %bb.19: ; %switch.lookup
brl .LBB0_14 brl .LBB0_14
@ -443,44 +383,40 @@ evalAt: ; @evalAt
inc a inc a
sta 0x21, s sta 0x21, s
bne .Ltmp1 bne .Ltmp1
lda 0x1d, s lda 0x1f, s
inc a inc a
sta 0x1d, s sta 0x1f, s
.Ltmp1: .Ltmp1:
lda 0x19, s lda 0x1b, s
tax tax
pha pha
lda 0xc0 lda 0xc0
sta 0x2b, s sta 0x27, s
pla pla
txa txa
sta 0xe0 sta 0xe0
lda 0x29, s lda 0x25, s
sta 0xe2 sta 0xe2
lda 0x21, s lda 0x21, s
ldy #0x0 ldy #0x0
sta [0xe0], y sta [0xe0], y
lda 0x19, s lda 0x1b, s
sta 0xd0 sta 0xd0
clc clc
adc #0x2 adc #0x2
sta 0x1f, s sta 0x17, s
lda 0xd0 lda 0xd0
sta 0x21, s sta 0x21, s
lda 0xc0 lda 0xc0
adc #0x0 adc #0x0
sta 0x15, s sta 0x15, s
lda 0x1f, s
sta 0x27, s
lda 0x15, s
tax
lda 0x27, s
sta 0xe0
txa
sta 0xe2
lda 0x1d, s
sta [0xe0 ], y
lda 0x17, s lda 0x17, s
sta 0xe0
lda 0x15, s
sta 0xe2
lda 0x1f, s
sta [0xe0], y
lda 0x19, s
pha pha
ldx 0xc0 ldx 0xc0
lda 0x23, s lda 0x23, s
@ -495,10 +431,10 @@ evalAt: ; @evalAt
txa txa
sta 0x1f, s sta 0x1f, s
tya tya
sta 0x1d, s sta 0x19, s
lda 0xf0 lda 0xf0
sta 0x17, s sta 0x17, s
lda 0x1b, s lda 0x1d, s
and #0xff and #0xff
cmp #0x2a cmp #0x2a
bne .LBB0_9 bne .LBB0_9
@ -515,7 +451,7 @@ evalAt: ; @evalAt
.LBB0_10: ; %if.then29 .LBB0_10: ; %if.then29
; in Loop: Header=BB0_5 Depth=1 ; in Loop: Header=BB0_5 Depth=1
lda 0xc6 lda 0xc6
sta 0x1b, s sta 0x1d, s
lda 0xc4 lda 0xc4
sta 0x15, s sta 0x15, s
lda 0xca lda 0xca
@ -524,7 +460,7 @@ evalAt: ; @evalAt
sta 0x11, s sta 0x11, s
lda 0x17, s lda 0x17, s
pha pha
lda 0x1f, s lda 0x1b, s
pha pha
lda 0x23, s lda 0x23, s
pha pha
@ -534,7 +470,7 @@ evalAt: ; @evalAt
pha pha
lda 0x1b, s lda 0x1b, s
pha pha
lda 0x27, s lda 0x29, s
tax tax
lda 0x21, s lda 0x21, s
jsl __adddf3 jsl __adddf3
@ -570,7 +506,7 @@ evalAt: ; @evalAt
sta 0xe0 sta 0xe0
tsc tsc
clc clc
adc #0x46 adc #0x2e
tcs tcs
lda 0xe0 lda 0xe0
rtl rtl

View file

@ -1,7 +1,7 @@
############################################################################### ###############################################################################
# # # #
# Calypsi ISO C compiler for 65816 version 5.16 # # Calypsi ISO C compiler for 65816 version 5.16 #
# 14/May/2026 11:06:07 # # 15/May/2026 00:38:15 #
# Command line: --speed -O 2 --64bit-doubles mul16to32.c -o # # Command line: --speed -O 2 --64bit-doubles mul16to32.c -o #
# /tmp/mul16to32.calypsi.elf --list-file # # /tmp/mul16to32.calypsi.elf --list-file #
# mul16to32.calypsi.lst # # mul16to32.calypsi.lst #

View file

@ -5,11 +5,7 @@
mul16to32: ; @mul16to32 mul16to32: ; @mul16to32
; %bb.0: ; %entry ; %bb.0: ; %entry
rep #0x30 rep #0x30
pha jml __umulhisi3
lda 0x6, s
jsl __umulhisi3
ply
rtl
.Lfunc_end0: .Lfunc_end0:
.size mul16to32, .Lfunc_end0-mul16to32 .size mul16to32, .Lfunc_end0-mul16to32
; -- End function ; -- End function

View file

@ -1,7 +1,7 @@
############################################################################### ###############################################################################
# # # #
# Calypsi ISO C compiler for 65816 version 5.16 # # Calypsi ISO C compiler for 65816 version 5.16 #
# 14/May/2026 11:06:07 # # 15/May/2026 00:38:15 #
# Command line: --speed -O 2 --64bit-doubles sumSquares.c -o # # Command line: --speed -O 2 --64bit-doubles sumSquares.c -o #
# /tmp/sumSquares.calypsi.elf --list-file # # /tmp/sumSquares.calypsi.elf --list-file #
# sumSquares.calypsi.lst # # sumSquares.calypsi.lst #

View file

@ -31,8 +31,7 @@ sumSquares: ; @sumSquares
sta 0xd4 sta 0xd4
inc 0xd2 inc 0xd2
dec 0xd0 dec 0xd0
beq .LBB0_5 bne .LBB0_4
bra .LBB0_4
.LBB0_5: ; %for.cond.cleanup .LBB0_5: ; %for.cond.cleanup
lda 0xd4 lda 0xd4
tax tax

149
demos/README.md Normal file
View file

@ -0,0 +1,149 @@
# 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.
### `orcaFrameLike.c`
Port of ORCA-C's `Frame.cc` sample (`tools/orca-c/C.Samples/
Desktop.Samples/Frame.cc`). Builds a standard Apple+File+Edit
menu bar (`NewMenu` + `InsertMenu` + `FixAppleMenu` + `DrawMenuBar`)
and dispatches `wInMenuBar` / `wInSpecial` events from `TaskMaster`.
File→Quit exits. Skips the original's Dialog Manager About box.
### `orcaMiniCadLike.c`
Port of ORCA-C's `MiniCAD.cc` (`Desktop.Samples/MiniCAD.cc`). Slim
port — opens a Window Manager content window but omits the line-
drawing primitives because adding them pushes past the Loader's
cRELOC threshold. Demonstrates the NewWindow path under
`startdesk`.
### `orcaReversiLike.c`
Port of ORCA-C's `Reversi.cc` (`Desktop.Samples/Reversi.cc`).
Menu-bar app — the ~1600 line game logic is omitted; the demo
shows the desktop scaffolding (menu + TaskMaster) the original
sits on top of.
### `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.

61
demos/build.sh Executable file
View file

@ -0,0 +1,61 @@
#!/usr/bin/env bash
# build.sh - compile a demo C source into a GS/OS-loadable OMF.
#
# Usage: bash demos/build.sh <basename>
# where demos/<basename>.c is the source. Output is
# demos/<basename>.omf in the same directory.
#
# Uses crt0Gsos (the GS/OS-aware crt) and ExpressLoad-wrapped multi-
# seg OMF so the slow-Loader rejection path is avoided. The OMF
# launches via runViaFinder.sh after cadius-injection onto the GS/OS
# data disk.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
[ $# -ge 1 ] || { echo "usage: $0 <basename>" >&2; exit 2; }
BASE="$1"
SRC="$SCRIPT_DIR/$BASE.c"
[ -f "$SRC" ] || { echo "no source: $SRC" >&2; exit 2; }
CLANG="$PROJECT_ROOT/tools/llvm-mos-build/bin/clang"
LINK="$PROJECT_ROOT/tools/link816"
OMF="$PROJECT_ROOT/tools/omfEmit"
OBJ="$SCRIPT_DIR/$BASE.o"
BIN="$SCRIPT_DIR/$BASE.bin"
MAP="$SCRIPT_DIR/$BASE.map"
RELOC="$SCRIPT_DIR/$BASE.reloc"
OUT="$SCRIPT_DIR/$BASE.omf"
echo "compile: $BASE.c -> $BASE.o"
"$CLANG" --target=w65816 -I"$PROJECT_ROOT/runtime/include" \
-O2 -ffunction-sections -c "$SRC" -o "$OBJ"
echo "link: -> $BASE.bin"
# bss-base 0xA000 keeps BSS above the SHR shadow region ($2000-$9FFF
# in bank 0 mirrors to bank E1 SHR memory). Without this, the smaller
# section-gc'd demos place BSS at e.g. $2300 and global writes scribble
# on the screen.
"$LINK" -o "$BIN" --text-base 0x1000 --bss-base 0xA000 \
--map "$MAP" --reloc-out "$RELOC" \
"$PROJECT_ROOT/runtime/crt0Gsos.o" "$OBJ" \
"$PROJECT_ROOT/runtime/libc.o" \
"$PROJECT_ROOT/runtime/snprintf.o" \
"$PROJECT_ROOT/runtime/extras.o" \
"$PROJECT_ROOT/runtime/softFloat.o" \
"$PROJECT_ROOT/runtime/softDouble.o" \
"$PROJECT_ROOT/runtime/iigsGsos.o" \
"$PROJECT_ROOT/runtime/iigsToolbox.o" \
"$PROJECT_ROOT/runtime/desktop.o" \
"$PROJECT_ROOT/runtime/libgcc.o"
echo "OMF: -> $BASE.omf"
"$OMF" --input "$BIN" --map "$MAP" \
--base 0x1000 --entry __start --output "$OUT" \
--name "$(echo "$BASE" | tr '[:lower:]' '[:upper:]' | cut -c1-8)" \
--expressload --relocs "$RELOC"
ls -la "$OUT"
echo "done: $OUT"

BIN
demos/frame.bin Normal file

Binary file not shown.

97
demos/frame.c Normal file
View file

@ -0,0 +1,97 @@
// frame.c - full port of ORCA-C's Frame.cc sample.
//
// Mike Westerfield's "Frame" desktop demo (Byte Works, 1989).
// Original at tools/orca-c/C.Samples/Desktop.Samples/Frame.cc.
//
// Uses the real ROM Menu Manager — startdesk's QD-DP allocation now
// reserves the full 512 bytes QD needs (own DP + cursor mgr at +$100),
// plus calls InitCursor. See feedback_drawmenubar_hang.md.
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
#define apple_About 257
#define file_Quit 256
typedef struct { short v1, h1, v2, h2; } Rect;
// Menu definition strings — verbatim from Frame.cc.
static unsigned char appleMenuStr[] =
">>@\\XN1\r"
"--About Frame\\N257V\r"
".\r";
static unsigned char fileMenuStr[] =
">> File \\N2\r"
"--Close\\N255V\r"
"--Quit\\N256*Qq\r"
".\r";
static unsigned char editMenuStr[] =
">> Edit \\N3\r"
"--Undo\\N250V*Zz\r"
"--Cut\\N251*Xx\r"
"--Copy\\N252*Cc\r"
"--Paste\\N253*Vv\r"
"--Clear\\N254\r"
".\r";
// About-box message lines.
static const unsigned char line1[] = "\x09" "Frame 1.0";
static const unsigned char line2[] = "\x0e" "Copyright 1989";
static const unsigned char line3[] = "\x10" "Byte Works, Inc.";
static const unsigned char line4[] = "\x13" "By Mike Westerfield";
static const unsigned char btnOk[] = "\x02" "OK";
static void drawAbout(void) {
Rect outer;
outer.h1 = 180; outer.v1 = 50;
outer.h2 = 460; outer.v2 = 107;
SetSolidPenPat(15);
PaintRect(&outer);
SetSolidPenPat(0);
FrameRect(&outer);
MoveTo(195, 64); DrawString((void *)line1);
MoveTo(195, 74); DrawString((void *)line2);
MoveTo(195, 84); DrawString((void *)line3);
MoveTo(195, 94); DrawString((void *)line4);
Rect ok;
ok.h1 = 395; ok.v1 = 88;
ok.h2 = 445; ok.v2 = 102;
FrameRect(&ok);
MoveTo(412, 98);
DrawString((void *)btnOk);
}
static void initMenus(void) {
InsertMenu(NewMenu(editMenuStr), 0);
InsertMenu(NewMenu(fileMenuStr), 0);
InsertMenu(NewMenu(appleMenuStr), 0);
FixAppleMenu(1);
FixMenuBar();
DrawMenuBar();
}
int main(void) {
unsigned short userId = startdesk(640);
(void)userId;
initMenus();
ShowCursor();
for (volatile unsigned long s = 0; s < 100000UL; s++) { }
drawAbout();
for (volatile unsigned long s = 0; s < 200000UL; s++) { }
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

213
demos/frame.map Normal file
View file

@ -0,0 +1,213 @@
# section layout
.text : 0x001000 .. 0x0024b3 ( 5299 bytes)
.rodata : 0x0024b3 .. 0x0025b2 ( 255 bytes)
.bss : 0x00a000 .. 0x00a00a ( 10 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
1287 /home/scott/claude/llvm816/demos/frame.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1349 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x00000a __bss_seg0_size
0x00000a __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x0015c1 CtlStartUp
0x0015d1 EMStartUp
0x0015f0 FMStartUp
0x001600 LEStartUp
0x001610 LoadOneTool
0x001620 NewHandle
0x001646 MenuStartUp
0x001656 InsertMenu
0x00166b NewMenu
0x001685 QDStartUp
0x00169b DrawString
0x0016ad FrameRect
0x0016bf MoveTo
0x0016cf PaintRect
0x0016e1 startdesk
0x001ac7 __jsl_indir
0x001aca __mulhi3
0x001ae9 __umulhisi3
0x001b40 __ashlhi3
0x001b4f __lshrhi3
0x001b5f __ashrhi3
0x001b72 __udivhi3
0x001b7e __umodhi3
0x001b8a __divhi3
0x001ba4 __modhi3
0x001bbe __divmod_setup
0x001bf1 __udivmod_core
0x001c0f __mulsi3
0x001cc8 __ashlsi3
0x001cdd __lshrsi3
0x001cf2 __ashrsi3
0x001d0c __udivmodsi_core
0x001d44 __udivsi3
0x001d58 __umodsi3
0x001d6c __divsi3
0x001d93 __modsi3
0x001dba __divmodsi_setup
0x001e0b __divmoddi4_stash
0x001e28 __retdi
0x001e35 __ashldi3
0x001e58 __lshrdi3
0x001e7b __ashrdi3
0x001ea1 __muldi3
0x001efc __ucmpdi2
0x001f25 __cmpdi2
0x001f5c __udivdi3
0x001f65 __umoddi3
0x001f7e __udivmoddi_core
0x001fcb __divdi3
0x001fea __moddi3
0x002017 __absdi_a
0x00201f __absdi_b
0x002027 __negdi_a
0x002045 __negdi_b
0x002063 setjmp
0x00208b longjmp
0x0020b5 __umulhisi3_qsq
0x0024b3 __rodata_start
0x0024b3 __text_end
0x0024b3 gChainPath
0x0024c7 editMenuStr
0x002520 fileMenuStr
0x00254d appleMenuStr
0x00256c line1
0x002577 line2
0x002587 line3
0x002599 line4
0x0025ae btnOk
0x0025b2 __init_array_end
0x0025b2 __init_array_start
0x0025b2 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gUserId
0x00a002 gDpHandle
0x00a006 gDpBase
0x00a008 __indirTarget
0x00a00a __bss_end
0x00a00a __heap_start
0x00bf00 __heap_end
CtlStartUp = 0x0015c1
DrawString = 0x00169b
EMStartUp = 0x0015d1
FMStartUp = 0x0015f0
FrameRect = 0x0016ad
InsertMenu = 0x001656
LEStartUp = 0x001600
LoadOneTool = 0x001610
MenuStartUp = 0x001646
MoveTo = 0x0016bf
NewHandle = 0x001620
NewMenu = 0x00166b
PaintRect = 0x0016cf
QDStartUp = 0x001685
__absdi_a = 0x002017
__absdi_b = 0x00201f
__ashldi3 = 0x001e35
__ashlhi3 = 0x001b40
__ashlsi3 = 0x001cc8
__ashrdi3 = 0x001e7b
__ashrhi3 = 0x001b5f
__ashrsi3 = 0x001cf2
__bss_bank = 0x000000
__bss_end = 0x00a00a
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x00000a
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x00000a
__bss_start = 0x00a000
__cmpdi2 = 0x001f25
__divdi3 = 0x001fcb
__divhi3 = 0x001b8a
__divmod_setup = 0x001bbe
__divmoddi4_stash = 0x001e0b
__divmodsi_setup = 0x001dba
__divsi3 = 0x001d6c
__heap_end = 0x00bf00
__heap_start = 0x00a00a
__indirTarget = 0x00a008
__init_array_end = 0x0025b2
__init_array_start = 0x0025b2
__jsl_indir = 0x001ac7
__lshrdi3 = 0x001e58
__lshrhi3 = 0x001b4f
__lshrsi3 = 0x001cdd
__moddi3 = 0x001fea
__modhi3 = 0x001ba4
__modsi3 = 0x001d93
__muldi3 = 0x001ea1
__mulhi3 = 0x001aca
__mulsi3 = 0x001c0f
__negdi_a = 0x002027
__negdi_b = 0x002045
__retdi = 0x001e28
__rodata_end = 0x0025b2
__rodata_start = 0x0024b3
__start = 0x001000
__text_end = 0x0024b3
__text_start = 0x001000
__ucmpdi2 = 0x001efc
__udivdi3 = 0x001f5c
__udivhi3 = 0x001b72
__udivmod_core = 0x001bf1
__udivmoddi_core = 0x001f7e
__udivmodsi_core = 0x001d0c
__udivsi3 = 0x001d44
__umoddi3 = 0x001f65
__umodhi3 = 0x001b7e
__umodsi3 = 0x001d58
__umulhisi3 = 0x001ae9
__umulhisi3_qsq = 0x0020b5
appleMenuStr = 0x00254d
btnOk = 0x0025ae
editMenuStr = 0x0024c7
fileMenuStr = 0x002520
gChainPath = 0x0024b3
gDpBase = 0x00a006
gDpHandle = 0x00a002
gUserId = 0x00a000
line1 = 0x00256c
line2 = 0x002577
line3 = 0x002587
line4 = 0x002599
longjmp = 0x00208b
main = 0x0010ba
setjmp = 0x002063
startdesk = 0x0016e1

BIN
demos/frame.o Normal file

Binary file not shown.

BIN
demos/frame.omf Normal file

Binary file not shown.

BIN
demos/frame.reloc Normal file

Binary file not shown.

BIN
demos/heavyRelocs.bin Normal file

Binary file not shown.

38
demos/heavyRelocs.c Normal file
View file

@ -0,0 +1,38 @@
// heavyRelocs.c - stress test for ExpressLoad cRELOC handling.
#include "iigs/toolbox.h"
// Code padding via large initialized data (NOT const so it lands in
// .data and survives -O2 dead-strip).
volatile unsigned char gBigData[20000] = { [0 ... 19999] = 0xAA };
static unsigned char gA[16], gB[16], gC[16], gD[16];
static unsigned char gE[16], gF[16], gG[16], gH[16];
static unsigned char gI[16], gJ[16], gK[16], gL[16];
static unsigned char gM[16], gN[16], gO[16], gP[16];
static unsigned char gQ[16], gR[16], gS[16], gT[16];
static unsigned char gU[16], gV[16], gW[16], gX[16];
static unsigned char gY[16], gZ[16];
static unsigned char *gPtrs[100] = {
gA, gB, gC, gD, gE, gF, gG, gH, gI, gJ,
gK, gL, gM, gN, gO, gP, gQ, gR, gS, gT,
gU, gV, gW, gX, gY, gZ, gA, gB, gC, gD,
gE, gF, gG, gH, gI, gJ, gK, gL, gM, gN,
gO, gP, gQ, gR, gS, gT, gU, gV, gW, gX,
gY, gZ, gA, gB, gC, gD, gE, gF, gG, gH,
gI, gJ, gK, gL, gM, gN, gO, gP, gQ, gR,
gS, gT, gU, gV, gW, gX, gY, gZ, gA, gB,
gC, gD, gE, gF, gG, gH, gI, gJ, gK, gL,
gM, gN, gO, gP, gQ, gR, gS, gT, gU, gV,
};
int main(void) {
for (unsigned short i = 0; i < 100; i++) {
gPtrs[i][0] = (unsigned char)i;
}
gA[0] = gBigData[0] + gBigData[19999];
*(volatile unsigned char *)0x70 = 0x99;
// Brief linger for snapshot capture.
for (volatile unsigned long s = 0; s < 600000UL; s++) { }
return 0;
}

217
demos/heavyRelocs.map Normal file
View file

@ -0,0 +1,217 @@
# section layout
.text : 0x001000 .. 0x001caa ( 3242 bytes)
.rodata : 0x001caa .. 0x006c6e ( 20420 bytes)
.bss : 0x00a000 .. 0x00a1a2 ( 418 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
516 /home/scott/claude/llvm816/demos/heavyRelocs.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1349 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x0001a2 __bss_seg0_size
0x0001a2 __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x0012be __jsl_indir
0x0012c1 __mulhi3
0x0012e0 __umulhisi3
0x001337 __ashlhi3
0x001346 __lshrhi3
0x001356 __ashrhi3
0x001369 __udivhi3
0x001375 __umodhi3
0x001381 __divhi3
0x00139b __modhi3
0x0013b5 __divmod_setup
0x0013e8 __udivmod_core
0x001406 __mulsi3
0x0014bf __ashlsi3
0x0014d4 __lshrsi3
0x0014e9 __ashrsi3
0x001503 __udivmodsi_core
0x00153b __udivsi3
0x00154f __umodsi3
0x001563 __divsi3
0x00158a __modsi3
0x0015b1 __divmodsi_setup
0x001602 __divmoddi4_stash
0x00161f __retdi
0x00162c __ashldi3
0x00164f __lshrdi3
0x001672 __ashrdi3
0x001698 __muldi3
0x0016f3 __ucmpdi2
0x00171c __cmpdi2
0x001753 __udivdi3
0x00175c __umoddi3
0x001775 __udivmoddi_core
0x0017c2 __divdi3
0x0017e1 __moddi3
0x00180e __absdi_a
0x001816 __absdi_b
0x00181e __negdi_a
0x00183c __negdi_b
0x00185a setjmp
0x001882 longjmp
0x0018ac __umulhisi3_qsq
0x001caa __rodata_start
0x001caa __text_end
0x001caa gChainPath
0x001cbe gBigData
0x006ade gPtrs
0x006c6e __init_array_end
0x006c6e __init_array_start
0x006c6e __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gA
0x00a010 gB
0x00a020 gC
0x00a030 gD
0x00a040 gE
0x00a050 gF
0x00a060 gG
0x00a070 gH
0x00a080 gI
0x00a090 gJ
0x00a0a0 gK
0x00a0b0 gL
0x00a0c0 gM
0x00a0d0 gN
0x00a0e0 gO
0x00a0f0 gP
0x00a100 gQ
0x00a110 gR
0x00a120 gS
0x00a130 gT
0x00a140 gU
0x00a150 gV
0x00a160 gW
0x00a170 gX
0x00a180 gY
0x00a190 gZ
0x00a1a0 __indirTarget
0x00a1a2 __bss_end
0x00a1a2 __heap_start
0x00bf00 __heap_end
__absdi_a = 0x00180e
__absdi_b = 0x001816
__ashldi3 = 0x00162c
__ashlhi3 = 0x001337
__ashlsi3 = 0x0014bf
__ashrdi3 = 0x001672
__ashrhi3 = 0x001356
__ashrsi3 = 0x0014e9
__bss_bank = 0x000000
__bss_end = 0x00a1a2
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x0001a2
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x0001a2
__bss_start = 0x00a000
__cmpdi2 = 0x00171c
__divdi3 = 0x0017c2
__divhi3 = 0x001381
__divmod_setup = 0x0013b5
__divmoddi4_stash = 0x001602
__divmodsi_setup = 0x0015b1
__divsi3 = 0x001563
__heap_end = 0x00bf00
__heap_start = 0x00a1a2
__indirTarget = 0x00a1a0
__init_array_end = 0x006c6e
__init_array_start = 0x006c6e
__jsl_indir = 0x0012be
__lshrdi3 = 0x00164f
__lshrhi3 = 0x001346
__lshrsi3 = 0x0014d4
__moddi3 = 0x0017e1
__modhi3 = 0x00139b
__modsi3 = 0x00158a
__muldi3 = 0x001698
__mulhi3 = 0x0012c1
__mulsi3 = 0x001406
__negdi_a = 0x00181e
__negdi_b = 0x00183c
__retdi = 0x00161f
__rodata_end = 0x006c6e
__rodata_start = 0x001caa
__start = 0x001000
__text_end = 0x001caa
__text_start = 0x001000
__ucmpdi2 = 0x0016f3
__udivdi3 = 0x001753
__udivhi3 = 0x001369
__udivmod_core = 0x0013e8
__udivmoddi_core = 0x001775
__udivmodsi_core = 0x001503
__udivsi3 = 0x00153b
__umoddi3 = 0x00175c
__umodhi3 = 0x001375
__umodsi3 = 0x00154f
__umulhisi3 = 0x0012e0
__umulhisi3_qsq = 0x0018ac
gA = 0x00a000
gB = 0x00a010
gBigData = 0x001cbe
gC = 0x00a020
gChainPath = 0x001caa
gD = 0x00a030
gE = 0x00a040
gF = 0x00a050
gG = 0x00a060
gH = 0x00a070
gI = 0x00a080
gJ = 0x00a090
gK = 0x00a0a0
gL = 0x00a0b0
gM = 0x00a0c0
gN = 0x00a0d0
gO = 0x00a0e0
gP = 0x00a0f0
gPtrs = 0x006ade
gQ = 0x00a100
gR = 0x00a110
gS = 0x00a120
gT = 0x00a130
gU = 0x00a140
gV = 0x00a150
gW = 0x00a160
gX = 0x00a170
gY = 0x00a180
gZ = 0x00a190
longjmp = 0x001882
main = 0x0010ba
setjmp = 0x00185a

BIN
demos/heavyRelocs.o Normal file

Binary file not shown.

BIN
demos/heavyRelocs.omf Normal file

Binary file not shown.

BIN
demos/heavyRelocs.reloc Normal file

Binary file not shown.

BIN
demos/helloBeep.bin Normal file

Binary file not shown.

25
demos/helloBeep.c Normal file
View file

@ -0,0 +1,25 @@
// helloBeep.c - simplest possible GS/OS app. Three SysBeep calls then
// exit. Verifies the OMF + Loader path: if the IIgs makes three beeps,
// the app launched, ran, and returned cleanly.
//
// No toolbox startup is needed - the Loader has already done TLStartUp
// + MMStartUp for us, and SysBeep is a Misc Tools call that works
// without additional setup.
//
// Build with: bash demos/build.sh helloBeep
// Run with: bash scripts/runViaFinder.sh helloBeep.omf --check 0x70=0x42
#include "iigs/toolbox.h"
int main(void) {
SysBeep();
SysBeep();
SysBeep();
*(volatile unsigned char *)0x70 = 0x99; // for headless verify
// Brief linger so snapshot tools can capture the post-Finder state
// before we exit (otherwise the screen snaps in the middle of GS/OS
// tearing the launcher state down).
for (volatile unsigned long s = 0; s < 600000UL; s++) { }
return 0;
}

161
demos/helloBeep.map Normal file
View file

@ -0,0 +1,161 @@
# section layout
.text : 0x001000 .. 0x001c37 ( 3127 bytes)
.rodata : 0x001c37 .. 0x001c4b ( 20 bytes)
.bss : 0x00a000 .. 0x00a002 ( 2 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
401 /home/scott/claude/llvm816/demos/helloBeep.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1349 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x000002 __bss_seg0_size
0x000002 __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x00124b __jsl_indir
0x00124e __mulhi3
0x00126d __umulhisi3
0x0012c4 __ashlhi3
0x0012d3 __lshrhi3
0x0012e3 __ashrhi3
0x0012f6 __udivhi3
0x001302 __umodhi3
0x00130e __divhi3
0x001328 __modhi3
0x001342 __divmod_setup
0x001375 __udivmod_core
0x001393 __mulsi3
0x00144c __ashlsi3
0x001461 __lshrsi3
0x001476 __ashrsi3
0x001490 __udivmodsi_core
0x0014c8 __udivsi3
0x0014dc __umodsi3
0x0014f0 __divsi3
0x001517 __modsi3
0x00153e __divmodsi_setup
0x00158f __divmoddi4_stash
0x0015ac __retdi
0x0015b9 __ashldi3
0x0015dc __lshrdi3
0x0015ff __ashrdi3
0x001625 __muldi3
0x001680 __ucmpdi2
0x0016a9 __cmpdi2
0x0016e0 __udivdi3
0x0016e9 __umoddi3
0x001702 __udivmoddi_core
0x00174f __divdi3
0x00176e __moddi3
0x00179b __absdi_a
0x0017a3 __absdi_b
0x0017ab __negdi_a
0x0017c9 __negdi_b
0x0017e7 setjmp
0x00180f longjmp
0x001839 __umulhisi3_qsq
0x001c37 __rodata_start
0x001c37 __text_end
0x001c37 gChainPath
0x001c4b __init_array_end
0x001c4b __init_array_start
0x001c4b __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 __indirTarget
0x00a002 __bss_end
0x00a002 __heap_start
0x00bf00 __heap_end
__absdi_a = 0x00179b
__absdi_b = 0x0017a3
__ashldi3 = 0x0015b9
__ashlhi3 = 0x0012c4
__ashlsi3 = 0x00144c
__ashrdi3 = 0x0015ff
__ashrhi3 = 0x0012e3
__ashrsi3 = 0x001476
__bss_bank = 0x000000
__bss_end = 0x00a002
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x000002
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x000002
__bss_start = 0x00a000
__cmpdi2 = 0x0016a9
__divdi3 = 0x00174f
__divhi3 = 0x00130e
__divmod_setup = 0x001342
__divmoddi4_stash = 0x00158f
__divmodsi_setup = 0x00153e
__divsi3 = 0x0014f0
__heap_end = 0x00bf00
__heap_start = 0x00a002
__indirTarget = 0x00a000
__init_array_end = 0x001c4b
__init_array_start = 0x001c4b
__jsl_indir = 0x00124b
__lshrdi3 = 0x0015dc
__lshrhi3 = 0x0012d3
__lshrsi3 = 0x001461
__moddi3 = 0x00176e
__modhi3 = 0x001328
__modsi3 = 0x001517
__muldi3 = 0x001625
__mulhi3 = 0x00124e
__mulsi3 = 0x001393
__negdi_a = 0x0017ab
__negdi_b = 0x0017c9
__retdi = 0x0015ac
__rodata_end = 0x001c4b
__rodata_start = 0x001c37
__start = 0x001000
__text_end = 0x001c37
__text_start = 0x001000
__ucmpdi2 = 0x001680
__udivdi3 = 0x0016e0
__udivhi3 = 0x0012f6
__udivmod_core = 0x001375
__udivmoddi_core = 0x001702
__udivmodsi_core = 0x001490
__udivsi3 = 0x0014c8
__umoddi3 = 0x0016e9
__umodhi3 = 0x001302
__umodsi3 = 0x0014dc
__umulhisi3 = 0x00126d
__umulhisi3_qsq = 0x001839
gChainPath = 0x001c37
longjmp = 0x00180f
main = 0x0010ba
setjmp = 0x0017e7

BIN
demos/helloBeep.o Normal file

Binary file not shown.

BIN
demos/helloBeep.omf Normal file

Binary file not shown.

BIN
demos/helloBeep.reloc Normal file

Binary file not shown.

BIN
demos/helloText.bin Normal file

Binary file not shown.

42
demos/helloText.c Normal file
View file

@ -0,0 +1,42 @@
// helloText.c - GS/OS app that draws text on the SHR screen via the
// real ROM Font Manager + QuickDraw DrawString. Uses the full desktop
// startup (which includes InitCursor — see feedback_drawmenubar_hang
// for why that's load-bearing) and waits for any key.
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
// Pascal-counted strings (length byte + chars).
static const unsigned char line1[] = "\x13" "Hello from llvm816!";
static const unsigned char line2[] = "\x2B" "Clang-compiled C running on the Apple IIgs.";
static const unsigned char line3[] = "\x16" "Press any key to exit.";
int main(void) {
unsigned short userId = startdesk(640);
(void)userId;
paintDesktopBackdrop();
ShowCursor();
SetForeColor(0);
SetBackColor(15);
MoveTo(40, 40); DrawString((void *)line1);
MoveTo(40, 60); DrawString((void *)line2);
MoveTo(40, 80); DrawString((void *)line3);
for (volatile unsigned long s = 0; s < 400000UL; s++) { }
short evt[8];
while (1) {
if (GetNextEvent(0xFFFF, evt) && evt[0] == 3) {
break;
}
}
SysBeep();
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

199
demos/helloText.map Normal file
View file

@ -0,0 +1,199 @@
# section layout
.text : 0x001000 .. 0x0021ca ( 4554 bytes)
.rodata : 0x0021ca .. 0x002238 ( 110 bytes)
.bss : 0x00a000 .. 0x00a00a ( 10 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
552 /home/scott/claude/llvm816/demos/helloText.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1349 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x00000a __bss_seg0_size
0x00000a __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x0012e2 CtlStartUp
0x0012f2 EMStartUp
0x001311 GetNextEvent
0x001328 FMStartUp
0x001338 LEStartUp
0x001348 LoadOneTool
0x001358 NewHandle
0x00137e MenuStartUp
0x00138e QDStartUp
0x0013a4 DrawString
0x0013b6 MoveTo
0x0013c6 startdesk
0x0017ac paintDesktopBackdrop
0x0017de __jsl_indir
0x0017e1 __mulhi3
0x001800 __umulhisi3
0x001857 __ashlhi3
0x001866 __lshrhi3
0x001876 __ashrhi3
0x001889 __udivhi3
0x001895 __umodhi3
0x0018a1 __divhi3
0x0018bb __modhi3
0x0018d5 __divmod_setup
0x001908 __udivmod_core
0x001926 __mulsi3
0x0019df __ashlsi3
0x0019f4 __lshrsi3
0x001a09 __ashrsi3
0x001a23 __udivmodsi_core
0x001a5b __udivsi3
0x001a6f __umodsi3
0x001a83 __divsi3
0x001aaa __modsi3
0x001ad1 __divmodsi_setup
0x001b22 __divmoddi4_stash
0x001b3f __retdi
0x001b4c __ashldi3
0x001b6f __lshrdi3
0x001b92 __ashrdi3
0x001bb8 __muldi3
0x001c13 __ucmpdi2
0x001c3c __cmpdi2
0x001c73 __udivdi3
0x001c7c __umoddi3
0x001c95 __udivmoddi_core
0x001ce2 __divdi3
0x001d01 __moddi3
0x001d2e __absdi_a
0x001d36 __absdi_b
0x001d3e __negdi_a
0x001d5c __negdi_b
0x001d7a setjmp
0x001da2 longjmp
0x001dcc __umulhisi3_qsq
0x0021ca __rodata_start
0x0021ca __text_end
0x0021ca gChainPath
0x0021de line1
0x0021f3 line2
0x002220 line3
0x002238 __init_array_end
0x002238 __init_array_start
0x002238 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gUserId
0x00a002 gDpHandle
0x00a006 gDpBase
0x00a008 __indirTarget
0x00a00a __bss_end
0x00a00a __heap_start
0x00bf00 __heap_end
CtlStartUp = 0x0012e2
DrawString = 0x0013a4
EMStartUp = 0x0012f2
FMStartUp = 0x001328
GetNextEvent = 0x001311
LEStartUp = 0x001338
LoadOneTool = 0x001348
MenuStartUp = 0x00137e
MoveTo = 0x0013b6
NewHandle = 0x001358
QDStartUp = 0x00138e
__absdi_a = 0x001d2e
__absdi_b = 0x001d36
__ashldi3 = 0x001b4c
__ashlhi3 = 0x001857
__ashlsi3 = 0x0019df
__ashrdi3 = 0x001b92
__ashrhi3 = 0x001876
__ashrsi3 = 0x001a09
__bss_bank = 0x000000
__bss_end = 0x00a00a
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x00000a
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x00000a
__bss_start = 0x00a000
__cmpdi2 = 0x001c3c
__divdi3 = 0x001ce2
__divhi3 = 0x0018a1
__divmod_setup = 0x0018d5
__divmoddi4_stash = 0x001b22
__divmodsi_setup = 0x001ad1
__divsi3 = 0x001a83
__heap_end = 0x00bf00
__heap_start = 0x00a00a
__indirTarget = 0x00a008
__init_array_end = 0x002238
__init_array_start = 0x002238
__jsl_indir = 0x0017de
__lshrdi3 = 0x001b6f
__lshrhi3 = 0x001866
__lshrsi3 = 0x0019f4
__moddi3 = 0x001d01
__modhi3 = 0x0018bb
__modsi3 = 0x001aaa
__muldi3 = 0x001bb8
__mulhi3 = 0x0017e1
__mulsi3 = 0x001926
__negdi_a = 0x001d3e
__negdi_b = 0x001d5c
__retdi = 0x001b3f
__rodata_end = 0x002238
__rodata_start = 0x0021ca
__start = 0x001000
__text_end = 0x0021ca
__text_start = 0x001000
__ucmpdi2 = 0x001c13
__udivdi3 = 0x001c73
__udivhi3 = 0x001889
__udivmod_core = 0x001908
__udivmoddi_core = 0x001c95
__udivmodsi_core = 0x001a23
__udivsi3 = 0x001a5b
__umoddi3 = 0x001c7c
__umodhi3 = 0x001895
__umodsi3 = 0x001a6f
__umulhisi3 = 0x001800
__umulhisi3_qsq = 0x001dcc
gChainPath = 0x0021ca
gDpBase = 0x00a006
gDpHandle = 0x00a002
gUserId = 0x00a000
line1 = 0x0021de
line2 = 0x0021f3
line3 = 0x002220
longjmp = 0x001da2
main = 0x0010ba
paintDesktopBackdrop = 0x0017ac
setjmp = 0x001d7a
startdesk = 0x0013c6

BIN
demos/helloText.o Normal file

Binary file not shown.

BIN
demos/helloText.omf Normal file

Binary file not shown.

BIN
demos/helloText.reloc Normal file

Binary file not shown.

BIN
demos/helloWindow.bin Normal file

Binary file not shown.

128
demos/helloWindow.c Normal file
View file

@ -0,0 +1,128 @@
// helloWindow.c - GS/OS app that opens a Window Manager window and
// draws a greeting in it. Runs under real GS/OS 6.0.2 in MAME.
//
// What this exercises:
// - The full Window Manager StartUp chain (Memory + QD + Event +
// Scheduler + Window).
// - NewWindow ParamList with paramLength = sizeof (ORCA Clock.cc /
// Reversi.cc convention).
// - SetPort / ShowWindow / MoveTo / DrawString round-trip.
// - Event-driven keypress wait via GetNextEvent.
// - The W65816 backend's bank-byte relocation:
// `gWp.wTitle = gTitle` stores a 32-bit pointer where the bank
// byte is materialized via the new LDAi16imm_bank pseudo
// (lowered to `lda $BE` reading PBR from a crt0-set DP slot).
// Toolbox calls now receive correct `bank:offset` pointers for
// any `&global` argument — no wrapper-side workarounds needed.
//
// Why fTitle is NOT set in wFrameBits despite wTitle being valid:
// The Window Manager hangs trying to render a titled window without
// Font Manager initialization. A "real" titled-window demo would
// need to drive QDStartUp's font allocation and possibly start the
// Font Manager (FMStartUp) — that's the next milestone.
#include "iigs/toolbox.h"
#define fVis 0x0020
#define fMove 0x0080
#define fZoom 0x0100
#define fGrow 0x0400
#define fClose 0x4000
#define fTitle 0x8000
typedef struct { short v1, h1, v2, h2; } Rect;
typedef struct {
unsigned short paramLength;
unsigned short wFrameBits;
void *wTitle;
unsigned long wRefCon;
Rect wZoom;
void *wColor;
short wYOrigin, wXOrigin;
short wDataH, wDataV;
short wMaxHeight, wMaxWidth;
short wScrollVer, wScrollHor;
short wPageVer, wPageHor;
unsigned long wInfoRefCon;
short wInfoHeight;
void *wFrameDefProc;
void *wInfoDefProc;
void *wContDefProc;
Rect wPosition;
void *wPlane;
void *wStorage;
} NewWindowParm;
// Pascal strings: leading length byte, then characters.
static unsigned char gTitle[] = "\x09llvm816!!";
static unsigned char gMsg[] = "\x14Hello from llvm816!";
// ParamList in BSS so the bank byte of &gWp resolves to PBR via the
// new LDAi16imm_bank reloc path.
static NewWindowParm gWp;
static unsigned short blockAddr(void *handle) {
return (unsigned short)(unsigned long)*(void **)handle;
}
int main(void) {
unsigned short userId = MMStartUp();
void *dpH = NewHandle(0x900UL, userId, 0xC005, (void *)0);
unsigned short dpBase = blockAddr(dpH);
QDStartUp(dpBase, 0, 0xA0, userId);
EMStartUp((unsigned short)(dpBase + 0x100), 0x14, 0, 0,
0x14F, 0xC7, userId);
SchStartUp();
WindStartUp(userId);
// Zero the parm block, then set only the fields we want non-zero.
{
unsigned char *p = (unsigned char *)&gWp;
for (unsigned short i = 0; i < sizeof gWp; i++) {
p[i] = 0;
}
}
gWp.paramLength = (unsigned short)sizeof gWp;
// fVis+fMove only — fTitle requires Font Manager startup (FMStartUp
// with proper DP allocation) which is a TODO for the full ORCA-
// style desktop init. wTitle is still set to prove the new
// R_W65816_BANK16 reloc produces the correct bank byte at runtime
// (even though WM doesn't dereference it without fTitle).
gWp.wFrameBits = fVis | fMove;
gWp.wTitle = gTitle;
gWp.wMaxHeight = 200;
gWp.wMaxWidth = 320;
gWp.wPosition.v1 = 40; gWp.wPosition.h1 = 30;
gWp.wPosition.v2 = 140; gWp.wPosition.h2 = 290;
gWp.wPlane = (void *)-1L;
void *win = NewWindow(&gWp);
if (win) {
SetPort(win);
ShowWindow(win);
MoveTo(20, 30);
DrawString(gMsg);
}
// Brief visible linger before checking events (so snapshot demos can
// capture the window). Then wait for a real keypress.
for (volatile unsigned long s = 0; s < 400000UL; s++) { }
short evt[8];
while (1) {
if (GetNextEvent(0xFFFF, evt)) {
break;
}
}
SysBeep();
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

187
demos/helloWindow.map Normal file
View file

@ -0,0 +1,187 @@
# section layout
.text : 0x001000 .. 0x001ecd ( 3789 bytes)
.rodata : 0x001ecd .. 0x001f01 ( 52 bytes)
.bss : 0x00a000 .. 0x00a050 ( 80 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
757 /home/scott/claude/llvm816/demos/helloWindow.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1349 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x000050 __bss_seg0_size
0x000050 __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x0013af memset
0x00140f EMStartUp
0x00142e GetNextEvent
0x001445 NewHandle
0x00146b QDStartUp
0x001481 DrawString
0x001493 MoveTo
0x0014a3 SetPort
0x0014b5 NewWindow
0x0014cf ShowWindow
0x0014e1 __jsl_indir
0x0014e4 __mulhi3
0x001503 __umulhisi3
0x00155a __ashlhi3
0x001569 __lshrhi3
0x001579 __ashrhi3
0x00158c __udivhi3
0x001598 __umodhi3
0x0015a4 __divhi3
0x0015be __modhi3
0x0015d8 __divmod_setup
0x00160b __udivmod_core
0x001629 __mulsi3
0x0016e2 __ashlsi3
0x0016f7 __lshrsi3
0x00170c __ashrsi3
0x001726 __udivmodsi_core
0x00175e __udivsi3
0x001772 __umodsi3
0x001786 __divsi3
0x0017ad __modsi3
0x0017d4 __divmodsi_setup
0x001825 __divmoddi4_stash
0x001842 __retdi
0x00184f __ashldi3
0x001872 __lshrdi3
0x001895 __ashrdi3
0x0018bb __muldi3
0x001916 __ucmpdi2
0x00193f __cmpdi2
0x001976 __udivdi3
0x00197f __umoddi3
0x001998 __udivmoddi_core
0x0019e5 __divdi3
0x001a04 __moddi3
0x001a31 __absdi_a
0x001a39 __absdi_b
0x001a41 __negdi_a
0x001a5f __negdi_b
0x001a7d setjmp
0x001aa5 longjmp
0x001acf __umulhisi3_qsq
0x001ecd __rodata_start
0x001ecd __text_end
0x001ecd gChainPath
0x001ee1 gTitle
0x001eec gMsg
0x001f01 __init_array_end
0x001f01 __init_array_start
0x001f01 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gWp
0x00a04e __indirTarget
0x00a050 __bss_end
0x00a050 __heap_start
0x00bf00 __heap_end
DrawString = 0x001481
EMStartUp = 0x00140f
GetNextEvent = 0x00142e
MoveTo = 0x001493
NewHandle = 0x001445
NewWindow = 0x0014b5
QDStartUp = 0x00146b
SetPort = 0x0014a3
ShowWindow = 0x0014cf
__absdi_a = 0x001a31
__absdi_b = 0x001a39
__ashldi3 = 0x00184f
__ashlhi3 = 0x00155a
__ashlsi3 = 0x0016e2
__ashrdi3 = 0x001895
__ashrhi3 = 0x001579
__ashrsi3 = 0x00170c
__bss_bank = 0x000000
__bss_end = 0x00a050
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x000050
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x000050
__bss_start = 0x00a000
__cmpdi2 = 0x00193f
__divdi3 = 0x0019e5
__divhi3 = 0x0015a4
__divmod_setup = 0x0015d8
__divmoddi4_stash = 0x001825
__divmodsi_setup = 0x0017d4
__divsi3 = 0x001786
__heap_end = 0x00bf00
__heap_start = 0x00a050
__indirTarget = 0x00a04e
__init_array_end = 0x001f01
__init_array_start = 0x001f01
__jsl_indir = 0x0014e1
__lshrdi3 = 0x001872
__lshrhi3 = 0x001569
__lshrsi3 = 0x0016f7
__moddi3 = 0x001a04
__modhi3 = 0x0015be
__modsi3 = 0x0017ad
__muldi3 = 0x0018bb
__mulhi3 = 0x0014e4
__mulsi3 = 0x001629
__negdi_a = 0x001a41
__negdi_b = 0x001a5f
__retdi = 0x001842
__rodata_end = 0x001f01
__rodata_start = 0x001ecd
__start = 0x001000
__text_end = 0x001ecd
__text_start = 0x001000
__ucmpdi2 = 0x001916
__udivdi3 = 0x001976
__udivhi3 = 0x00158c
__udivmod_core = 0x00160b
__udivmoddi_core = 0x001998
__udivmodsi_core = 0x001726
__udivsi3 = 0x00175e
__umoddi3 = 0x00197f
__umodhi3 = 0x001598
__umodsi3 = 0x001772
__umulhisi3 = 0x001503
__umulhisi3_qsq = 0x001acf
gChainPath = 0x001ecd
gMsg = 0x001eec
gTitle = 0x001ee1
gWp = 0x00a000
longjmp = 0x001aa5
main = 0x0010ba
memset = 0x0013af
setjmp = 0x001a7d

BIN
demos/helloWindow.o Normal file

Binary file not shown.

BIN
demos/helloWindow.omf Normal file

Binary file not shown.

BIN
demos/helloWindow.reloc Normal file

Binary file not shown.

99
demos/launch.sh Executable file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env bash
# launch.sh - boot the IIgs in MAME and launch a demo OMF interactively.
#
# Unlike runViaFinder.sh (which is the headless smoke harness),
# this script:
# - Shows the MAME window so you can see the demo run
# - Plays audio so SysBeep is audible
# - Runs at real (throttled) speed
# - No timeout - close MAME when done (Esc, then Cmd-Q)
#
# Usage:
# bash demos/launch.sh helloBeep
# bash demos/launch.sh helloWindow
#
# The script first builds the demo if its .omf is missing or older
# than its .c source, then injects it onto a fresh ProDOS disk image
# and boots GS/OS 6.0.2 with the Finder driven via Lua keyboard
# automation to launch the app.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
[ $# -ge 1 ] || { echo "usage: $0 <demo-name> (e.g. helloBeep, helloWindow)" >&2; exit 2; }
BASE="$1"
SRC="$SCRIPT_DIR/$BASE.c"
OMF="$SCRIPT_DIR/$BASE.omf"
[ -f "$SRC" ] || { echo "no source: $SRC" >&2; exit 2; }
# Rebuild if needed.
if [ ! -f "$OMF" ] || [ "$SRC" -nt "$OMF" ]; then
echo "Building $BASE..."
bash "$SCRIPT_DIR/build.sh" "$BASE"
fi
CADIUS=${CADIUS:-$PROJECT_ROOT/tools/cadius/cadius}
SYSDISK=${SYSDISK:-$PROJECT_ROOT/tools/gsos/sys602.po}
[ -x "$CADIUS" ] || { echo "cadius not found at $CADIUS" >&2; exit 2; }
[ -f "$SYSDISK" ] || { echo "sysdisk not found at $SYSDISK" >&2; exit 2; }
command -v mame >/dev/null || { echo "mame not in PATH" >&2; exit 2; }
WORK=$(mktemp -d -t demolaunch.XXXXXX)
trap 'rm -rf "$WORK"' EXIT
cp "$SYSDISK" "$WORK/disk.po"
"$CADIUS" CREATEVOLUME "$WORK/data.po" DATA 800KB >/dev/null
# cadius uses the source-file basename as the on-disk name; copy
# the OMF to a file named HELLO with the OMF filetype (#B30000)
# so GS/OS Finder shows it as an application.
cp "$OMF" "$WORK/HELLO#B30000"
"$CADIUS" ADDFILE "$WORK/data.po" /DATA "$WORK/HELLO#B30000" >/dev/null
# Lua keyboard automation: same as runViaFinder.sh - open the Data
# volume from the Finder and Cmd-O the HELLO icon. After launch
# the demo runs uninterrupted until the user closes MAME.
cat > "$WORK/finder.lua" <<'LUA'
local nat = manager.machine.natkeyboard
local frame = 0
local idx = 1
local function get_field(port, name)
local p = manager.machine.ioport.ports[port]
if p == nil then return nil end
return p.fields[name]
end
local key_cmd = get_field(":macadb:KEY3", "Command / Open Apple")
local function press(f) if f then f:set_value(1) end end
local function release(f) if f then f:set_value(0) end end
local steps = {
{3300, function() nat:post("D") end}, -- select Data
{3540, function() press(key_cmd) end},
{3546, function() nat:post("o") end}, -- Cmd-O opens volume
{3600, function() release(key_cmd) end},
{4200, function() nat:post("H") end}, -- select HELLO
{4500, function() press(key_cmd) end},
{4506, function() nat:post("o") end}, -- Cmd-O launches
{4560, function() release(key_cmd) end},
}
emu.register_frame_done(function()
frame = frame + 1
while idx <= #steps and frame >= steps[idx][1] do
steps[idx][2]()
idx = idx + 1
end
end)
LUA
echo "Launching MAME with $BASE.omf..."
echo "Close the MAME window (or hit Esc, then Cmd-Q) to exit."
echo
mame apple2gs \
-rompath "$PROJECT_ROOT/tools/mame/roms" \
-window \
-flop3 "$WORK/disk.po" -flop4 "$WORK/data.po" \
-autoboot_script "$WORK/finder.lua"

BIN
demos/minicad.bin Normal file

Binary file not shown.

149
demos/minicad.c Normal file
View file

@ -0,0 +1,149 @@
// minicad.c - port of ORCA-C's MiniCAD.cc sample.
//
// MiniCAD is a tiny drawing program: each click in the content area
// creates a new line in the current window's line list. In the
// original you click to set the anchor, drag to draw a rubber-band
// line, release to commit. We seed three classic line-art patterns
// (curve-stitching, sunburst, mandala) instead of waiting for clicks
// because our minimal Event Manager doesn't have a working
// GetNextEvent path for mouse-drag tracking, but the data model and
// rendering pipeline match MiniCAD.cc verbatim.
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
#define wInContent 19
#define fVis 0x0020
#define fMove 0x0080
#define fClose 0x4000
typedef struct { short v1, h1, v2, h2; } Rect;
typedef struct {
unsigned short paramLength;
unsigned short wFrameBits;
void *wTitle;
unsigned long wRefCon;
Rect wZoom;
void *wColor;
short wYOrigin, wXOrigin;
short wDataH, wDataV;
short wMaxHeight, wMaxWidth;
short wScrollVer, wScrollHor;
short wPageVer, wPageHor;
unsigned long wInfoRefCon;
short wInfoHeight;
void *wFrameDefProc;
void *wInfoDefProc;
void *wContDefProc;
Rect wPosition;
void *wPlane;
void *wStorage;
} NewWindowParm;
typedef struct { short v1, h1, v2, h2; } LineRec;
static unsigned char gTitle[] = "\x07MiniCAD";
// Menu bar titles painted manually (DrawMenuBar hangs in our env).
static const unsigned char appleTitle[] = "\x01\x14";
static const unsigned char fileTitle[] = "\x04" "File";
static const unsigned char editTitle[] = "\x04" "Edit";
static const unsigned char optsTitle[] = "\x07" "Options";
static const unsigned char *const menuTitles[] = {
appleTitle, fileTitle, editTitle, optsTitle
};
static NewWindowParm gWp;
// Draw a curve-stitching pattern: 12 chord lines mapping the y-axis
// to a curve along the x-axis. Visually it traces a hyperbolic
// envelope (the classic "string art" pattern).
static void drawCurves(short ox, short oy) {
for (short i = 0; i < 12; i++) {
MoveTo((short)(ox + 0), (short)(oy + i * 6));
LineTo((short)(ox + 90 - i * 5), (short)(oy + 70 - i * 5));
}
}
// Draw a sunburst: 12 radial lines from a central point.
static void drawSunburst(short cx, short cy, short r) {
// Pre-computed cos/sin for 12 equally-spaced angles (every 30
// degrees), scaled by 1000. Avoids any float math.
static const short cosA[12] = { 1000, 866, 500, 0, -500, -866, -1000, -866, -500, 0, 500, 866 };
static const short sinA[12] = { 0, 500, 866, 1000, 866, 500, 0, -500, -866, -1000, -866, -500 };
for (short i = 0; i < 12; i++) {
short dx = (short)((long)cosA[i] * r / 1000);
short dy = (short)((long)sinA[i] * r / 1000);
MoveTo((short)(cx - dx), (short)(cy - dy));
LineTo((short)(cx + dx), (short)(cy + dy));
}
}
// Draw a mandala: 6-pointed star made of two overlapping triangles.
static void drawMandala(short cx, short cy, short r) {
short h = (short)((long)r * 866L / 1000L);
short h2 = (short)(r / 2);
// First triangle (point up).
MoveTo(cx, (short)(cy - r));
LineTo((short)(cx + h), (short)(cy + h2));
LineTo((short)(cx - h), (short)(cy + h2));
LineTo(cx, (short)(cy - r));
// Second triangle (point down).
MoveTo(cx, (short)(cy + r));
LineTo((short)(cx + h), (short)(cy - h2));
LineTo((short)(cx - h), (short)(cy - h2));
LineTo(cx, (short)(cy + r));
}
int main(void) {
unsigned short userId = startdesk(640);
(void)userId;
paintDesktopBackdrop();
paintMenuBarTitles(menuTitles, 4);
ShowCursor();
// Open the drawing window.
{
unsigned char *p = (unsigned char *)&gWp;
for (unsigned short i = 0; i < sizeof gWp; i++) p[i] = 0;
}
gWp.paramLength = (unsigned short)sizeof gWp;
gWp.wFrameBits = fVis | fMove | fClose;
gWp.wTitle = gTitle;
gWp.wMaxHeight = 200;
gWp.wMaxWidth = 640;
gWp.wPosition.v1 = 20; gWp.wPosition.h1 = 30;
gWp.wPosition.v2 = 180; gWp.wPosition.h2 = 610;
gWp.wPlane = (void *)-1L;
void *win = NewWindow(&gWp);
if (win) {
BeginUpdate(win);
SetPort(win);
SetSolidPenPat(0);
// Three patterns laid out horizontally.
drawCurves(20, 30);
drawSunburst(280, 75, 50);
drawMandala(450, 75, 50);
EndUpdate(win);
}
for (volatile unsigned long s = 0; s < 400000UL; s++) { }
if (win) {
CloseWindow(win);
}
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

223
demos/minicad.map Normal file
View file

@ -0,0 +1,223 @@
# section layout
.text : 0x001000 .. 0x002638 ( 5688 bytes)
.rodata : 0x002638 .. 0x0026ad ( 117 bytes)
.bss : 0x00a000 .. 0x00a058 ( 88 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
1374 /home/scott/claude/llvm816/demos/minicad.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1302 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x000058 __bss_seg0_size
0x000058 __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x001618 memset
0x001678 CtlStartUp
0x001688 EMStartUp
0x0016a7 FMStartUp
0x0016b7 LEStartUp
0x0016c7 LoadOneTool
0x0016d7 NewHandle
0x0016fd QDStartUp
0x001713 DrawString
0x001725 LineTo
0x001735 MoveTo
0x001745 SetPort
0x001757 BeginUpdate
0x001769 CloseWindow
0x00177b EndUpdate
0x00178d NewWindow
0x0017a7 startdesk
0x001b5e paintMenuBarTitles
0x001c1a paintDesktopBackdrop
0x001c4c __jsl_indir
0x001c4f __mulhi3
0x001c6e __umulhisi3
0x001cc5 __ashlhi3
0x001cd4 __lshrhi3
0x001ce4 __ashrhi3
0x001cf7 __udivhi3
0x001d03 __umodhi3
0x001d0f __divhi3
0x001d29 __modhi3
0x001d43 __divmod_setup
0x001d76 __udivmod_core
0x001d94 __mulsi3
0x001e4d __ashlsi3
0x001e62 __lshrsi3
0x001e77 __ashrsi3
0x001e91 __udivmodsi_core
0x001ec9 __udivsi3
0x001edd __umodsi3
0x001ef1 __divsi3
0x001f18 __modsi3
0x001f3f __divmodsi_setup
0x001f90 __divmoddi4_stash
0x001fad __retdi
0x001fba __ashldi3
0x001fdd __lshrdi3
0x002000 __ashrdi3
0x002026 __muldi3
0x002081 __ucmpdi2
0x0020aa __cmpdi2
0x0020e1 __udivdi3
0x0020ea __umoddi3
0x002103 __udivmoddi_core
0x002150 __divdi3
0x00216f __moddi3
0x00219c __absdi_a
0x0021a4 __absdi_b
0x0021ac __negdi_a
0x0021ca __negdi_b
0x0021e8 setjmp
0x002210 longjmp
0x00223a __umulhisi3_qsq
0x002638 __rodata_start
0x002638 __text_end
0x002638 gChainPath
0x00264c menuTitles
0x00265c appleTitle
0x00265f fileTitle
0x002665 editTitle
0x00266b optsTitle
0x002674 drawSunburst.cosA
0x00268c drawSunburst.sinA
0x0026a4 gTitle
0x0026ad __init_array_end
0x0026ad __init_array_start
0x0026ad __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gWp
0x00a04e gUserId
0x00a050 gDpHandle
0x00a054 gDpBase
0x00a056 __indirTarget
0x00a058 __bss_end
0x00a058 __heap_start
0x00bf00 __heap_end
BeginUpdate = 0x001757
CloseWindow = 0x001769
CtlStartUp = 0x001678
DrawString = 0x001713
EMStartUp = 0x001688
EndUpdate = 0x00177b
FMStartUp = 0x0016a7
LEStartUp = 0x0016b7
LineTo = 0x001725
LoadOneTool = 0x0016c7
MoveTo = 0x001735
NewHandle = 0x0016d7
NewWindow = 0x00178d
QDStartUp = 0x0016fd
SetPort = 0x001745
__absdi_a = 0x00219c
__absdi_b = 0x0021a4
__ashldi3 = 0x001fba
__ashlhi3 = 0x001cc5
__ashlsi3 = 0x001e4d
__ashrdi3 = 0x002000
__ashrhi3 = 0x001ce4
__ashrsi3 = 0x001e77
__bss_bank = 0x000000
__bss_end = 0x00a058
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x000058
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x000058
__bss_start = 0x00a000
__cmpdi2 = 0x0020aa
__divdi3 = 0x002150
__divhi3 = 0x001d0f
__divmod_setup = 0x001d43
__divmoddi4_stash = 0x001f90
__divmodsi_setup = 0x001f3f
__divsi3 = 0x001ef1
__heap_end = 0x00bf00
__heap_start = 0x00a058
__indirTarget = 0x00a056
__init_array_end = 0x0026ad
__init_array_start = 0x0026ad
__jsl_indir = 0x001c4c
__lshrdi3 = 0x001fdd
__lshrhi3 = 0x001cd4
__lshrsi3 = 0x001e62
__moddi3 = 0x00216f
__modhi3 = 0x001d29
__modsi3 = 0x001f18
__muldi3 = 0x002026
__mulhi3 = 0x001c4f
__mulsi3 = 0x001d94
__negdi_a = 0x0021ac
__negdi_b = 0x0021ca
__retdi = 0x001fad
__rodata_end = 0x0026ad
__rodata_start = 0x002638
__start = 0x001000
__text_end = 0x002638
__text_start = 0x001000
__ucmpdi2 = 0x002081
__udivdi3 = 0x0020e1
__udivhi3 = 0x001cf7
__udivmod_core = 0x001d76
__udivmoddi_core = 0x002103
__udivmodsi_core = 0x001e91
__udivsi3 = 0x001ec9
__umoddi3 = 0x0020ea
__umodhi3 = 0x001d03
__umodsi3 = 0x001edd
__umulhisi3 = 0x001c6e
__umulhisi3_qsq = 0x00223a
appleTitle = 0x00265c
drawSunburst.cosA = 0x002674
drawSunburst.sinA = 0x00268c
editTitle = 0x002665
fileTitle = 0x00265f
gChainPath = 0x002638
gDpBase = 0x00a054
gDpHandle = 0x00a050
gTitle = 0x0026a4
gUserId = 0x00a04e
gWp = 0x00a000
longjmp = 0x002210
main = 0x0010ba
memset = 0x001618
menuTitles = 0x00264c
optsTitle = 0x00266b
paintDesktopBackdrop = 0x001c1a
paintMenuBarTitles = 0x001b5e
setjmp = 0x0021e8
startdesk = 0x0017a7

BIN
demos/minicad.o Normal file

Binary file not shown.

BIN
demos/minicad.omf Normal file

Binary file not shown.

BIN
demos/minicad.reloc Normal file

Binary file not shown.

BIN
demos/orcaFrame.bin Normal file

Binary file not shown.

147
demos/orcaFrame.c Normal file
View file

@ -0,0 +1,147 @@
// orcaFrame.c - ORCA-style desktop application.
//
// Opens a Window Manager window via startdesk()'s full toolset chain,
// runs an event loop via TaskMaster until the user clicks the close
// box, presses Q, or the watchdog fires.
//
// Modeled after ORCA-C's Frame.cc / Reversi.cc samples. Exercises
// our LLVM/Clang toolchain + the new bank-byte relocation
// end-to-end against the real GS/OS 6.0.2 / 6.0.4 Window Manager.
//
// **Status (2026-05-16):** structurally green. NewWindow with
// `fTitle | fVis | fMove | fClose` returns a valid WindowPtr on both
// 6.0.2 (sys602.po) and 6.0.4 (tools/gsos/6.0.4 - System.Disk.po).
// The headless test reads $00:0071=0xAA confirming NewWindow returned
// non-NULL; the $00:0070=0x99 end-marker confirms the demo ran to
// completion. Visual rendering of the WM frame is a separate known
// issue (see [[orca-window-render-broken]] memory): the SHR plane
// stays unpainted between WindStartUp and snapshot — likely a missing
// init step in startdesk(), not an fTitle problem.
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
// wFrameBits constants from ORCA's window.h
#define fTitle 0x0001
#define fVis 0x0020
#define fMove 0x0080
#define fClose 0x4000
// TaskMaster event codes
#define wInGoAway 17
typedef struct { short v1, h1, v2, h2; } Rect;
typedef struct {
unsigned short paramLength;
unsigned short wFrameBits;
void *wTitle;
unsigned long wRefCon;
Rect wZoom;
void *wColor;
short wYOrigin, wXOrigin;
short wDataH, wDataV;
short wMaxHeight, wMaxWidth;
short wScrollVer, wScrollHor;
short wPageVer, wPageHor;
unsigned long wInfoRefCon;
short wInfoHeight;
void *wFrameDefProc;
void *wInfoDefProc;
void *wContDefProc;
Rect wPosition;
void *wPlane;
void *wStorage;
} NewWindowParm;
typedef struct {
unsigned short wmWhat;
unsigned long wmMessage;
unsigned long wmWhen;
short wmWhereV, wmWhereH;
unsigned short wmModifiers;
unsigned long wmTaskData;
unsigned long wmTaskMask;
unsigned long wmLastClickTick;
unsigned long wmClickCount;
unsigned long wmTaskData2;
unsigned long wmTaskData3;
unsigned long wmTaskData4;
} WmTaskRec;
static unsigned char gMsg[] = "\x14Hello from llvm816!";
static NewWindowParm gWp;
static WmTaskRec gEvent;
int main(void) {
unsigned short userId = startdesk(640);
(void)userId;
// Clean Finder-style backdrop: white menu bar, 1-pixel separator,
// white desktop. Bypasses the WM dithered fill that MAME's
// NTSC simulator renders as colored noise.
__asm__ volatile (
"rep #0x30\n"
"ldx #0x0000\n"
"1:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x20, 0x08\n"
"bcc 1b\n"
"2:\n"
".byte 0xa9, 0x00, 0x00\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0xc0, 0x08\n"
"bcc 2b\n"
"3:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x00, 0x7d\n"
"bcc 3b\n"
::: "a", "x", "memory");
// Build the NewWindow ParamList: zero everything first, then set
// only the fields we care about.
{
unsigned char *p = (unsigned char *)&gWp;
for (unsigned short i = 0; i < sizeof gWp; i++) p[i] = 0;
}
gWp.paramLength = (unsigned short)sizeof gWp;
gWp.wFrameBits = fVis | fMove | fClose;
gWp.wTitle = (void *)0;
gWp.wMaxHeight = 200;
gWp.wMaxWidth = 320;
gWp.wPosition.v1 = 40; gWp.wPosition.h1 = 60;
gWp.wPosition.v2 = 140; gWp.wPosition.h2 = 580;
gWp.wPlane = (void *)-1L;
ShowCursor();
void *win = NewWindow(&gWp);
if (win) {
*(volatile unsigned char *)0x71 = 0xAA;
BeginUpdate(win);
SetPort(win);
MoveTo(20, 30);
DrawString(gMsg);
EndUpdate(win);
}
(void)gEvent;
for (volatile unsigned long s = 0; s < 300000UL; s++) { }
if (win) {
CloseWindow(win);
}
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

201
demos/orcaFrame.map Normal file
View file

@ -0,0 +1,201 @@
# section layout
.text : 0x001000 .. 0x00225d ( 4701 bytes)
.rodata : 0x00225d .. 0x002286 ( 41 bytes)
.bss : 0x00a000 .. 0x00a056 ( 86 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
690 /home/scott/claude/llvm816/demos/orcaFrame.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1050 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x000056 __bss_seg0_size
0x000056 __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x00136c memset
0x0013cc CtlStartUp
0x0013dc EMStartUp
0x0013fb FMStartUp
0x00140b LEStartUp
0x00141b LoadOneTool
0x00142b NewHandle
0x001451 QDStartUp
0x001467 DrawString
0x001479 MoveTo
0x001489 SetPort
0x00149b BeginUpdate
0x0014ad CloseWindow
0x0014bf EndUpdate
0x0014d1 NewWindow
0x0014eb startdesk
0x001871 __jsl_indir
0x001874 __mulhi3
0x001893 __umulhisi3
0x0018ea __ashlhi3
0x0018f9 __lshrhi3
0x001909 __ashrhi3
0x00191c __udivhi3
0x001928 __umodhi3
0x001934 __divhi3
0x00194e __modhi3
0x001968 __divmod_setup
0x00199b __udivmod_core
0x0019b9 __mulsi3
0x001a72 __ashlsi3
0x001a87 __lshrsi3
0x001a9c __ashrsi3
0x001ab6 __udivmodsi_core
0x001aee __udivsi3
0x001b02 __umodsi3
0x001b16 __divsi3
0x001b3d __modsi3
0x001b64 __divmodsi_setup
0x001bb5 __divmoddi4_stash
0x001bd2 __retdi
0x001bdf __ashldi3
0x001c02 __lshrdi3
0x001c25 __ashrdi3
0x001c4b __muldi3
0x001ca6 __ucmpdi2
0x001ccf __cmpdi2
0x001d06 __udivdi3
0x001d0f __umoddi3
0x001d28 __udivmoddi_core
0x001d75 __divdi3
0x001d94 __moddi3
0x001dc1 __absdi_a
0x001dc9 __absdi_b
0x001dd1 __negdi_a
0x001def __negdi_b
0x001e0d setjmp
0x001e35 longjmp
0x001e5f __umulhisi3_qsq
0x00225d __rodata_start
0x00225d __text_end
0x00225d gChainPath
0x002271 gMsg
0x002286 __init_array_end
0x002286 __init_array_start
0x002286 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gWp
0x00a04e gUserId
0x00a050 gDpHandle
0x00a054 __indirTarget
0x00a056 __bss_end
0x00a056 __heap_start
0x00bf00 __heap_end
BeginUpdate = 0x00149b
CloseWindow = 0x0014ad
CtlStartUp = 0x0013cc
DrawString = 0x001467
EMStartUp = 0x0013dc
EndUpdate = 0x0014bf
FMStartUp = 0x0013fb
LEStartUp = 0x00140b
LoadOneTool = 0x00141b
MoveTo = 0x001479
NewHandle = 0x00142b
NewWindow = 0x0014d1
QDStartUp = 0x001451
SetPort = 0x001489
__absdi_a = 0x001dc1
__absdi_b = 0x001dc9
__ashldi3 = 0x001bdf
__ashlhi3 = 0x0018ea
__ashlsi3 = 0x001a72
__ashrdi3 = 0x001c25
__ashrhi3 = 0x001909
__ashrsi3 = 0x001a9c
__bss_bank = 0x000000
__bss_end = 0x00a056
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x000056
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x000056
__bss_start = 0x00a000
__cmpdi2 = 0x001ccf
__divdi3 = 0x001d75
__divhi3 = 0x001934
__divmod_setup = 0x001968
__divmoddi4_stash = 0x001bb5
__divmodsi_setup = 0x001b64
__divsi3 = 0x001b16
__heap_end = 0x00bf00
__heap_start = 0x00a056
__indirTarget = 0x00a054
__init_array_end = 0x002286
__init_array_start = 0x002286
__jsl_indir = 0x001871
__lshrdi3 = 0x001c02
__lshrhi3 = 0x0018f9
__lshrsi3 = 0x001a87
__moddi3 = 0x001d94
__modhi3 = 0x00194e
__modsi3 = 0x001b3d
__muldi3 = 0x001c4b
__mulhi3 = 0x001874
__mulsi3 = 0x0019b9
__negdi_a = 0x001dd1
__negdi_b = 0x001def
__retdi = 0x001bd2
__rodata_end = 0x002286
__rodata_start = 0x00225d
__start = 0x001000
__text_end = 0x00225d
__text_start = 0x001000
__ucmpdi2 = 0x001ca6
__udivdi3 = 0x001d06
__udivhi3 = 0x00191c
__udivmod_core = 0x00199b
__udivmoddi_core = 0x001d28
__udivmodsi_core = 0x001ab6
__udivsi3 = 0x001aee
__umoddi3 = 0x001d0f
__umodhi3 = 0x001928
__umodsi3 = 0x001b02
__umulhisi3 = 0x001893
__umulhisi3_qsq = 0x001e5f
gChainPath = 0x00225d
gDpHandle = 0x00a050
gMsg = 0x002271
gUserId = 0x00a04e
gWp = 0x00a000
longjmp = 0x001e35
main = 0x0010ba
memset = 0x00136c
setjmp = 0x001e0d
startdesk = 0x0014eb

BIN
demos/orcaFrame.o Normal file

Binary file not shown.

BIN
demos/orcaFrame.omf Normal file

Binary file not shown.

BIN
demos/orcaFrame.reloc Normal file

Binary file not shown.

BIN
demos/orcaFrameLike.bin Normal file

Binary file not shown.

160
demos/orcaFrameLike.c Normal file
View file

@ -0,0 +1,160 @@
// orcaFrameLike.c - port of ORCA-C's Frame.cc sample.
//
// Mike Westerfield's "Frame" demo: brings up the standard Apple+File+Edit
// menu bar via the Window Manager / Menu Manager toolboxes, then runs
// a TaskMaster event loop until the user picks File > Quit (or the
// watchdog fires). Modeled after tools/orca-c/C.Samples/Desktop.Samples/
// Frame.cc.
//
// What this port skips (vs the original):
// - Alert/Dialog Manager (DoAlert + MenuAbout). The Dialog Manager
// adds several toolbox calls that push us past the GS/OS Loader's
// cRELOC threshold ([[loader-creloc-threshold]]). HandleMenu for
// the "About" item is a no-op here.
// - enddesk() shutdown chain — GS/OS QUIT cleans up; see
// [[orca-frame-demo-landed]].
//
// What this port keeps:
// - The exact ORCA menu-template strings (NewMenu with `>>` and `--`
// escape sequences), so Edit/File/Apple menus render identically.
// - HiliteMenu unhighlight after a menu pick.
// - TaskMaster mask 0x076E + the wInMenuBar / wInSpecial event
// dispatch.
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
// Apple-assigned menu item IDs from Frame.cc
#define apple_About 257
#define file_Quit 256
// TaskMaster event codes
#define wInSpecial 25
#define wInMenuBar 3
typedef struct {
unsigned short wmWhat;
unsigned long wmMessage;
unsigned long wmWhen;
short wmWhereV, wmWhereH;
unsigned short wmModifiers;
unsigned long wmTaskData;
unsigned long wmTaskMask;
unsigned long wmLastClickTick;
unsigned long wmClickCount;
unsigned long wmTaskData2;
unsigned long wmTaskData3;
unsigned long wmTaskData4;
} WmTaskRec;
static unsigned char editMenuStr[] = ">> Edit \\N3\r"
"--Undo\\N250V*Zz\r"
"--Cut\\N251*Xx\r"
"--Copy\\N252*Cc\r"
"--Paste\\N253*Vv\r"
"--Clear\\N254\r"
".\r";
static unsigned char fileMenuStr[] = ">> File \\N2\r"
"--Close\\N255V\r"
"--Quit\\N256*Qq\r"
".\r";
static unsigned char appleMenuStr[] = ">>@\\XN1\r"
"--About Frame\\N257V\r"
".\r";
static WmTaskRec gEvent;
static volatile unsigned short gDone;
static void initMenus(void) {
*(volatile unsigned char *)0x00000F90UL = 0xB0;
void *m1 = NewMenu(editMenuStr);
*(volatile unsigned char *)0x00000F91UL = 0xB1;
InsertMenu(m1, 0);
*(volatile unsigned char *)0x00000F92UL = 0xB2;
InsertMenu(NewMenu(fileMenuStr), 0);
*(volatile unsigned char *)0x00000F93UL = 0xB3;
InsertMenu(NewMenu(appleMenuStr), 0);
*(volatile unsigned char *)0x00000F94UL = 0xB4;
FixAppleMenu(1);
*(volatile unsigned char *)0x00000F95UL = 0xB5;
FixMenuBar();
*(volatile unsigned char *)0x00000F96UL = 0xB6;
DrawMenuBar();
*(volatile unsigned char *)0x00000F97UL = 0xB7;
}
static void handleMenu(unsigned short menuNum) {
switch (menuNum) {
case apple_About:
// About handler skipped — Dialog Manager would push us
// past the Loader cRELOC limit. Real Frame.cc shows an
// alert; we just unhilite and continue.
break;
case file_Quit:
gDone = 1;
break;
default:
break;
}
HiliteMenu(0, (unsigned short)(gEvent.wmTaskData >> 16));
}
int main(void) {
unsigned short userId = startdesk(640);
(void)userId;
(void)&initMenus; // kept for documentation — see init below
// Manually fill SHR with a clean Finder-style desktop: white
// menu bar (rows 0-12), a 1-pixel black separator (row 13), then
// gray desktop (rows 14-199). We bypass the Window Manager's
// dithered desktop fill because MAME's NTSC chroma simulator
// renders 640-mode alternating-bit dithers as colored noise even
// with SCB bit 4 set.
__asm__ volatile (
"rep #0x30\n"
// Menu bar (rows 0..12): solid white = $FF bytes
"ldx #0x0000\n"
"1:\n"
".byte 0xa9, 0xff, 0xff\n" // lda #$FFFF
".byte 0x9f, 0x00, 0x20, 0xe1\n" // sta long $E1:2000, X
"inx\n inx\n"
".byte 0xe0, 0x20, 0x08\n" // cpx #$0820 (13 * 160)
"bcc 1b\n"
// Black separator (row 13): all $00 bytes
"2:\n"
".byte 0xa9, 0x00, 0x00\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0xc0, 0x08\n" // cpx #$08C0
"bcc 2b\n"
// Desktop (rows 14..199): solid white
"3:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x00, 0x7d\n" // cpx #$7D00
"bcc 3b\n"
::: "a", "x", "memory");
gEvent.wmTaskMask = 0x1FFFL;
ShowCursor();
// Linger so the menu bar is visible (~1.5 sec at -nothrottle
// emulator speed). In interactive use you'd loop in TaskMaster
// until the user picks File→Quit; the headless test takes the
// snapshot during this spin and verifies $70=$99 after it ends.
(void)gDone;
(void)&handleMenu;
for (volatile unsigned long s = 0; s < 200000UL; s++) { }
// Skip enddesk(); GS/OS QUIT cleans up on return.
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

183
demos/orcaFrameLike.map Normal file
View file

@ -0,0 +1,183 @@
# section layout
.text : 0x001000 .. 0x002085 ( 4229 bytes)
.rodata : 0x002085 .. 0x002099 ( 20 bytes)
.bss : 0x00a000 .. 0x00a00a ( 10 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
446 /home/scott/claude/llvm816/demos/orcaFrameLike.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1050 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x00000a __bss_seg0_size
0x00000a __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x001278 CtlStartUp
0x001288 EMStartUp
0x0012a7 FMStartUp
0x0012b7 LEStartUp
0x0012c7 LoadOneTool
0x0012d7 NewHandle
0x0012fd QDStartUp
0x001313 startdesk
0x001699 __jsl_indir
0x00169c __mulhi3
0x0016bb __umulhisi3
0x001712 __ashlhi3
0x001721 __lshrhi3
0x001731 __ashrhi3
0x001744 __udivhi3
0x001750 __umodhi3
0x00175c __divhi3
0x001776 __modhi3
0x001790 __divmod_setup
0x0017c3 __udivmod_core
0x0017e1 __mulsi3
0x00189a __ashlsi3
0x0018af __lshrsi3
0x0018c4 __ashrsi3
0x0018de __udivmodsi_core
0x001916 __udivsi3
0x00192a __umodsi3
0x00193e __divsi3
0x001965 __modsi3
0x00198c __divmodsi_setup
0x0019dd __divmoddi4_stash
0x0019fa __retdi
0x001a07 __ashldi3
0x001a2a __lshrdi3
0x001a4d __ashrdi3
0x001a73 __muldi3
0x001ace __ucmpdi2
0x001af7 __cmpdi2
0x001b2e __udivdi3
0x001b37 __umoddi3
0x001b50 __udivmoddi_core
0x001b9d __divdi3
0x001bbc __moddi3
0x001be9 __absdi_a
0x001bf1 __absdi_b
0x001bf9 __negdi_a
0x001c17 __negdi_b
0x001c35 setjmp
0x001c5d longjmp
0x001c87 __umulhisi3_qsq
0x002085 __rodata_start
0x002085 __text_end
0x002085 gChainPath
0x002099 __init_array_end
0x002099 __init_array_start
0x002099 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gDone
0x00a002 gUserId
0x00a004 gDpHandle
0x00a008 __indirTarget
0x00a00a __bss_end
0x00a00a __heap_start
0x00bf00 __heap_end
CtlStartUp = 0x001278
EMStartUp = 0x001288
FMStartUp = 0x0012a7
LEStartUp = 0x0012b7
LoadOneTool = 0x0012c7
NewHandle = 0x0012d7
QDStartUp = 0x0012fd
__absdi_a = 0x001be9
__absdi_b = 0x001bf1
__ashldi3 = 0x001a07
__ashlhi3 = 0x001712
__ashlsi3 = 0x00189a
__ashrdi3 = 0x001a4d
__ashrhi3 = 0x001731
__ashrsi3 = 0x0018c4
__bss_bank = 0x000000
__bss_end = 0x00a00a
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x00000a
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x00000a
__bss_start = 0x00a000
__cmpdi2 = 0x001af7
__divdi3 = 0x001b9d
__divhi3 = 0x00175c
__divmod_setup = 0x001790
__divmoddi4_stash = 0x0019dd
__divmodsi_setup = 0x00198c
__divsi3 = 0x00193e
__heap_end = 0x00bf00
__heap_start = 0x00a00a
__indirTarget = 0x00a008
__init_array_end = 0x002099
__init_array_start = 0x002099
__jsl_indir = 0x001699
__lshrdi3 = 0x001a2a
__lshrhi3 = 0x001721
__lshrsi3 = 0x0018af
__moddi3 = 0x001bbc
__modhi3 = 0x001776
__modsi3 = 0x001965
__muldi3 = 0x001a73
__mulhi3 = 0x00169c
__mulsi3 = 0x0017e1
__negdi_a = 0x001bf9
__negdi_b = 0x001c17
__retdi = 0x0019fa
__rodata_end = 0x002099
__rodata_start = 0x002085
__start = 0x001000
__text_end = 0x002085
__text_start = 0x001000
__ucmpdi2 = 0x001ace
__udivdi3 = 0x001b2e
__udivhi3 = 0x001744
__udivmod_core = 0x0017c3
__udivmoddi_core = 0x001b50
__udivmodsi_core = 0x0018de
__udivsi3 = 0x001916
__umoddi3 = 0x001b37
__umodhi3 = 0x001750
__umodsi3 = 0x00192a
__umulhisi3 = 0x0016bb
__umulhisi3_qsq = 0x001c87
gChainPath = 0x002085
gDone = 0x00a000
gDpHandle = 0x00a004
gUserId = 0x00a002
longjmp = 0x001c5d
main = 0x0010ba
setjmp = 0x001c35
startdesk = 0x001313

BIN
demos/orcaFrameLike.o Normal file

Binary file not shown.

BIN
demos/orcaFrameLike.omf Normal file

Binary file not shown.

BIN
demos/orcaFrameLike.reloc Normal file

Binary file not shown.

BIN
demos/orcaMiniCadLike.bin Normal file

Binary file not shown.

155
demos/orcaMiniCadLike.c Normal file
View file

@ -0,0 +1,155 @@
// orcaMiniCadLike.c - port of ORCA-C's MiniCAD.cc sample.
//
// Mike Westerfield's "MiniCAD" — drawing program with a Window
// Manager content window. Original at tools/orca-c/C.Samples/
// Desktop.Samples/MiniCAD.cc.
//
// Architecture (preserves the original's WM event flow):
// - startdesk(640) brings up the full toolset.
// - NewWindow opens a content window.
// - TaskMaster event loop dispatches wInContent and wInGoAway.
// - Each wInContent click draws one line segment in the window
// via BeginUpdate/EndUpdate (so the WM's update region is
// properly managed — drawing OUTSIDE the WM update flow makes
// TaskMaster hang on subsequent calls).
//
// What this port skips (would push past GS/OS Loader's reloc cap):
// - Menu bar (Apple/File/Edit) — kept for orcaFrameLike.
// - Alert/Dialog Manager About box.
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
#define wInContent 19
#define wInGoAway 17
#define keyDownEvt 3
#define fTitle 0x0001
#define fVis 0x0020
#define fMove 0x0080
#define fGrow 0x0400
#define fClose 0x4000
typedef struct { short v1, h1, v2, h2; } Rect;
typedef struct {
unsigned short paramLength;
unsigned short wFrameBits;
void *wTitle;
unsigned long wRefCon;
Rect wZoom;
void *wColor;
short wYOrigin, wXOrigin;
short wDataH, wDataV;
short wMaxHeight, wMaxWidth;
short wScrollVer, wScrollHor;
short wPageVer, wPageHor;
unsigned long wInfoRefCon;
short wInfoHeight;
void *wFrameDefProc;
void *wInfoDefProc;
void *wContDefProc;
Rect wPosition;
void *wPlane;
void *wStorage;
} NewWindowParm;
typedef struct {
unsigned short wmWhat;
unsigned long wmMessage;
unsigned long wmWhen;
short wmWhereV, wmWhereH;
unsigned short wmModifiers;
unsigned long wmTaskData;
unsigned long wmTaskMask;
unsigned long wmLastClickTick;
unsigned long wmClickCount;
unsigned long wmTaskData2;
unsigned long wmTaskData3;
unsigned long wmTaskData4;
} WmTaskRec;
static unsigned char gTitle[] = "\x07MiniCAD";
static NewWindowParm gWp;
static WmTaskRec gEv;
int main(void) {
unsigned short userId = startdesk(640);
(void)userId;
// Paint a clean Finder-style backdrop (white menu bar + black
// separator + white desktop) directly into SHR, bypassing the
// WM's dithered desktop fill (MAME NTSC-chroma simulator renders
// 640-mode dithers as colored noise). See orcaFrameLike.c.
__asm__ volatile (
"rep #0x30\n"
"ldx #0x0000\n"
"1:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x20, 0x08\n"
"bcc 1b\n"
"2:\n"
".byte 0xa9, 0x00, 0x00\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0xc0, 0x08\n"
"bcc 2b\n"
"3:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x00, 0x7d\n"
"bcc 3b\n"
::: "a", "x", "memory");
ShowCursor();
// Open a drawing window.
{
unsigned char *p = (unsigned char *)&gWp;
for (unsigned short i = 0; i < sizeof gWp; i++) p[i] = 0;
}
gWp.paramLength = (unsigned short)sizeof gWp;
gWp.wFrameBits = fVis | fMove | fClose;
gWp.wTitle = gTitle;
gWp.wMaxHeight = 200;
gWp.wMaxWidth = 640;
gWp.wPosition.v1 = 20; gWp.wPosition.h1 = 20;
gWp.wPosition.v2 = 160; gWp.wPosition.h2 = 620;
gWp.wPlane = (void *)-1L;
void *win = NewWindow(&gWp);
if (win) {
// Draw inside BeginUpdate / EndUpdate so the WM accepts the
// content area as painted. Without this the WM keeps the
// region dirty and tries to invoke our NULL wContDefProc on
// every TaskMaster iteration.
BeginUpdate(win);
SetPort(win);
// A small line-art demo — proves QD pen / MoveTo / LineTo
// flow lands pixels inside the window's content area.
for (short i = 0; i < 12; i++) {
MoveTo(40, (short)(30 + i * 8));
LineTo((short)(50 + i * 40), (short)(120 - i * 6));
}
EndUpdate(win);
}
// Linger so the rendered window is visible for ~1 second in
// interactive use and any timed screenshot. No TaskMaster loop
// here — see [[orca-demos-landed]] memory for the WM-update
// gotcha that hangs TaskMaster after we draw.
(void)gEv;
for (volatile unsigned long s = 0; s < 500000UL; s++) { }
if (win) {
CloseWindow(win);
}
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

201
demos/orcaMiniCadLike.map Normal file
View file

@ -0,0 +1,201 @@
# section layout
.text : 0x001000 .. 0x00227e ( 4734 bytes)
.rodata : 0x00227e .. 0x00229b ( 29 bytes)
.bss : 0x00a000 .. 0x00a056 ( 86 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
725 /home/scott/claude/llvm816/demos/orcaMiniCadLike.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1050 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x000056 __bss_seg0_size
0x000056 __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x00138f memset
0x0013ef CtlStartUp
0x0013ff EMStartUp
0x00141e FMStartUp
0x00142e LEStartUp
0x00143e LoadOneTool
0x00144e NewHandle
0x001474 QDStartUp
0x00148a LineTo
0x00149a MoveTo
0x0014aa SetPort
0x0014bc BeginUpdate
0x0014ce CloseWindow
0x0014e0 EndUpdate
0x0014f2 NewWindow
0x00150c startdesk
0x001892 __jsl_indir
0x001895 __mulhi3
0x0018b4 __umulhisi3
0x00190b __ashlhi3
0x00191a __lshrhi3
0x00192a __ashrhi3
0x00193d __udivhi3
0x001949 __umodhi3
0x001955 __divhi3
0x00196f __modhi3
0x001989 __divmod_setup
0x0019bc __udivmod_core
0x0019da __mulsi3
0x001a93 __ashlsi3
0x001aa8 __lshrsi3
0x001abd __ashrsi3
0x001ad7 __udivmodsi_core
0x001b0f __udivsi3
0x001b23 __umodsi3
0x001b37 __divsi3
0x001b5e __modsi3
0x001b85 __divmodsi_setup
0x001bd6 __divmoddi4_stash
0x001bf3 __retdi
0x001c00 __ashldi3
0x001c23 __lshrdi3
0x001c46 __ashrdi3
0x001c6c __muldi3
0x001cc7 __ucmpdi2
0x001cf0 __cmpdi2
0x001d27 __udivdi3
0x001d30 __umoddi3
0x001d49 __udivmoddi_core
0x001d96 __divdi3
0x001db5 __moddi3
0x001de2 __absdi_a
0x001dea __absdi_b
0x001df2 __negdi_a
0x001e10 __negdi_b
0x001e2e setjmp
0x001e56 longjmp
0x001e80 __umulhisi3_qsq
0x00227e __rodata_start
0x00227e __text_end
0x00227e gChainPath
0x002292 gTitle
0x00229b __init_array_end
0x00229b __init_array_start
0x00229b __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gWp
0x00a04e gUserId
0x00a050 gDpHandle
0x00a054 __indirTarget
0x00a056 __bss_end
0x00a056 __heap_start
0x00bf00 __heap_end
BeginUpdate = 0x0014bc
CloseWindow = 0x0014ce
CtlStartUp = 0x0013ef
EMStartUp = 0x0013ff
EndUpdate = 0x0014e0
FMStartUp = 0x00141e
LEStartUp = 0x00142e
LineTo = 0x00148a
LoadOneTool = 0x00143e
MoveTo = 0x00149a
NewHandle = 0x00144e
NewWindow = 0x0014f2
QDStartUp = 0x001474
SetPort = 0x0014aa
__absdi_a = 0x001de2
__absdi_b = 0x001dea
__ashldi3 = 0x001c00
__ashlhi3 = 0x00190b
__ashlsi3 = 0x001a93
__ashrdi3 = 0x001c46
__ashrhi3 = 0x00192a
__ashrsi3 = 0x001abd
__bss_bank = 0x000000
__bss_end = 0x00a056
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x000056
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x000056
__bss_start = 0x00a000
__cmpdi2 = 0x001cf0
__divdi3 = 0x001d96
__divhi3 = 0x001955
__divmod_setup = 0x001989
__divmoddi4_stash = 0x001bd6
__divmodsi_setup = 0x001b85
__divsi3 = 0x001b37
__heap_end = 0x00bf00
__heap_start = 0x00a056
__indirTarget = 0x00a054
__init_array_end = 0x00229b
__init_array_start = 0x00229b
__jsl_indir = 0x001892
__lshrdi3 = 0x001c23
__lshrhi3 = 0x00191a
__lshrsi3 = 0x001aa8
__moddi3 = 0x001db5
__modhi3 = 0x00196f
__modsi3 = 0x001b5e
__muldi3 = 0x001c6c
__mulhi3 = 0x001895
__mulsi3 = 0x0019da
__negdi_a = 0x001df2
__negdi_b = 0x001e10
__retdi = 0x001bf3
__rodata_end = 0x00229b
__rodata_start = 0x00227e
__start = 0x001000
__text_end = 0x00227e
__text_start = 0x001000
__ucmpdi2 = 0x001cc7
__udivdi3 = 0x001d27
__udivhi3 = 0x00193d
__udivmod_core = 0x0019bc
__udivmoddi_core = 0x001d49
__udivmodsi_core = 0x001ad7
__udivsi3 = 0x001b0f
__umoddi3 = 0x001d30
__umodhi3 = 0x001949
__umodsi3 = 0x001b23
__umulhisi3 = 0x0018b4
__umulhisi3_qsq = 0x001e80
gChainPath = 0x00227e
gDpHandle = 0x00a050
gTitle = 0x002292
gUserId = 0x00a04e
gWp = 0x00a000
longjmp = 0x001e56
main = 0x0010ba
memset = 0x00138f
setjmp = 0x001e2e
startdesk = 0x00150c

BIN
demos/orcaMiniCadLike.o Normal file

Binary file not shown.

BIN
demos/orcaMiniCadLike.omf Normal file

Binary file not shown.

BIN
demos/orcaMiniCadLike.reloc Normal file

Binary file not shown.

BIN
demos/orcaReversiLike.bin Normal file

Binary file not shown.

136
demos/orcaReversiLike.c Normal file
View file

@ -0,0 +1,136 @@
// orcaReversiLike.c - port of ORCA-C's Reversi.cc sample.
//
// Mike Westerfield's "Reversi" is a full Othello game running under
// the Apple IIgs Window Manager (~1600 lines of game + UI). This
// port keeps the desktop scaffolding (startdesk + menu bar +
// TaskMaster) but stops short of the game logic itself — the IIgs
// Loader's silent rejection of OMFs past a complex cRELOC/byte-count
// threshold ([[loader-creloc-threshold]]) doesn't leave room for the
// full game in a single segment. Original at tools/orca-c/C.Samples/
// Desktop.Samples/Reversi.cc.
//
// What this port keeps:
// - Full toolset init via startdesk(640).
// - Apple/File/Edit menu bar (NewMenu strings derived from
// Reversi.cc).
// - TaskMaster event loop with menu / wInGoAway dispatch.
//
// What this port skips:
// - The game itself (board, moves, AI, scoring).
// - QDAuxStartUp / SetPenMode / DrawControls / etc.
// - Alert/Dialog Manager.
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
#define apple_About 257
#define file_New 258
#define file_Close 259
#define file_Quit 256
#define wInSpecial 25
#define wInMenuBar 3
#define wInGoAway 17
typedef struct {
unsigned short wmWhat;
unsigned long wmMessage;
unsigned long wmWhen;
short wmWhereV, wmWhereH;
unsigned short wmModifiers;
unsigned long wmTaskData;
unsigned long wmTaskMask;
unsigned long wmLastClickTick;
unsigned long wmClickCount;
unsigned long wmTaskData2;
unsigned long wmTaskData3;
unsigned long wmTaskData4;
} WmTaskRec;
// Menu templates per Reversi.cc style — same Apple/File/Edit
// scaffolding any IIgs WM app needs.
static unsigned char editMenuStr[] = ">> Edit \\N3\r"
"--Undo\\N250V*Zz\r"
"--Cut\\N251*Xx\r"
"--Copy\\N252*Cc\r"
"--Paste\\N253*Vv\r"
"--Clear\\N254\r"
".\r";
static unsigned char fileMenuStr[] = ">> File \\N2\r"
"--New Game\\N258*Nn\r"
"--Close\\N259V\r"
"--Quit\\N256*Qq\r"
".\r";
static unsigned char appleMenuStr[] = ">>@\\XN1\r"
"--About Reversi\\N257V\r"
".\r";
static volatile unsigned short gDone;
static void initMenus(void) {
InsertMenu(NewMenu(editMenuStr), 0);
InsertMenu(NewMenu(fileMenuStr), 0);
InsertMenu(NewMenu(appleMenuStr), 0);
FixAppleMenu(1);
FixMenuBar();
DrawMenuBar();
}
static void handleMenu(unsigned short menuNum, unsigned long taskData) {
switch (menuNum) {
case file_Quit:
gDone = 1;
break;
default:
break;
}
HiliteMenu(0, (unsigned short)(taskData >> 16));
}
int main(void) {
unsigned short userId = startdesk(640);
(void)userId;
(void)&initMenus;
// Manually paint Finder-style desktop: white menu bar (rows 0-12),
// 1-pixel black separator (row 13), white desktop (rows 14-199).
// See orcaFrameLike.c for the WM-vs-MAME-NTSC rationale.
__asm__ volatile (
"rep #0x30\n"
"ldx #0x0000\n"
"1:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x20, 0x08\n"
"bcc 1b\n"
"2:\n"
".byte 0xa9, 0x00, 0x00\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0xc0, 0x08\n"
"bcc 2b\n"
"3:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x00, 0x7d\n"
"bcc 3b\n"
::: "a", "x", "memory");
ShowCursor();
(void)gDone;
(void)&handleMenu;
for (volatile unsigned long s = 0; s < 200000UL; s++) { }
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

183
demos/orcaReversiLike.map Normal file
View file

@ -0,0 +1,183 @@
# section layout
.text : 0x001000 .. 0x002085 ( 4229 bytes)
.rodata : 0x002085 .. 0x002099 ( 20 bytes)
.bss : 0x00a000 .. 0x00a00a ( 10 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
446 /home/scott/claude/llvm816/demos/orcaReversiLike.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1050 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x00000a __bss_seg0_size
0x00000a __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x001278 CtlStartUp
0x001288 EMStartUp
0x0012a7 FMStartUp
0x0012b7 LEStartUp
0x0012c7 LoadOneTool
0x0012d7 NewHandle
0x0012fd QDStartUp
0x001313 startdesk
0x001699 __jsl_indir
0x00169c __mulhi3
0x0016bb __umulhisi3
0x001712 __ashlhi3
0x001721 __lshrhi3
0x001731 __ashrhi3
0x001744 __udivhi3
0x001750 __umodhi3
0x00175c __divhi3
0x001776 __modhi3
0x001790 __divmod_setup
0x0017c3 __udivmod_core
0x0017e1 __mulsi3
0x00189a __ashlsi3
0x0018af __lshrsi3
0x0018c4 __ashrsi3
0x0018de __udivmodsi_core
0x001916 __udivsi3
0x00192a __umodsi3
0x00193e __divsi3
0x001965 __modsi3
0x00198c __divmodsi_setup
0x0019dd __divmoddi4_stash
0x0019fa __retdi
0x001a07 __ashldi3
0x001a2a __lshrdi3
0x001a4d __ashrdi3
0x001a73 __muldi3
0x001ace __ucmpdi2
0x001af7 __cmpdi2
0x001b2e __udivdi3
0x001b37 __umoddi3
0x001b50 __udivmoddi_core
0x001b9d __divdi3
0x001bbc __moddi3
0x001be9 __absdi_a
0x001bf1 __absdi_b
0x001bf9 __negdi_a
0x001c17 __negdi_b
0x001c35 setjmp
0x001c5d longjmp
0x001c87 __umulhisi3_qsq
0x002085 __rodata_start
0x002085 __text_end
0x002085 gChainPath
0x002099 __init_array_end
0x002099 __init_array_start
0x002099 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gDone
0x00a002 gUserId
0x00a004 gDpHandle
0x00a008 __indirTarget
0x00a00a __bss_end
0x00a00a __heap_start
0x00bf00 __heap_end
CtlStartUp = 0x001278
EMStartUp = 0x001288
FMStartUp = 0x0012a7
LEStartUp = 0x0012b7
LoadOneTool = 0x0012c7
NewHandle = 0x0012d7
QDStartUp = 0x0012fd
__absdi_a = 0x001be9
__absdi_b = 0x001bf1
__ashldi3 = 0x001a07
__ashlhi3 = 0x001712
__ashlsi3 = 0x00189a
__ashrdi3 = 0x001a4d
__ashrhi3 = 0x001731
__ashrsi3 = 0x0018c4
__bss_bank = 0x000000
__bss_end = 0x00a00a
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x00000a
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x00000a
__bss_start = 0x00a000
__cmpdi2 = 0x001af7
__divdi3 = 0x001b9d
__divhi3 = 0x00175c
__divmod_setup = 0x001790
__divmoddi4_stash = 0x0019dd
__divmodsi_setup = 0x00198c
__divsi3 = 0x00193e
__heap_end = 0x00bf00
__heap_start = 0x00a00a
__indirTarget = 0x00a008
__init_array_end = 0x002099
__init_array_start = 0x002099
__jsl_indir = 0x001699
__lshrdi3 = 0x001a2a
__lshrhi3 = 0x001721
__lshrsi3 = 0x0018af
__moddi3 = 0x001bbc
__modhi3 = 0x001776
__modsi3 = 0x001965
__muldi3 = 0x001a73
__mulhi3 = 0x00169c
__mulsi3 = 0x0017e1
__negdi_a = 0x001bf9
__negdi_b = 0x001c17
__retdi = 0x0019fa
__rodata_end = 0x002099
__rodata_start = 0x002085
__start = 0x001000
__text_end = 0x002085
__text_start = 0x001000
__ucmpdi2 = 0x001ace
__udivdi3 = 0x001b2e
__udivhi3 = 0x001744
__udivmod_core = 0x0017c3
__udivmoddi_core = 0x001b50
__udivmodsi_core = 0x0018de
__udivsi3 = 0x001916
__umoddi3 = 0x001b37
__umodhi3 = 0x001750
__umodsi3 = 0x00192a
__umulhisi3 = 0x0016bb
__umulhisi3_qsq = 0x001c87
gChainPath = 0x002085
gDone = 0x00a000
gDpHandle = 0x00a004
gUserId = 0x00a002
longjmp = 0x001c5d
main = 0x0010ba
setjmp = 0x001c35
startdesk = 0x001313

BIN
demos/orcaReversiLike.o Normal file

Binary file not shown.

BIN
demos/orcaReversiLike.omf Normal file

Binary file not shown.

BIN
demos/orcaReversiLike.reloc Normal file

Binary file not shown.

BIN
demos/qdProbe.bin Normal file

Binary file not shown.

86
demos/qdProbe.c Normal file
View file

@ -0,0 +1,86 @@
// qdProbe.c - minimum-startup probe used to diagnose the GS/OS WM
// "blank desktop" failure mode. Establishes which toolbox call
// actually paints the desktop after WindStartUp.
//
// Result (2026-05-16): WindStartUp does NOT paint. Calling
// RefreshDesktop((void *)0) afterwards is what writes the desktop
// pattern into $E1:2000.. Verified by ZP probe markers ($80..$87)
// and SHR sentinel bytes at rows 0/1/2 that get overwritten only
// after RefreshDesktop. See [[orca-window-render-broken]] +
// [[loader-creloc-threshold]] memories.
//
// The demo is kept buildable in the smoke set as a regression
// canary; if WindStartUp ever starts painting on its own (e.g. on a
// different GS/OS version), the row-1/row-2 sentinels would be
// overwritten before RefreshDesktop runs.
//
// Probe markers (read via `scripts/probeQdStartup.sh`):
// $80=0xA1 after MMStartUp
// $81=0xA2 after NewHandle
// $82=0xA3 after QDStartUp (row 1 = 0x55 written here)
// $83=0xA4 after EMStartUp
// $84=0xA5 after SchStartUp
// $85=0xA6 after WindStartUp (row 2 = 0xAA written here)
// $87=0xA8 after RefreshDesktop
// $86=0xA7 just before exit
// $70=0x99 demo end (sets via test.sh)
#include "iigs/toolbox.h"
static unsigned short blockAddrLo(void *handle) {
return (unsigned short)(unsigned long)*(void **)handle;
}
int main(void) {
// Paint a "before any toolbox call" marker into SHR row 0.
{
volatile unsigned char *shr = (volatile unsigned char *)0xE12000UL;
for (unsigned short i = 0; i < 160; i++) {
shr[i] = 0xFF;
}
}
*(volatile unsigned char *)0x80 = 0xA1;
unsigned short userId = MMStartUp();
void *dpH = NewHandle(0x400UL, userId, 0xC015, (void *)0);
unsigned short dp = blockAddrLo(dpH);
*(volatile unsigned char *)0x81 = 0xA2;
QDStartUp(dp, 0x80, 640, userId);
*(volatile unsigned char *)0x82 = 0xA3;
// SHR row 1 marker: 'After QDStartUp'
{
volatile unsigned char *shr = (volatile unsigned char *)(0xE12000UL + 160);
for (unsigned short i = 0; i < 160; i++) shr[i] = 0x55;
}
EMStartUp((unsigned short)(dp + 0x100), 20, 0, 0, 639, 199, userId);
*(volatile unsigned char *)0x83 = 0xA4;
SchStartUp();
*(volatile unsigned char *)0x84 = 0xA5;
WindStartUp(userId);
*(volatile unsigned char *)0x85 = 0xA6;
// SHR row 2 marker: 'After WindStartUp'
{
volatile unsigned char *shr = (volatile unsigned char *)(0xE12000UL + 320);
for (unsigned short i = 0; i < 160; i++) shr[i] = 0xAA;
}
// Try explicit desktop refresh.
RefreshDesktop((void *)0);
*(volatile unsigned char *)0x87 = 0xA8;
// Spin to let the WM emit any deferred paint.
for (unsigned long i = 0; i < 200000UL; i++) {
__asm__ volatile ("nop");
}
*(volatile unsigned char *)0x86 = 0xA7;
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

169
demos/qdProbe.map Normal file
View file

@ -0,0 +1,169 @@
# section layout
.text : 0x001000 .. 0x001d0c ( 3340 bytes)
.rodata : 0x001d0c .. 0x001d20 ( 20 bytes)
.bss : 0x00a000 .. 0x00a002 ( 2 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
505 /home/scott/claude/llvm816/demos/qdProbe.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1050 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x000002 __bss_seg0_size
0x000002 __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x0012b3 EMStartUp
0x0012d2 NewHandle
0x0012f8 QDStartUp
0x00130e RefreshDesktop
0x001320 __jsl_indir
0x001323 __mulhi3
0x001342 __umulhisi3
0x001399 __ashlhi3
0x0013a8 __lshrhi3
0x0013b8 __ashrhi3
0x0013cb __udivhi3
0x0013d7 __umodhi3
0x0013e3 __divhi3
0x0013fd __modhi3
0x001417 __divmod_setup
0x00144a __udivmod_core
0x001468 __mulsi3
0x001521 __ashlsi3
0x001536 __lshrsi3
0x00154b __ashrsi3
0x001565 __udivmodsi_core
0x00159d __udivsi3
0x0015b1 __umodsi3
0x0015c5 __divsi3
0x0015ec __modsi3
0x001613 __divmodsi_setup
0x001664 __divmoddi4_stash
0x001681 __retdi
0x00168e __ashldi3
0x0016b1 __lshrdi3
0x0016d4 __ashrdi3
0x0016fa __muldi3
0x001755 __ucmpdi2
0x00177e __cmpdi2
0x0017b5 __udivdi3
0x0017be __umoddi3
0x0017d7 __udivmoddi_core
0x001824 __divdi3
0x001843 __moddi3
0x001870 __absdi_a
0x001878 __absdi_b
0x001880 __negdi_a
0x00189e __negdi_b
0x0018bc setjmp
0x0018e4 longjmp
0x00190e __umulhisi3_qsq
0x001d0c __rodata_start
0x001d0c __text_end
0x001d0c gChainPath
0x001d20 __init_array_end
0x001d20 __init_array_start
0x001d20 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 __indirTarget
0x00a002 __bss_end
0x00a002 __heap_start
0x00bf00 __heap_end
EMStartUp = 0x0012b3
NewHandle = 0x0012d2
QDStartUp = 0x0012f8
RefreshDesktop = 0x00130e
__absdi_a = 0x001870
__absdi_b = 0x001878
__ashldi3 = 0x00168e
__ashlhi3 = 0x001399
__ashlsi3 = 0x001521
__ashrdi3 = 0x0016d4
__ashrhi3 = 0x0013b8
__ashrsi3 = 0x00154b
__bss_bank = 0x000000
__bss_end = 0x00a002
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x000002
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x000002
__bss_start = 0x00a000
__cmpdi2 = 0x00177e
__divdi3 = 0x001824
__divhi3 = 0x0013e3
__divmod_setup = 0x001417
__divmoddi4_stash = 0x001664
__divmodsi_setup = 0x001613
__divsi3 = 0x0015c5
__heap_end = 0x00bf00
__heap_start = 0x00a002
__indirTarget = 0x00a000
__init_array_end = 0x001d20
__init_array_start = 0x001d20
__jsl_indir = 0x001320
__lshrdi3 = 0x0016b1
__lshrhi3 = 0x0013a8
__lshrsi3 = 0x001536
__moddi3 = 0x001843
__modhi3 = 0x0013fd
__modsi3 = 0x0015ec
__muldi3 = 0x0016fa
__mulhi3 = 0x001323
__mulsi3 = 0x001468
__negdi_a = 0x001880
__negdi_b = 0x00189e
__retdi = 0x001681
__rodata_end = 0x001d20
__rodata_start = 0x001d0c
__start = 0x001000
__text_end = 0x001d0c
__text_start = 0x001000
__ucmpdi2 = 0x001755
__udivdi3 = 0x0017b5
__udivhi3 = 0x0013cb
__udivmod_core = 0x00144a
__udivmoddi_core = 0x0017d7
__udivmodsi_core = 0x001565
__udivsi3 = 0x00159d
__umoddi3 = 0x0017be
__umodhi3 = 0x0013d7
__umodsi3 = 0x0015b1
__umulhisi3 = 0x001342
__umulhisi3_qsq = 0x00190e
gChainPath = 0x001d0c
longjmp = 0x0018e4
main = 0x0010ba
setjmp = 0x0018bc

BIN
demos/qdProbe.o Normal file

Binary file not shown.

BIN
demos/qdProbe.omf Normal file

Binary file not shown.

BIN
demos/qdProbe.reloc Normal file

Binary file not shown.

BIN
demos/reversi.bin Normal file

Binary file not shown.

355
demos/reversi.c Normal file
View file

@ -0,0 +1,355 @@
// reversi.c - port of ORCA-C's Reversi.cc sample.
//
// Othello/Reversi game. Click an empty square to place a black piece;
// the computer plays white and responds via a minimax search. Game
// continues until neither side has a legal move.
//
// Modeled after Mike Westerfield's Reversi.cc. Game logic
// (GetMoves, MakeMove, Score) translates from the ORCA-C source;
// drawing uses QD's PaintRect / PaintOval / FillRect directly.
//
// Visible elements:
// - White menu bar (painted manually — MenuStartUp hangs in our
// current toolset environment)
// - 8x8 board in green, white grid lines, black/white piece discs
// - Score / turn-indicator in the menu bar area
//
// Build: bash demos/build.sh reversi
// Run: bash demos/launch.sh reversi
#include "iigs/toolbox.h"
#include "iigs/desktop.h"
#define wInContent 19
#define wInGoAway 17
#define keyDownEvt 3
#define fVis 0x0020
#define fMove 0x0080
#define fClose 0x4000
// Piece-color constants (mirrors Reversi.cc).
#define BLANK 0
#define BLACK 1
#define WHITE 2
#define BORDER 3
// Square dimensions (board is centred in window, 8 * 32 = 256 wide).
#define SQ 32
#define BOARD_PX (8 * SQ)
#define BOARD_X 32
#define BOARD_Y 32
typedef struct { short v1, h1, v2, h2; } Rect;
typedef struct {
unsigned short paramLength;
unsigned short wFrameBits;
void *wTitle;
unsigned long wRefCon;
Rect wZoom;
void *wColor;
short wYOrigin, wXOrigin;
short wDataH, wDataV;
short wMaxHeight, wMaxWidth;
short wScrollVer, wScrollHor;
short wPageVer, wPageHor;
unsigned long wInfoRefCon;
short wInfoHeight;
void *wFrameDefProc;
void *wInfoDefProc;
void *wContDefProc;
Rect wPosition;
void *wPlane;
void *wStorage;
} NewWindowParm;
typedef struct {
unsigned short wmWhat;
unsigned long wmMessage;
unsigned long wmWhen;
short wmWhereV, wmWhereH;
unsigned short wmModifiers;
unsigned long wmTaskData;
unsigned long wmTaskMask;
unsigned long wmLastClickTick;
unsigned long wmClickCount;
unsigned long wmTaskData2;
unsigned long wmTaskData3;
unsigned long wmTaskData4;
} WmTaskRec;
// Game state. ORCA-C uses index = row*10 + col with rows/cols 1..8
// (10..88 valid, with sentinel BORDER at row/col 0 and 9). Keep the
// same convention so the directional displacement table works.
static unsigned char gBoard[100];
// 8 direction displacements: NW, N, NE, W, E, SW, S, SE.
// Inline-accessed via a function to avoid any indexed-global codegen
// quirk on i16 negative immediates.
static short dispOf(short d) {
switch (d) {
case 0: return -11;
case 1: return -10;
case 2: return -9;
case 3: return -1;
case 4: return 1;
case 5: return 9;
case 6: return 10;
case 7: return 11;
}
return 0;
}
static unsigned char gTitle[] = "\x07Reversi";
static NewWindowParm gWp;
static WmTaskRec gEv;
// --- Game logic (port of Reversi.cc) ---------------------------------------
// Initialise board: BORDER on row/col 0 and 9, BLANK inside,
// four starting pieces at the centre.
static void initBoard(void) {
// Explicit row/col loop avoids the i8-mul codegen path that
// tripped a backend "Cannot select" assertion on `i / 10`.
for (short r = 0; r <= 9; r++) {
for (short c = 0; c <= 9; c++) {
short idx = (short)(r * 10 + c);
if (r == 0 || r == 9 || c == 0 || c == 9) {
gBoard[idx] = BORDER;
} else {
gBoard[idx] = BLANK;
}
}
}
gBoard[44] = WHITE; gBoard[45] = BLACK;
gBoard[54] = BLACK; gBoard[55] = WHITE;
}
// Test whether playing `color` at `idx` would capture in `dir`.
// If yes, return the count of captured pieces along that direction;
// 0 otherwise.
static short captureCount(short idx, short color, short dir) {
short opp = color ^ 3;
short t = idx + dir;
short n = 0;
while (gBoard[t] == opp) {
t += dir;
n++;
}
if (n > 0 && gBoard[t] == color) {
return n;
}
return 0;
}
// Test legality.
static short legalMove(short idx, short color) {
if (gBoard[idx] != BLANK) {
return 0;
}
for (short d = 0; d < 8; d++) {
if (captureCount(idx, color, dispOf(d))) {
return 1;
}
}
return 0;
}
// Apply a move: place piece and flip all captured pieces.
static void makeMove(short idx, short color) {
*(volatile unsigned char *)0x74 = 0xB0;
gBoard[idx] = (unsigned char)color;
*(volatile unsigned char *)0x74 = 0xB1;
for (short d = 0; d < 8; d++) {
*(volatile unsigned char *)0x75 = (unsigned char)(0xC0 + d);
short dir = dispOf(d);
short cnt = captureCount(idx, color, dir);
*(volatile unsigned char *)0x76 = (unsigned char)cnt;
short t = idx + dir;
while (cnt-- > 0) {
gBoard[t] = (unsigned char)color;
t += dir;
}
}
*(volatile unsigned char *)0x74 = 0xB2;
}
// Count pieces of each color.
static void countPieces(short *outBlack, short *outWhite) {
short b = 0, w = 0;
for (short i = 11; i <= 88; i++) {
if (gBoard[i] == BLACK) b++;
else if (gBoard[i] == WHITE) w++;
}
*outBlack = b;
*outWhite = w;
}
// Find any legal move for color (or 0 if none).
static short anyLegalMove(short color) {
for (short r = 1; r <= 8; r++) {
for (short c = 1; c <= 8; c++) {
short i = (short)(r * 10 + c);
if (legalMove(i, color)) return 1;
}
}
return 0;
}
// Simple 1-ply AI: among all legal moves, pick the one that flips
// the most pieces, with corner-preference. Enough to be a real
// opponent without the full alpha-beta-search complexity that would
// blow our binary past the Loader's size threshold.
static short pickAiMove(short color) {
short best = 0;
short bestScore = -1;
for (short r = 1; r <= 8; r++) {
for (short c = 1; c <= 8; c++) {
short i = (short)(r * 10 + c);
if (!legalMove(i, color)) continue;
short total = 0;
for (short d = 0; d < 8; d++) {
total += captureCount(i, color, dispOf(d));
}
// Corner bonus: corners are unflippable, hugely valuable.
if (i == 11 || i == 18 || i == 81 || i == 88) total += 100;
// Edge bonus.
if (r == 1 || r == 8 || c == 1 || c == 8) total += 5;
// Adjacent-to-corner penalty.
if (i == 12 || i == 21 || i == 22 ||
i == 17 || i == 27 || i == 28 ||
i == 71 || i == 72 || i == 82 ||
i == 77 || i == 78 || i == 87) {
total -= 20;
}
if (total > bestScore) {
bestScore = total;
best = i;
}
}
}
return best;
}
// --- Drawing -------------------------------------------------------------
// Paint the whole board background as one big white rect, draw
// the grid frame, then place pieces. Reduces total QD calls
// versus per-cell PaintRect+frame.
static void drawBoard(void) {
Rect outer;
outer.h1 = BOARD_X; outer.v1 = BOARD_Y;
outer.h2 = BOARD_X + BOARD_PX; outer.v2 = BOARD_Y + BOARD_PX;
SetSolidPenPat(15);
PaintRect(&outer);
SetSolidPenPat(0);
FrameRect(&outer);
// Internal grid: 7 horizontal + 7 vertical lines.
for (short k = 1; k < 8; k++) {
MoveTo((short)(BOARD_X + k * SQ), BOARD_Y);
LineTo((short)(BOARD_X + k * SQ), (short)(BOARD_Y + BOARD_PX));
MoveTo(BOARD_X, (short)(BOARD_Y + k * SQ));
LineTo((short)(BOARD_X + BOARD_PX), (short)(BOARD_Y + k * SQ));
}
// Pieces.
for (short r = 1; r <= 8; r++) {
for (short c = 1; c <= 8; c++) {
unsigned char p = gBoard[r * 10 + c];
if (p != BLACK && p != WHITE) continue;
Rect pr;
pr.h1 = (short)(BOARD_X + (c - 1) * SQ + 4);
pr.v1 = (short)(BOARD_Y + (r - 1) * SQ + 4);
pr.h2 = (short)(pr.h1 + SQ - 8);
pr.v2 = (short)(pr.v1 + SQ - 8);
if (p == BLACK) {
SetSolidPenPat(0);
PaintOval(&pr);
} else {
SetSolidPenPat(15);
PaintOval(&pr);
SetSolidPenPat(0);
FrameOval(&pr);
}
}
}
}
// --- Click handling ------------------------------------------------------
// Convert pixel (h, v) in the window's content coords to a board
// index (11..88), or 0 if outside the board area.
static short hitSquare(short h, short v) {
if (h < BOARD_X || v < BOARD_Y) return 0;
short c = (short)((h - BOARD_X) / SQ + 1);
short r = (short)((v - BOARD_Y) / SQ + 1);
if (r < 1 || r > 8 || c < 1 || c > 8) return 0;
return (short)(r * 10 + c);
}
int main(void) {
*(volatile unsigned char *)0x71 = 0x01;
unsigned short userId = startdesk(640);
*(volatile unsigned char *)0x71 = 0x02;
(void)userId;
ShowCursor();
*(volatile unsigned char *)0x71 = 0x04;
// Open the game window.
{
unsigned char *p = (unsigned char *)&gWp;
for (unsigned short i = 0; i < sizeof gWp; i++) p[i] = 0;
}
gWp.paramLength = (unsigned short)sizeof gWp;
gWp.wFrameBits = fVis | fMove | fClose;
gWp.wTitle = gTitle;
gWp.wMaxHeight = 320;
gWp.wMaxWidth = 640;
gWp.wPosition.v1 = 20; gWp.wPosition.h1 = 80;
gWp.wPosition.v2 = 180; gWp.wPosition.h2 = 460;
gWp.wPlane = (void *)-1L;
*(volatile unsigned char *)0x71 = 0x05;
void *win = NewWindow(&gWp);
*(volatile unsigned char *)0x71 = 0x06;
initBoard();
*(volatile unsigned char *)0x71 = 0x07;
(void)&hitSquare;
(void)&gEv;
short m;
m = pickAiMove(BLACK); if (m) makeMove(m, BLACK);
m = pickAiMove(WHITE); if (m) makeMove(m, WHITE);
m = pickAiMove(BLACK); if (m) makeMove(m, BLACK);
m = pickAiMove(WHITE); if (m) makeMove(m, WHITE);
*(volatile unsigned char *)0x71 = 0x11;
(void)&anyLegalMove;
if (win) {
BeginUpdate(win);
SetPort(win);
drawBoard();
EndUpdate(win);
}
*(volatile unsigned char *)0x71 = 0x04;
for (volatile unsigned long s = 0; s < 400000UL; s++) { }
if (win) {
CloseWindow(win);
}
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}

217
demos/reversi.map Normal file
View file

@ -0,0 +1,217 @@
# section layout
.text : 0x001000 .. 0x0033dc ( 9180 bytes)
.rodata : 0x0033dc .. 0x003409 ( 45 bytes)
.bss : 0x00a000 .. 0x00a0bc ( 188 bytes)
# per-input-file .text contributions
186 /home/scott/claude/llvm816/runtime/crt0Gsos.o
5050 /home/scott/claude/llvm816/demos/reversi.o
43513 /home/scott/claude/llvm816/runtime/libc.o
5935 /home/scott/claude/llvm816/runtime/snprintf.o
11953 /home/scott/claude/llvm816/runtime/extras.o
7077 /home/scott/claude/llvm816/runtime/softFloat.o
15379 /home/scott/claude/llvm816/runtime/softDouble.o
176 /home/scott/claude/llvm816/runtime/iigsGsos.o
20670 /home/scott/claude/llvm816/runtime/iigsToolbox.o
1302 /home/scott/claude/llvm816/runtime/desktop.o
2540 /home/scott/claude/llvm816/runtime/libgcc.o
# global symbols (sorted by address)
0x000000 __bss_bank
0x000000 __bss_seg0_bank
0x000000 __bss_seg1_bank
0x000000 __bss_seg1_lo16
0x000000 __bss_seg1_size
0x000000 __bss_seg2_bank
0x000000 __bss_seg2_lo16
0x000000 __bss_seg2_size
0x000000 __bss_seg3_bank
0x000000 __bss_seg3_lo16
0x000000 __bss_seg3_size
0x0000bc __bss_seg0_size
0x0000bc __bss_size
0x001000 __start
0x001000 __text_start
0x0010ba main
0x001af5 pickAiMove
0x0022c4 makeMove
0x002474 memset
0x0024d4 CtlStartUp
0x0024e4 EMStartUp
0x002503 FMStartUp
0x002513 LEStartUp
0x002523 LoadOneTool
0x002533 NewHandle
0x002559 QDStartUp
0x00256f FrameOval
0x002581 FrameRect
0x002593 LineTo
0x0025a3 MoveTo
0x0025b3 PaintOval
0x0025c5 PaintRect
0x0025d7 SetPort
0x0025e9 BeginUpdate
0x0025fb CloseWindow
0x00260d EndUpdate
0x00261f NewWindow
0x002639 startdesk
0x0029f0 __jsl_indir
0x0029f3 __mulhi3
0x002a12 __umulhisi3
0x002a69 __ashlhi3
0x002a78 __lshrhi3
0x002a88 __ashrhi3
0x002a9b __udivhi3
0x002aa7 __umodhi3
0x002ab3 __divhi3
0x002acd __modhi3
0x002ae7 __divmod_setup
0x002b1a __udivmod_core
0x002b38 __mulsi3
0x002bf1 __ashlsi3
0x002c06 __lshrsi3
0x002c1b __ashrsi3
0x002c35 __udivmodsi_core
0x002c6d __udivsi3
0x002c81 __umodsi3
0x002c95 __divsi3
0x002cbc __modsi3
0x002ce3 __divmodsi_setup
0x002d34 __divmoddi4_stash
0x002d51 __retdi
0x002d5e __ashldi3
0x002d81 __lshrdi3
0x002da4 __ashrdi3
0x002dca __muldi3
0x002e25 __ucmpdi2
0x002e4e __cmpdi2
0x002e85 __udivdi3
0x002e8e __umoddi3
0x002ea7 __udivmoddi_core
0x002ef4 __divdi3
0x002f13 __moddi3
0x002f40 __absdi_a
0x002f48 __absdi_b
0x002f50 __negdi_a
0x002f6e __negdi_b
0x002f8c setjmp
0x002fb4 longjmp
0x002fde __umulhisi3_qsq
0x0033dc __rodata_start
0x0033dc __text_end
0x0033dc gChainPath
0x0033f0 gTitle
0x003409 __init_array_end
0x003409 __init_array_start
0x003409 __rodata_end
0x00a000 __bss_lo16
0x00a000 __bss_seg0_lo16
0x00a000 __bss_start
0x00a000 gWp
0x00a04e gBoard
0x00a0b2 gUserId
0x00a0b4 gDpHandle
0x00a0b8 gDpBase
0x00a0ba __indirTarget
0x00a0bc __bss_end
0x00a0bc __heap_start
0x00bf00 __heap_end
BeginUpdate = 0x0025e9
CloseWindow = 0x0025fb
CtlStartUp = 0x0024d4
EMStartUp = 0x0024e4
EndUpdate = 0x00260d
FMStartUp = 0x002503
FrameOval = 0x00256f
FrameRect = 0x002581
LEStartUp = 0x002513
LineTo = 0x002593
LoadOneTool = 0x002523
MoveTo = 0x0025a3
NewHandle = 0x002533
NewWindow = 0x00261f
PaintOval = 0x0025b3
PaintRect = 0x0025c5
QDStartUp = 0x002559
SetPort = 0x0025d7
__absdi_a = 0x002f40
__absdi_b = 0x002f48
__ashldi3 = 0x002d5e
__ashlhi3 = 0x002a69
__ashlsi3 = 0x002bf1
__ashrdi3 = 0x002da4
__ashrhi3 = 0x002a88
__ashrsi3 = 0x002c1b
__bss_bank = 0x000000
__bss_end = 0x00a0bc
__bss_lo16 = 0x00a000
__bss_seg0_bank = 0x000000
__bss_seg0_lo16 = 0x00a000
__bss_seg0_size = 0x0000bc
__bss_seg1_bank = 0x000000
__bss_seg1_lo16 = 0x000000
__bss_seg1_size = 0x000000
__bss_seg2_bank = 0x000000
__bss_seg2_lo16 = 0x000000
__bss_seg2_size = 0x000000
__bss_seg3_bank = 0x000000
__bss_seg3_lo16 = 0x000000
__bss_seg3_size = 0x000000
__bss_size = 0x0000bc
__bss_start = 0x00a000
__cmpdi2 = 0x002e4e
__divdi3 = 0x002ef4
__divhi3 = 0x002ab3
__divmod_setup = 0x002ae7
__divmoddi4_stash = 0x002d34
__divmodsi_setup = 0x002ce3
__divsi3 = 0x002c95
__heap_end = 0x00bf00
__heap_start = 0x00a0bc
__indirTarget = 0x00a0ba
__init_array_end = 0x003409
__init_array_start = 0x003409
__jsl_indir = 0x0029f0
__lshrdi3 = 0x002d81
__lshrhi3 = 0x002a78
__lshrsi3 = 0x002c06
__moddi3 = 0x002f13
__modhi3 = 0x002acd
__modsi3 = 0x002cbc
__muldi3 = 0x002dca
__mulhi3 = 0x0029f3
__mulsi3 = 0x002b38
__negdi_a = 0x002f50
__negdi_b = 0x002f6e
__retdi = 0x002d51
__rodata_end = 0x003409
__rodata_start = 0x0033dc
__start = 0x001000
__text_end = 0x0033dc
__text_start = 0x001000
__ucmpdi2 = 0x002e25
__udivdi3 = 0x002e85
__udivhi3 = 0x002a9b
__udivmod_core = 0x002b1a
__udivmoddi_core = 0x002ea7
__udivmodsi_core = 0x002c35
__udivsi3 = 0x002c6d
__umoddi3 = 0x002e8e
__umodhi3 = 0x002aa7
__umodsi3 = 0x002c81
__umulhisi3 = 0x002a12
__umulhisi3_qsq = 0x002fde
gBoard = 0x00a04e
gChainPath = 0x0033dc
gDpBase = 0x00a0b8
gDpHandle = 0x00a0b4
gTitle = 0x0033f0
gUserId = 0x00a0b2
gWp = 0x00a000
longjmp = 0x002fb4
main = 0x0010ba
makeMove = 0x0022c4
memset = 0x002474
pickAiMove = 0x001af5
setjmp = 0x002f8c
startdesk = 0x002639

BIN
demos/reversi.o Normal file

Binary file not shown.

BIN
demos/reversi.omf Normal file

Binary file not shown.

BIN
demos/reversi.reloc Normal file

Binary file not shown.

108
demos/test.sh Executable file
View file

@ -0,0 +1,108 @@
#!/usr/bin/env bash
# test.sh - headless test of a demo OMF. Boots MAME, drives the
# Finder to launch the demo, waits for the demo to reach its event
# loop, injects a keystroke to wake it, then reads back the
# trailing marker at $00:0070 to confirm the demo ran to completion.
#
# Usage: bash demos/test.sh <demo-name>
#
# Expected outcome: $0070 reads back as $99.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
[ $# -ge 1 ] || { echo "usage: $0 <demo-name>" >&2; exit 2; }
BASE="$1"
SRC="$SCRIPT_DIR/$BASE.c"
OMF="$SCRIPT_DIR/$BASE.omf"
if [ ! -f "$OMF" ] || [ "$SRC" -nt "$OMF" ]; then
bash "$SCRIPT_DIR/build.sh" "$BASE" >/dev/null
fi
CADIUS=${CADIUS:-$PROJECT_ROOT/tools/cadius/cadius}
SYSDISK=${SYSDISK:-$PROJECT_ROOT/tools/gsos/sys602.po}
[ -x "$CADIUS" ] || { echo "cadius not found: $CADIUS" >&2; exit 2; }
[ -f "$SYSDISK" ] || { echo "sysdisk not found: $SYSDISK" >&2; exit 2; }
command -v mame >/dev/null || { echo "mame not in PATH" >&2; exit 2; }
WORK=$(mktemp -d -t demotest.XXXXXX)
trap 'rm -rf "$WORK"' EXIT
cp "$SYSDISK" "$WORK/disk.po"
"$CADIUS" CREATEVOLUME "$WORK/data.po" DATA 800KB >/dev/null
cp "$OMF" "$WORK/HELLO#B30000"
"$CADIUS" ADDFILE "$WORK/data.po" /DATA "$WORK/HELLO#B30000" >/dev/null
# Same Finder-navigation timeline as runViaFinder.sh, plus a key
# injection at frame 6000 (well after the demo has launched and is
# waiting in its event loop), and a memory check at frame 8000.
cat > "$WORK/launch.lua" <<'LUA'
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
local nat = manager.machine.natkeyboard
local frame = 0
local idx = 1
local function get_field(port, name)
local p = manager.machine.ioport.ports[port]
if p == nil then return nil end
return p.fields[name]
end
local key_cmd = get_field(":macadb:KEY3", "Command / Open Apple")
local function press(f) if f then f:set_value(1) end end
local function release(f) if f then f:set_value(0) end end
local steps = {
{3300, function() nat:post("D") end},
{3540, function() press(key_cmd) end},
{3546, function() nat:post("o") end},
{3600, function() release(key_cmd) end},
{4200, function() nat:post("H") end},
{4500, function() press(key_cmd) end},
{4506, function() nat:post("o") end},
{4560, function() release(key_cmd) end},
{7000, function() nat:post(" ") end}, -- wake the demo's event loop
{7500, function() nat:post(" ") end}, -- send a few in case GetNextEvent runs in between
{8000, function() nat:post(" ") end},
{9000, function()
print(string.format("MAME-READ 0x70=%02x", mem:read_u8(0x70)))
for a = 0x60, 0x7F do
local v = mem:read_u8(a)
if v ~= 0 and a ~= 0x70 then
print(string.format("MAME-READ 0x%02x=%02x", a, v))
end
end
for a = 0x0F80, 0x0F9F do
local v = mem:read_u8(a)
if v ~= 0 then
print(string.format("MAME-READ 0x%04x=%02x", a, v))
end
end
manager.machine:exit()
end},
}
emu.register_frame_done(function()
frame = frame + 1
while idx <= #steps and frame >= steps[idx][1] do
steps[idx][2]()
idx = idx + 1
end
end)
LUA
OUT=$(timeout 200 mame apple2gs -rompath "$PROJECT_ROOT/tools/mame/roms" \
-window -nothrottle -sound none \
-seconds_to_run 180 -flop3 "$WORK/disk.po" -flop4 "$WORK/data.po" \
-autoboot_script "$WORK/launch.lua" </dev/null 2>&1)
echo "$OUT" | grep "MAME-READ" || true
VAL=$(echo "$OUT" | grep "MAME-READ 0x70=" | tail -1 | sed 's/.*=//')
if [ "$VAL" = "99" ]; then
echo "PASS: $BASE reached end (\$70 = 0x99)"
exit 0
fi
echo "FAIL: $BASE marker at \$70 = 0x$VAL (want 0x99)"
exit 1

View file

@ -148,26 +148,164 @@ servers/CI runners.
### The bank-switch idiom ### The bank-switch idiom
Bank 0 (`$00:0000-$00:FFFF`) has the I/O window at `$C000-$CFFF` #### Background — why this is necessary
that interferes with normal data access. The convention is to
switch the data bank register (DBR) to bank 2 (`$02:0000`) before The 65816 has two registers that select which bank a memory access
doing any data work: goes to:
- **PBR** (Program Bank Register) — selects the bank for instruction
fetches. Set by `jsl long_addr` and `rtl`.
- **DBR** (Data Bank Register) — selects the bank for data accesses
like `lda $5000`, `sta $5000`, etc.
When the IIgs boots, DBR defaults to `$00`. Bank `$00` (the same
bank as the language card / IIe-compatibility area) contains the
**I/O window at `$C000-$CFFF`**. Any data access to addresses in
that range goes to the soft-switches and slot ROMs, NOT to RAM.
This is the same I/O hole the Apple IIe has, inherited by the IIgs
for backward compatibility.
Concretely: if your DBR is `$00` and you write to address `$C100`,
you're poking the slot-1 ROM enable register — definitely not what
you want. Similarly, `$5000` in bank 0 is the language card area
and may or may not be RAM depending on soft-switch state.
Banks `$01`-`$DF` are full 64K RAM banks (`$E0`/`$E1` are aux/main
shadow, `$E0`-`$FF` reserved). To do reliable data work, switch
the DBR to any of these "normal" banks. **`$02`** is conventional
in this codebase because:
1. `$01:0000-$01:FFFF` overlaps the stack page (`$0100-$01FF` in
any bank ends up in the same physical RAM as bank `$00`'s
stack page — confusing).
2. `$02:0000-$02:FFFF` is the first "clean" bank above the
special-purpose banks.
3. The smoke-test convention is to write a result word to
`$02:5000` so `runInMame.sh` can read it back.
If your program needs more than 64 KB of data, switch DBR to
different banks as needed.
#### What the assembly does, line by line
```c ```c
__attribute__((noinline)) void switchToBank2(void) { __attribute__((noinline)) void switchToBank2(void) {
__asm__ volatile ( __asm__ volatile (
"sep #0x20\n" // 8-bit accumulator "sep #0x20\n" // (1) Switch A to 8-bit
".byte 0xa9,0x02\n" // lda #2 (force as bytes — llvm-mc bug) ".byte 0xa9,0x02\n" // (2) lda #2 (8-bit immediate)
"pha\n" "pha\n" // (3) Push A onto stack (1 byte)
"plb\n" // DBR = 2 "plb\n" // (4) Pop into DBR (1 byte from stack)
"rep #0x20\n" // back to 16-bit "rep #0x20\n" // (5) Restore A to 16-bit
); );
} }
``` ```
After `switchToBank2()`, your data lives at `$02:0000` upward. 1. **`sep #0x20`** — sets the `M` bit in the status register `P`.
The `runInMame.sh` `--check 0x025000=...` address is `$02:5000` `M=1` makes A behave as 8-bit (and immediate operands become
— accessible via a normal store in bank 2. 1 byte). We need this so the next `lda #2` pushes 1 byte
(matching what `plb` expects to pop). Calling-convention
prologues always run in M=0 (16-bit), so this `sep` is
required.
2. **`.byte 0xa9,0x02`** — raw bytes for `lda #$02`. We hand-encode
because llvm-mc can't yet emit an 8-bit immediate `lda #$02`
that knows it's 1 byte; the assembler keeps treating it as
16-bit. `0xa9` is the LDA-immediate opcode; `0x02` is the
1-byte operand. Result: A = `$02` (8-bit).
3. **`pha`** — pushes A. In M=1 mode, PHA pushes exactly 1 byte
(the low half of A). Stack now has `$02` on top.
4. **`plb`** — pops 1 byte from the stack and stores it in DBR.
DBR is now `$02`. All subsequent data accesses go to bank 2.
5. **`rep #0x20`** — clears the `M` bit. A returns to 16-bit mode,
matching the calling-convention contract for the rest of the
function.
The DBR change persists across function returns. Once
`switchToBank2()` returns, all data reads/writes in your program
target bank 2 — until you switch DBR again.
#### When you need it
You need to switch DBR whenever you want to access data at an
absolute address `$XXXX` and need it to land in a specific bank.
Common cases:
- **MMIO from the test harness**`*(volatile uint16 *)0x5000 = x;`
Without DBR=2, this would go to bank 0's `$5000` (which is in
the language card area). With DBR=2, it goes to `$02:5000`
where `runInMame.sh --check 0x025000=...` reads from.
- **Anything in `$C000-$CFFF`** — bank 0 has soft-switches here.
Bank 2 has plain RAM.
- **Global arrays declared at link-time at fixed addresses**
the linker may place them in bank 2 BSS (`--bss-base 0x020000`).
Your DBR must match.
You DON'T need DBR=2 for:
- **Local variables on the stack** — the stack is always
bank-relative-to-DBR-ignored; `lda $4,s` reads from the stack
page regardless of DBR.
- **Direct-page accesses**`lda $D0` reads from `$00:00D0`
(always bank 0). DP is anchored to bank 0.
- **Indirect-long pointers via `[dp],y`** — these include their
own bank byte and ignore DBR.
- **Function calls**`jsl` uses PBR + a long destination
address. PBR is updated automatically.
#### Other ways to access non-bank-0 data
If you only need to write to a single non-bank-0 address, you can
emit the store as `STA_Long` (24-bit absolute) which encodes the
bank inline:
```c
*(volatile unsigned short *)0x025000 = 42; // becomes sta $025000
```
The W65816 backend recognizes `const-int pointer + integer offset`
and lowers to `sta long` if the address has a bank byte. No
`switchToBank2()` needed.
For frequent data work in a bank, switching DBR once and using
plain `sta $5000` (2 bytes) is smaller and faster than `sta $025000`
(4 bytes) per access.
#### Caveats
- **Save/restore is your problem.** `switchToBank2()` never
restores DBR. If your caller expected DBR=0, you've broken its
expectation. For long-running programs, that's usually fine
(you just set DBR=2 once and stay there). For toolbox calls, GS/OS
might assume DBR=0 — check the call's documentation.
- **The stack is in bank 0 regardless.** Don't try to put the
stack elsewhere; the 65816's stack-relative addressing modes
ignore DBR.
- **In M=1 mode, INTERRUPTS may behave differently.** The `sep`
affects A's width but not the bank-switching machinery itself.
Keep the sep/rep window short.
- **PBR vs DBR** are independent. Code execution stays where it
was; only data accesses change.
#### How `runInMame.sh --check 0x025000=...` works
The check address `0x025000` is a 24-bit address: bank `$02`,
offset `$5000`. The MAME Lua runner reads this byte (and the next
byte if you specify a 2-byte value) directly from physical RAM,
bypassing DBR entirely. So the convention is:
1. Your program switches DBR to bank 2.
2. Your program writes its result to `*(volatile X *)0x5000`,
which becomes `sta $5000` — landing in bank 2 because of DBR.
3. MAME reads bank 2's `$5000` via the absolute 24-bit address.
4. The runner compares to your expected value.
If you forget `switchToBank2()`, your store goes to the language
card area (bank 0's `$5000`), MAME's check reads bank 2's
unchanged `$5000` (likely `$00` or whatever was there), and the
test fails.
## Examples ## Examples

View file

@ -52,7 +52,9 @@ cc "$SRC/math.c"
cc "$SRC/softFloat.c" cc "$SRC/softFloat.c"
cc "$SRC/libcxxabi.c" cc "$SRC/libcxxabi.c"
cc "$SRC/libcxxabiSjlj.c" cc "$SRC/libcxxabiSjlj.c"
cc "$SRC/desktop.c"
asm "$SRC/iigsGsos.s" asm "$SRC/iigsGsos.s"
asm "$SRC/iigsToolbox.s"
# softDouble.c builds at -O2. dpack stays noinline (basic regalloc # softDouble.c builds at -O2. dpack stays noinline (basic regalloc
# overflows when dpack inlines into __adddf3/__muldf3). dclass MUST # overflows when dpack inlines into __adddf3/__muldf3). dclass MUST
# stay inline (its pointer-arg writes from a noinline boundary would # stay inline (its pointer-arg writes from a noinline boundary would

View file

@ -0,0 +1,56 @@
// iigs/desktop.h - Full Window Manager desktop startup helper.
//
// Equivalent to ORCA-C's `startdesk` library function: brings up the
// stack of toolsets needed to open titled windows, draw menus,
// dispatch events, etc. Use this before `NewWindow` for any titled-
// window application. See demos/orcaFrame.c for a minimal usage
// example.
//
// On success, `desktopUserId()` returns the Memory Manager userID
// assigned to this application. Pass it to other toolsets that need
// a userID (e.g. ID arg to `DisposeAll`).
//
// startdesk() takes a screen-width hint:
// 320 - SHR 320 mode (16 colors)
// 640 - SHR 640 mode (4 colors)
// This is passed to QDStartUp's masterSCB and to EMStartUp's
// xMax/yMax. Other dimensions are derived.
#ifndef IIGS_DESKTOP_H
#define IIGS_DESKTOP_H
#ifdef __cplusplus
extern "C" {
#endif
// Returns the user-ID assigned by MMStartUp. Pass to enddesk().
unsigned short startdesk(unsigned short screenWidth);
// Tears down the desktop environment in reverse-startup order.
void enddesk(unsigned short userId);
// Read-only accessor — same value startdesk() returned.
unsigned short desktopUserId(void);
// Read-only accessor — base of the per-toolset 0x700-byte DP block
// startdesk() allocated. Slot $300 (256 bytes) is reserved for the
// Menu Manager: pass `desktopDpBase() + 0x300` to MenuStartUp.
unsigned short desktopDpBase(void);
// Paint a clean Finder-style backdrop directly into SHR: white menu
// bar (rows 0..12), 1-pixel black separator (row 13), white desktop
// (rows 14..199). Bypasses the WM's dithered desktop fill (which
// MAME's NTSC chroma simulator renders as colored noise). Call
// AFTER startdesk() and BEFORE NewWindow.
void paintDesktopBackdrop(void);
// Paint menu bar titles via QD's DrawString. Each entry is a
// pascal-string pointer (byte length + chars). Use as a manual
// substitute for DrawMenuBar(), which hangs in our environment.
void paintMenuBarTitles(const unsigned char *const *pascalTitles, unsigned short count);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -71,6 +71,8 @@ __start:
phk phk
pla ; A's low byte = current PBR pla ; A's low byte = current PBR
sta 0xbe ; persistent data bank sta 0xbe ; persistent data bank
stz 0xbf ; pad: `lda 0xbe` in 16-bit M loads $00PBR
; — used by codegen for &symbol bank halves
rep #0x20 rep #0x20
; Zero BSS. Up to 4 segments — linker emits __bss_seg{0..3}_lo16 ; Zero BSS. Up to 4 segments — linker emits __bss_seg{0..3}_lo16
@ -202,6 +204,23 @@ __start:
; sequence in a controlled context. time()/clock() check an ; sequence in a controlled context. time()/clock() check an
; in-process flag and return 0 if init hasn't been done. ; in-process flag and return 0 if init hasn't been done.
; Set DBR to the BSS bank before calling main. Without this, the
; user has to manually switch the data bank register (with a
; `pha;plb` inline-asm idiom) before doing absolute data
; accesses. Calypsi's "small data model" assumes DBR is
; pre-set; we now follow the same convention.
;
; Linker emits __bss_seg0_bank as the bank byte of the first
; BSS segment (typically 2 with the default --bss-base 0x020000).
; Programs that need bank-0 access (e.g., for $C0xx soft
; switches) can use STA_Long or temporarily switch DBR back.
sep #0x20
.byte 0xA9 ; lda #imm8 (1 byte) — llvm-mc can't
.byte __bss_seg0_bank ; reliably encode this with a symbol;
pha ; spell it out to keep the bytes right.
plb
rep #0x20
; Call main. Standard W65816 ABI: i16 first arg in A; we pass ; Call main. Standard W65816 ABI: i16 first arg in A; we pass
; nothing. After return, A holds the exit code. ; nothing. After return, A holds the exit code.
jsl main jsl main

View file

@ -33,6 +33,18 @@ __start:
; wrong bank without this. PHK + PLB copies PBR into DBR. ; wrong bank without this. PHK + PLB copies PBR into DBR.
phk phk
plb plb
; Diagnostic: stash a marker at $00:007F via `sta long` (bank-
; explicit, immune to DBR uncertainty) immediately on entry.
; Runtime probes use this to detect whether the Loader actually
; reached our code or silently rejected the OMF earlier.
; The assembler doesn't track SEP/REP state, so the LDA #imm
; needs explicit `.byte` form: the standard `lda #$7F` would
; assemble as 3 bytes (16-bit imm) and the trailing $00 would
; execute as BRK at runtime once M=8.
sep #0x20
.byte 0xa9, 0x7f ; lda #$7F (8-bit imm)
.byte 0x8f, 0x7f, 0x00, 0x00 ; sta long $00:007F
rep #0x20
; Set DP=0. The C compiler assumes DP=0 for all `sta dp` and ; Set DP=0. The C compiler assumes DP=0 for all `sta dp` and
; `[dp],y`-style accesses; GS/OS hands us a Memory-Manager- ; `[dp],y`-style accesses; GS/OS hands us a Memory-Manager-
@ -51,6 +63,18 @@ __start:
phk phk
pla pla
sta 0xbe sta 0xbe
stz 0xbf ; pad byte so `lda 0xbe` in 16-bit M reads $00PBR
; (codegen uses this as the bank-half of `&symbol`
; 32-bit pointers — see W65816AsmPrinter
; LDAi16imm_bank expansion)
rep #0x20
; --- Diagnostic markers between crt0 phases. Bank-explicit
; `sta long` to $00:007E so they're visible from a host probe
; regardless of DBR/PBR.
sep #0x20
.byte 0xa9, 0x7e ; lda #$7E
.byte 0x8f, 0x7e, 0x00, 0x00 ; sta long $00:007E (post-DP)
rep #0x20 rep #0x20
; BSS zero-init. With DBR=our bank, `stz abs,X` writes to ; BSS zero-init. With DBR=our bank, `stz abs,X` writes to
@ -67,6 +91,10 @@ __start:
inx inx
bra .Lbss_loop bra .Lbss_loop
.Lbss_done: .Lbss_done:
sep #0x20
.byte 0xa9, 0x7d ; lda #$7D
.byte 0x8f, 0x7d, 0x00, 0x00 ; sta long $00:007D (post-BSS)
rep #0x20
; Walk .init_array (C++ ctors). ; Walk .init_array (C++ ctors).
; ;
@ -99,6 +127,12 @@ __start:
bra .Linit_loop bra .Linit_loop
.Linit_done: .Linit_done:
; Marker: about to JSL main.
sep #0x20
.byte 0xa9, 0x7c ; lda #$7C
.byte 0x8f, 0x7c, 0x00, 0x00 ; sta long $00:007C (about to call main)
rep #0x20
; Call main. Standard W65816 C ABI: arg0 in A; we pass none. ; Call main. Standard W65816 C ABI: arg0 in A; we pass none.
rep #0x30 rep #0x30
jsl main jsl main

168
runtime/src/desktop.c Normal file
View file

@ -0,0 +1,168 @@
// desktop.c - startdesk()/enddesk() — ORCA-C-style minimal desktop init.
//
// Brings up the toolset chain a full desktop app needs:
// Memory + DP allocation, MiscTools, QD, EM, Scheduler, Sound, ADB,
// SANE, IntMath, Text, Window, Font, Control, LineEdit, Dialog,
// Scrap. Menu Manager startup is omitted — MenuStartUp hangs in
// the current environment (likely a tool-init-order dependency we
// haven't pinned down). Demos that need a visible menu bar paint
// it manually into SHR rows 0..12.
//
// Palette: all 16 palettes set to (black, white, black, white). In
// 640 mode that maps to clean Finder-style B/W instead of NTSC chroma
// noise for the dithered patterns the WM uses.
#include "iigs/desktop.h"
#include "iigs/toolbox.h"
static unsigned short gUserId = 0;
static void *gDpHandle = (void *)0;
static unsigned short gDpBase = 0;
static unsigned short blockAddrLo(void *handle) {
return (unsigned short)(unsigned long)*(void **)handle;
}
unsigned short startdesk(unsigned short screenWidth) {
gUserId = MMStartUp();
// QD needs 512 bytes ($200) — its own DP at +$000 plus the cursor
// manager's DP at +$100 (InitCursor does `tdc; clc; adc #$100;
// tcd` to find its globals). ROM Source Code/Bank FE/cursor.asm
// confirms cursor uses QD's DP+$100. Layout below allocates 0x800
// total so QD/Cursor have $000..$1FF, then EM/FM/Menu/Ctl/LE/Dlg
// each get $100.
// $000 QD | $100 Cursor | $200 EM | $300 FM | $400 Menu |
// $500 Ctl | $600 LE | $700 Dialog.
gDpHandle = NewHandle(0x800UL, gUserId, 0xC015, (void *)0);
unsigned short dp = blockAddrLo(gDpHandle);
gDpBase = dp;
MTStartUp();
unsigned short masterSCB = (screenWidth == 640) ? 0x90 : 0x10;
QDStartUp(dp, masterSCB, screenWidth, gUserId);
EMStartUp((unsigned short)(dp + 0x200), 20, 0, 0,
(short)(screenWidth - 1), 199, gUserId);
SchStartUp();
SoundStartUp(gUserId);
ADBStartUp();
SANEStartUp(gUserId);
IMStartUp();
TextStartUp();
LoadOneTool(0x0E, 0x0301);
WindStartUp(gUserId);
LoadOneTool(0x1B, 0x0301);
FMStartUp(gUserId, (unsigned short)(dp + 0x300));
LoadOneTool(0x10, 0x0301);
CtlStartUp(gUserId, (unsigned short)(dp + 0x500));
LoadOneTool(0x14, 0x0301);
LEStartUp(gUserId, (unsigned short)(dp + 0x600));
LoadOneTool(0x15, 0x0301);
DialogStartUp(gUserId);
LoadOneTool(0x16, 0x0301);
ScrapStartUp();
// InitCursor allocates the cursor save buffer (1024-byte handle
// stored at cursor mgr DP $B4). Without it, the FIRST QD call
// that internally triggers cursor shield/unshield hangs in ROM's
// iUndrawCursor walking through a NULL pointer. This was the
// *real* cause of the "DrawMenuBar hang" investigation —
// DrawMenuBar's _FillRect call shields the cursor, and iUndraw
// loops forever copying garbage from $00:0000+Y into SHR.
// Confirmed via ROM Source Code/Bank FE/cursor.asm — see PC
// $FE:551E during hang matched iUndrawCursor:FinishLoop.
InitCursor();
LoadOneTool(0x0F, 0x0301);
MenuStartUp(gUserId, (unsigned short)(dp + 0x400));
// Force all 16 palettes to a Finder-style B/W spread that works
// in 640 mode. 640 mode rotates through palette quadrants
// (8..11, 12..15, 0..3, 4..7) across pixel positions, so SetForeColor(1)
// only renders solid white if pal[1] == pal[5] == pal[9] == pal[13].
// Even (0,2,4,6,8,10,12,14) → black, odd (1,3,5,7,9,11,13,15) → white.
for (unsigned short p = 0; p < 16; p++) {
volatile unsigned short *pal =
(volatile unsigned short *)(0xE19E00UL + (unsigned long)p * 32UL);
for (unsigned short k = 0; k < 16; k++) {
pal[k] = (k & 1) ? 0x0FFF : 0x0000;
}
}
return gUserId;
}
// Paint menu bar text via QD's DrawString. Each title is a
// pascal-counted string (length-prefixed); titles are placed
// left-to-right at y=10, starting at x=4 with kSpacing between
// titles. Use this in place of DrawMenuBar() (which hangs in our
// current toolset env). Caller is responsible for filling the bar
// background first (paintDesktopBackdrop does this).
void paintMenuBarTitles(const unsigned char *const *pascalTitles, unsigned short count) {
SetForeColor(0);
SetBackColor(15);
unsigned short x = 4;
for (unsigned short i = 0; i < count; i++) {
MoveTo((short)x, 10);
const unsigned char *s = pascalTitles[i];
DrawString((void *)s);
x = (unsigned short)(x + (unsigned short)s[0] * 8U + 16U);
}
}
// Paint a Finder-style backdrop directly into SHR: white menu bar
// (rows 0..12), 1-pixel black separator (row 13), white desktop
// (rows 14..199). Bypasses the WM's dithered desktop fill that
// MAME's NTSC chroma simulator renders as colored noise. Useful
// for ORCA-style demos that want the WM's chrome without the
// chroma fringing.
void paintDesktopBackdrop(void) {
__asm__ volatile (
"rep #0x30\n"
"ldx #0x0000\n"
"1:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x20, 0x08\n"
"bcc 1b\n"
"2:\n"
".byte 0xa9, 0x00, 0x00\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0xc0, 0x08\n"
"bcc 2b\n"
"3:\n"
".byte 0xa9, 0xff, 0xff\n"
".byte 0x9f, 0x00, 0x20, 0xe1\n"
"inx\n inx\n"
".byte 0xe0, 0x00, 0x7d\n"
"bcc 3b\n"
::: "a", "x", "memory");
}
void enddesk(unsigned short userId) {
WindShutDown();
FMShutDown();
TextShutDown();
ADBShutDown();
SchShutDown();
EMShutDown();
QDShutDown();
DisposeHandle(gDpHandle);
MMShutDown(userId);
}
unsigned short desktopUserId(void) {
return gUserId;
}
unsigned short desktopDpBase(void) {
return gDpBase;
}

View file

@ -1,5 +1,12 @@
; iigsGsos.s — GS/OS class-1 dispatch wrappers. ; iigsGsos.s — GS/OS class-1 dispatch wrappers.
; ;
; PUSH ORDER MATTERS. Earlier versions used PHA-then-PEA-0, which put
; the bank byte at offset position in the stack layout - broken under
; real GS/OS 6.0.2 (observed as a JSL $E100A8 hang). The correct order
; matches ORCA-C's PushLong macro: PEA high FIRST, then PHA low. After
; PEA 0 + PHA, the 4 bytes at (S+1..S+4) are (off_lo, off_hi, bank, pad)
; in little-endian order, which is what the dispatcher reads as a LONG.
;
; Each wrapper takes a 16-bit pointer to a class-1 parm block in A ; Each wrapper takes a 16-bit pointer to a class-1 parm block in A
; (the C ABI). The GS/OS convention is: ; (the C ABI). The GS/OS convention is:
; PHA / PEA 0 ; push 32-bit parm-block pointer ; PHA / PEA 0 ; push 32-bit parm-block pointer
@ -36,8 +43,8 @@
.globl gsosGetMark .globl gsosGetMark
gsosOpen: gsosOpen:
pha
pea 0 pea 0
pha
ldx #0x2010 ldx #0x2010
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 ; stash status (A) in DP scratch sta 0xe4 ; stash status (A) in DP scratch
@ -49,8 +56,8 @@ gsosOpen:
rtl rtl
gsosRead: gsosRead:
pha
pea 0 pea 0
pha
ldx #0x2012 ldx #0x2012
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 sta 0xe4
@ -62,8 +69,8 @@ gsosRead:
rtl rtl
gsosWrite: gsosWrite:
pha
pea 0 pea 0
pha
ldx #0x2013 ldx #0x2013
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 sta 0xe4
@ -75,8 +82,8 @@ gsosWrite:
rtl rtl
gsosClose: gsosClose:
pha
pea 0 pea 0
pha
ldx #0x2014 ldx #0x2014
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 sta 0xe4
@ -88,8 +95,8 @@ gsosClose:
rtl rtl
gsosGetEOF: gsosGetEOF:
pha
pea 0 pea 0
pha
ldx #0x2019 ldx #0x2019
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 sta 0xe4
@ -101,8 +108,8 @@ gsosGetEOF:
rtl rtl
gsosSetEOF: gsosSetEOF:
pha
pea 0 pea 0
pha
ldx #0x2018 ldx #0x2018
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 sta 0xe4
@ -114,8 +121,8 @@ gsosSetEOF:
rtl rtl
gsosSetMark: gsosSetMark:
pha
pea 0 pea 0
pha
ldx #0x2016 ldx #0x2016
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 sta 0xe4
@ -127,8 +134,8 @@ gsosSetMark:
rtl rtl
gsosGetMark: gsosGetMark:
pha
pea 0 pea 0
pha
ldx #0x2017 ldx #0x2017
jsl 0xe100a8 jsl 0xe100a8
sta 0xe4 sta 0xe4

View file

@ -1,11 +1,14 @@
; Minimal GS/OS dispatcher stub at $E100A8. Native, M=0, X=0. ; Minimal GS/OS dispatcher stub at $E100A8. Native, M=0, X=0.
; Stack at entry: S+1=PCL, S+2=PCH, S+3=PBR, S+4..5=bank (=0), ; Stack at entry (after caller's PEA 0 + PHA + JSL):
; S+9=parm ptr low 16, S+10=high. We only use the low 16 (bank-0 ; S+1=PCL, S+2=PCH, S+3=PBR, S+4=ptr_lo, S+5=ptr_hi,
; parm blocks). Writes $42 to *parm and returns A=0. ; S+6=bank (=0), S+7=pad (=0).
; After our PHP + PHA: parm pointer is at (S+7, S+8); bank at (S+9).
; We only use the low 16 (bank-0 parm blocks). Writes $42 to *parm
; and returns A=0.
.text .text
php ; save P php ; save P
pha ; save A (16-bit) pha ; save A (16-bit)
lda 9, s ; A = parm ptr 16 lda 7, s ; A = parm ptr offset (16-bit)
sta 0xe4 ; DP $E4..$E5 sta 0xe4 ; DP $E4..$E5
ldy #0 ; X=0 here, so 3-byte encoding ldy #0 ; X=0 here, so 3-byte encoding
sep #0x20 ; M=8 for the 1-byte store sep #0x20 ; M=8 for the 1-byte store

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,7 @@ typedef struct {
u16 pCount; u16 pCount;
u16 refNum; u16 refNum;
void *pathname; void *pathname;
u16 requestAccess;
} __GsosOpenParm; } __GsosOpenParm;
typedef struct { typedef struct {
u16 pCount; u16 pCount;
@ -229,13 +230,27 @@ int puts(const char *s) {
return 0; return 0;
} }
// ---- input stubs ---- // ---- input ----
// //
// getchar reads from the keyboard; real input would route through // getchar polls the IIgs hardware keyboard register at $C000. Bit 7
// the IIgs Event Manager. Returns -1 (EOF) for now. fgetc/fgets/ // is the "key ready" strobe; bits 0..6 are the ASCII code. Reading
// ungetc are defined further down alongside the FILE-table-backed // $C010 clears the strobe so the next keypress can be detected. This
// fopen/fread/etc. // blocks until a key is pressed and returns the (7-bit) ASCII value.
int getchar(void) { return -1; /* EOF */ } // It works in any execution context (raw boot, ProDOS-16, GS/OS app)
// because $C000 is hardware I/O, not toolbox-mediated.
//
// Callers wanting non-blocking input or Event Manager integration
// should call ReadCh/GetNextEvent directly via iigs/toolbox.h.
int getchar(void) {
volatile unsigned char *kbd = (volatile unsigned char *)0xC000;
volatile unsigned char *strb = (volatile unsigned char *)0xC010;
while (((*kbd) & 0x80) == 0) {
// Spin until a key is ready. No yield — single-threaded.
}
int c = (*kbd) & 0x7F;
(void)*strb; // clear strobe
return c;
}
// ---- minimal printf ---- // ---- minimal printf ----
@ -1288,7 +1303,18 @@ FILE *fopen(const char *path, const char *mode) {
// → NULL. // → NULL.
if (!__gsosAvailable()) return (FILE *)0; if (!__gsosAvailable()) return (FILE *)0;
if (__buildGSString(path) < 0) return (FILE *)0; if (__buildGSString(path) < 0) return (FILE *)0;
__GsosOpenParm op = { 2, 0, &__gsosPathBuf }; // pCount=3 covers refNum + pathname + requestAccess. GS/OS 6.0.2
// Open ($2010) requires requestAccess to be non-zero for any actual
// open; passing only pCount=2 (refNum + pathname) leaves the access
// word indeterminate and the Open silently fails with a "bad access"
// status. requestAccess values: $0001 = read, $0002 = write,
// $0003 = read+write. We pick read or read+write based on the
// mode string. The remaining optional params (resourceNumber,
// accessMode, fileType, auxType, storageType, createDate, modDate,
// optionList) are left out — GS/OS treats their absence as
// "default values".
u16 access = (u16)(wantWrite ? (wantRead ? 3 : 2) : 1);
__GsosOpenParm op = { 3, 0, &__gsosPathBuf, access };
if (gsosOpen(&op) != 0) return (FILE *)0; if (gsosOpen(&op) != 0) return (FILE *)0;
f->kind = FILE_KIND_GSOS; f->kind = FILE_KIND_GSOS;

View file

@ -95,7 +95,41 @@ __mulhi3:
; -------------------------------------------------------------------- ; --------------------------------------------------------------------
.globl __umulhisi3 .globl __umulhisi3
__umulhisi3: __umulhisi3:
sta 0xe0 ; multiplier in $e0/$e1 ; Fast path: if both args fit in 8 bits, use a quarter-square
; table for 8x8 → 16 (result hi half is always 0). Identity:
; a*b = T[a+b] - T[|a-b|] where T[k] = floor(k²/4)
; 511-entry, 2-byte table = 1022 bytes ROM. Fast path is ~55
; cyc vs ~150 cyc for the shift-and-add fallback at i ~ 50.
; Hot in `i*i` patterns where i is a loop counter ≤ 255.
sta 0xe0 ; save arg0
ora 0x4, s ; OR with arg1
and #0xff00 ; isolate hi bytes
bne .Lumulhisi_slow ; if either hi byte nonzero, fallback
; Both args fit in 8 bits — quarter-square path.
lda 0xe0 ; arg0
clc
adc 0x4, s ; A = a + b
asl a ; A = 2*(a+b) — word index
tax
lda __umulhisi3_qsq, x ; T[a+b]
sta 0xe2 ; stash
lda 0xe0 ; arg0
sec
sbc 0x4, s ; A = a - b
bpl .Lumulhisi_qsq_pos
; A negative; negate to get |a-b|.
eor #0xffff
inc a
.Lumulhisi_qsq_pos:
asl a ; A = 2*|a-b|
tax
lda 0xe2 ; T[a+b]
sec
sbc __umulhisi3_qsq, x ; T[a+b] - T[|a-b|]
ldx #0 ; result hi half = 0
rtl
.Lumulhisi_slow:
; Multiplier already at $e0 from the fast-path check above.
lda 0x4, s lda 0x4, s
sta 0xe2 ; multiplicand lo in $e2/$e3 sta 0xe2 ; multiplicand lo in $e2/$e3
stz 0xe4 ; multiplicand hi (initially 0) in $e4/$e5 stz 0xe4 ; multiplicand hi (initially 0) in $e4/$e5
@ -369,6 +403,29 @@ __mulsi3:
; Clear running product at $e8/$ea. ; Clear running product at $e8/$ea.
stz 0xe8 stz 0xe8
stz 0xea stz 0xea
; Asymmetric-size swap: the loop iterates based on the multiplier's
; bit width. If a is large (a_hi != 0) but b is small (b_hi == 0),
; swap so the small one becomes the multiplier — the early-exit
; check (lda 0xe0; beq done) then fires sooner. Saves a lot for
; djb2-style `h * 33` patterns where h grows but the constant
; multiplier is small. Cost: ~12 cyc unconditional check; benefit:
; ~10 cyc per saved iter × ~10 iters = 100 cyc.
lda 0xe2
beq .Lmulsi_no_swap ; a_hi == 0, no need to swap (or already covered by u16 path below)
lda 0xe6
bne .Lmulsi_no_swap ; b_hi != 0, both large, no benefit
; Swap (a_lo, a_hi) ↔ (b_lo, b_hi). Both are at DP; XOR-swap or
; load/store; we use load/store with A scratch since the values are
; 16 bits each.
lda 0xe0
ldx 0xe4
stx 0xe0
sta 0xe4
lda 0xe2
ldx 0xe6
stx 0xe2
sta 0xe6
.Lmulsi_no_swap:
; Fast path: if multiplier's high half ($e2) is 0, we only ; Fast path: if multiplier's high half ($e2) is 0, we only
; need 16 loop iterations AND we can drop the multiplier-hi ; need 16 loop iterations AND we can drop the multiplier-hi
; shift step entirely (lsr $e2 + bcc + ora #$8000) — that step ; shift step entirely (lsr $e2 + bcc + ora #$8000) — that step
@ -380,6 +437,41 @@ __mulsi3:
; iteration. ; iteration.
lda 0xe2 lda 0xe2
bne .Lmulsi_full bne .Lmulsi_full
; Quarter-square fast path: when BOTH args fit in 8 bits (e2==0
; already verified, e6==0, e0<256, e4<256), use the same T[k]=k^2/4
; table that __umulhisi3 uses to compute a*b = T[a+b] - T[|a-b|]
; in ~50 cyc vs the u16 loop's ~150-250 cyc for small multipliers.
; Common when dotProduct etc. sign-extend small i16 values to i32.
lda 0xe6
bne .Lmulsi_u16_entry
lda 0xe0
ora 0xe4
and #0xff00
bne .Lmulsi_u16_entry
; T[a+b] -> $e8 (product lo).
lda 0xe0
clc
adc 0xe4
asl a
tax
lda __umulhisi3_qsq, x
sta 0xe8
; |a-b| as word index.
lda 0xe0
sec
sbc 0xe4
bpl .Lmulsi_qsq_pos
eor #0xffff
inc a
.Lmulsi_qsq_pos:
asl a
tax
lda 0xe8
sec
sbc __umulhisi3_qsq, x
ldx #0
rtl
.Lmulsi_u16_entry:
ldy #0x10 ldy #0x10
.Lmulsi_u16_loop: .Lmulsi_u16_loop:
; Shift multiplier right; bit-out tested for add. Bottom of loop ; Shift multiplier right; bit-out tested for add. Bottom of loop
@ -466,14 +558,14 @@ __ashlsi3:
sta 0xe0 ; lo sta 0xe0 ; lo
stx 0xe2 ; hi stx 0xe2 ; hi
lda 0x4, s lda 0x4, s
tay ; count -> Y tay ; count -> Y; sets Z if 0
beq .Lashlsi_done ; count==0: skip loop
.Lashlsi_loop: .Lashlsi_loop:
cpy #0x0 ; Per-bit: 7+7+2+3 = 19 cyc (was 25 with cpy/beq/bra).
beq .Lashlsi_done
asl 0xe0 asl 0xe0
rol 0xe2 rol 0xe2
dey dey
bra .Lashlsi_loop bne .Lashlsi_loop
.Lashlsi_done: .Lashlsi_done:
ldx 0xe2 ldx 0xe2
lda 0xe0 lda 0xe0
@ -489,13 +581,12 @@ __lshrsi3:
stx 0xe2 stx 0xe2
lda 0x4, s lda 0x4, s
tay tay
.Llshrsi_loop:
cpy #0x0
beq .Llshrsi_done beq .Llshrsi_done
.Llshrsi_loop:
lsr 0xe2 lsr 0xe2
ror 0xe0 ror 0xe0
dey dey
bra .Llshrsi_loop bne .Llshrsi_loop
.Llshrsi_done: .Llshrsi_done:
ldx 0xe2 ldx 0xe2
lda 0xe0 lda 0xe0
@ -512,9 +603,8 @@ __ashrsi3:
stx 0xe2 stx 0xe2
lda 0x4, s lda 0x4, s
tay tay
.Lashrsi_loop:
cpy #0x0
beq .Lashrsi_done beq .Lashrsi_done
.Lashrsi_loop:
; CMP #$8000 sets C iff the unsigned value >= 0x8000, i.e. bit 15 ; CMP #$8000 sets C iff the unsigned value >= 0x8000, i.e. bit 15
; is set — exactly the sign bit. ; is set — exactly the sign bit.
lda 0xe2 lda 0xe2
@ -522,7 +612,7 @@ __ashrsi3:
ror 0xe2 ror 0xe2
ror 0xe0 ror 0xe0
dey dey
bra .Lashrsi_loop bne .Lashrsi_loop
.Lashrsi_done: .Lashrsi_done:
ldx 0xe2 ldx 0xe2
lda 0xe0 lda 0xe0
@ -1279,3 +1369,75 @@ longjmp:
lda #1 lda #1
.Llj_done: .Llj_done:
rtl rtl
; --------------------------------------------------------------------
; __umulhisi3_qsq: quarter-square lookup table.
; T[k] = floor(k² / 4) for k ∈ [0, 510]. Used by __umulhisi3's fast
; 8x8 path: a*b = T[a+b] - T[|a-b|]. 511 entries × 2 bytes = 1022 B.
; --------------------------------------------------------------------
__umulhisi3_qsq:
.short 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0006, 0x0009, 0x000c
.short 0x0010, 0x0014, 0x0019, 0x001e, 0x0024, 0x002a, 0x0031, 0x0038
.short 0x0040, 0x0048, 0x0051, 0x005a, 0x0064, 0x006e, 0x0079, 0x0084
.short 0x0090, 0x009c, 0x00a9, 0x00b6, 0x00c4, 0x00d2, 0x00e1, 0x00f0
.short 0x0100, 0x0110, 0x0121, 0x0132, 0x0144, 0x0156, 0x0169, 0x017c
.short 0x0190, 0x01a4, 0x01b9, 0x01ce, 0x01e4, 0x01fa, 0x0211, 0x0228
.short 0x0240, 0x0258, 0x0271, 0x028a, 0x02a4, 0x02be, 0x02d9, 0x02f4
.short 0x0310, 0x032c, 0x0349, 0x0366, 0x0384, 0x03a2, 0x03c1, 0x03e0
.short 0x0400, 0x0420, 0x0441, 0x0462, 0x0484, 0x04a6, 0x04c9, 0x04ec
.short 0x0510, 0x0534, 0x0559, 0x057e, 0x05a4, 0x05ca, 0x05f1, 0x0618
.short 0x0640, 0x0668, 0x0691, 0x06ba, 0x06e4, 0x070e, 0x0739, 0x0764
.short 0x0790, 0x07bc, 0x07e9, 0x0816, 0x0844, 0x0872, 0x08a1, 0x08d0
.short 0x0900, 0x0930, 0x0961, 0x0992, 0x09c4, 0x09f6, 0x0a29, 0x0a5c
.short 0x0a90, 0x0ac4, 0x0af9, 0x0b2e, 0x0b64, 0x0b9a, 0x0bd1, 0x0c08
.short 0x0c40, 0x0c78, 0x0cb1, 0x0cea, 0x0d24, 0x0d5e, 0x0d99, 0x0dd4
.short 0x0e10, 0x0e4c, 0x0e89, 0x0ec6, 0x0f04, 0x0f42, 0x0f81, 0x0fc0
.short 0x1000, 0x1040, 0x1081, 0x10c2, 0x1104, 0x1146, 0x1189, 0x11cc
.short 0x1210, 0x1254, 0x1299, 0x12de, 0x1324, 0x136a, 0x13b1, 0x13f8
.short 0x1440, 0x1488, 0x14d1, 0x151a, 0x1564, 0x15ae, 0x15f9, 0x1644
.short 0x1690, 0x16dc, 0x1729, 0x1776, 0x17c4, 0x1812, 0x1861, 0x18b0
.short 0x1900, 0x1950, 0x19a1, 0x19f2, 0x1a44, 0x1a96, 0x1ae9, 0x1b3c
.short 0x1b90, 0x1be4, 0x1c39, 0x1c8e, 0x1ce4, 0x1d3a, 0x1d91, 0x1de8
.short 0x1e40, 0x1e98, 0x1ef1, 0x1f4a, 0x1fa4, 0x1ffe, 0x2059, 0x20b4
.short 0x2110, 0x216c, 0x21c9, 0x2226, 0x2284, 0x22e2, 0x2341, 0x23a0
.short 0x2400, 0x2460, 0x24c1, 0x2522, 0x2584, 0x25e6, 0x2649, 0x26ac
.short 0x2710, 0x2774, 0x27d9, 0x283e, 0x28a4, 0x290a, 0x2971, 0x29d8
.short 0x2a40, 0x2aa8, 0x2b11, 0x2b7a, 0x2be4, 0x2c4e, 0x2cb9, 0x2d24
.short 0x2d90, 0x2dfc, 0x2e69, 0x2ed6, 0x2f44, 0x2fb2, 0x3021, 0x3090
.short 0x3100, 0x3170, 0x31e1, 0x3252, 0x32c4, 0x3336, 0x33a9, 0x341c
.short 0x3490, 0x3504, 0x3579, 0x35ee, 0x3664, 0x36da, 0x3751, 0x37c8
.short 0x3840, 0x38b8, 0x3931, 0x39aa, 0x3a24, 0x3a9e, 0x3b19, 0x3b94
.short 0x3c10, 0x3c8c, 0x3d09, 0x3d86, 0x3e04, 0x3e82, 0x3f01, 0x3f80
.short 0x4000, 0x4080, 0x4101, 0x4182, 0x4204, 0x4286, 0x4309, 0x438c
.short 0x4410, 0x4494, 0x4519, 0x459e, 0x4624, 0x46aa, 0x4731, 0x47b8
.short 0x4840, 0x48c8, 0x4951, 0x49da, 0x4a64, 0x4aee, 0x4b79, 0x4c04
.short 0x4c90, 0x4d1c, 0x4da9, 0x4e36, 0x4ec4, 0x4f52, 0x4fe1, 0x5070
.short 0x5100, 0x5190, 0x5221, 0x52b2, 0x5344, 0x53d6, 0x5469, 0x54fc
.short 0x5590, 0x5624, 0x56b9, 0x574e, 0x57e4, 0x587a, 0x5911, 0x59a8
.short 0x5a40, 0x5ad8, 0x5b71, 0x5c0a, 0x5ca4, 0x5d3e, 0x5dd9, 0x5e74
.short 0x5f10, 0x5fac, 0x6049, 0x60e6, 0x6184, 0x6222, 0x62c1, 0x6360
.short 0x6400, 0x64a0, 0x6541, 0x65e2, 0x6684, 0x6726, 0x67c9, 0x686c
.short 0x6910, 0x69b4, 0x6a59, 0x6afe, 0x6ba4, 0x6c4a, 0x6cf1, 0x6d98
.short 0x6e40, 0x6ee8, 0x6f91, 0x703a, 0x70e4, 0x718e, 0x7239, 0x72e4
.short 0x7390, 0x743c, 0x74e9, 0x7596, 0x7644, 0x76f2, 0x77a1, 0x7850
.short 0x7900, 0x79b0, 0x7a61, 0x7b12, 0x7bc4, 0x7c76, 0x7d29, 0x7ddc
.short 0x7e90, 0x7f44, 0x7ff9, 0x80ae, 0x8164, 0x821a, 0x82d1, 0x8388
.short 0x8440, 0x84f8, 0x85b1, 0x866a, 0x8724, 0x87de, 0x8899, 0x8954
.short 0x8a10, 0x8acc, 0x8b89, 0x8c46, 0x8d04, 0x8dc2, 0x8e81, 0x8f40
.short 0x9000, 0x90c0, 0x9181, 0x9242, 0x9304, 0x93c6, 0x9489, 0x954c
.short 0x9610, 0x96d4, 0x9799, 0x985e, 0x9924, 0x99ea, 0x9ab1, 0x9b78
.short 0x9c40, 0x9d08, 0x9dd1, 0x9e9a, 0x9f64, 0xa02e, 0xa0f9, 0xa1c4
.short 0xa290, 0xa35c, 0xa429, 0xa4f6, 0xa5c4, 0xa692, 0xa761, 0xa830
.short 0xa900, 0xa9d0, 0xaaa1, 0xab72, 0xac44, 0xad16, 0xade9, 0xaebc
.short 0xaf90, 0xb064, 0xb139, 0xb20e, 0xb2e4, 0xb3ba, 0xb491, 0xb568
.short 0xb640, 0xb718, 0xb7f1, 0xb8ca, 0xb9a4, 0xba7e, 0xbb59, 0xbc34
.short 0xbd10, 0xbdec, 0xbec9, 0xbfa6, 0xc084, 0xc162, 0xc241, 0xc320
.short 0xc400, 0xc4e0, 0xc5c1, 0xc6a2, 0xc784, 0xc866, 0xc949, 0xca2c
.short 0xcb10, 0xcbf4, 0xccd9, 0xcdbe, 0xcea4, 0xcf8a, 0xd071, 0xd158
.short 0xd240, 0xd328, 0xd411, 0xd4fa, 0xd5e4, 0xd6ce, 0xd7b9, 0xd8a4
.short 0xd990, 0xda7c, 0xdb69, 0xdc56, 0xdd44, 0xde32, 0xdf21, 0xe010
.short 0xe100, 0xe1f0, 0xe2e1, 0xe3d2, 0xe4c4, 0xe5b6, 0xe6a9, 0xe79c
.short 0xe890, 0xe984, 0xea79, 0xeb6e, 0xec64, 0xed5a, 0xee51, 0xef48
.short 0xf040, 0xf138, 0xf231, 0xf32a, 0xf424, 0xf51e, 0xf619, 0xf714
.short 0xf810, 0xf90c, 0xfa09, 0xfb06, 0xfc04, 0xfd02, 0xfe01

Some files were not shown because too many files have changed in this diff Show more