From d95c30e8194e6ca3cf89246733029ccbe5cd1097 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Wed, 20 May 2026 20:14:20 -0500 Subject: [PATCH] Update. --- README.md | 22 +- SESSION_RECOVERY.md | 59 +- STATUS.md | 60 +- benchmarks/dadd.c | 4 + benchmarks/ddiv.c | 4 + benchmarks/dmul.c | 4 + compare/README.md | 14 +- compare/evalAt.calypsi.lst | 2 +- compare/evalAt.ours.s | 200 ++-- compare/mul16to32.calypsi.lst | 2 +- compare/sumSquares.calypsi.lst | 2 +- demos/README.md | 33 +- demos/frame.bin | Bin 5554 -> 5106 bytes demos/frame.c | 201 +++- demos/frame.map | 340 +++--- demos/frame.o | Bin 3328 -> 2904 bytes demos/frame.omf | Bin 37815 -> 37931 bytes demos/frame.reloc | Bin 1228 -> 1348 bytes demos/minicad.bin | Bin 5805 -> 10554 bytes demos/minicad.c | 399 +++++-- demos/minicad.map | 386 ++++--- demos/minicad.o | Bin 4036 -> 11028 bytes demos/minicad.omf | Bin 38187 -> 38870 bytes demos/minicad.reloc | Bin 1732 -> 2824 bytes demos/orcaFrameLike.bin | Bin 4249 -> 0 bytes demos/orcaFrameLike.c | 160 --- demos/orcaFrameLike.map | 183 ---- demos/orcaFrameLike.o | Bin 1416 -> 0 bytes demos/orcaFrameLike.omf | Bin 37605 -> 0 bytes demos/orcaFrameLike.reloc | Bin 868 -> 0 bytes demos/orcaMiniCadLike.bin | Bin 4763 -> 0 bytes demos/orcaMiniCadLike.c | 155 --- demos/orcaMiniCadLike.map | 201 ---- demos/orcaMiniCadLike.o | Bin 2304 -> 0 bytes demos/orcaMiniCadLike.omf | Bin 37835 -> 0 bytes demos/orcaMiniCadLike.reloc | Bin 1132 -> 0 bytes demos/orcaReversiLike.bin | Bin 4249 -> 0 bytes demos/orcaReversiLike.c | 136 --- demos/orcaReversiLike.map | 183 ---- demos/orcaReversiLike.o | Bin 1420 -> 0 bytes demos/orcaReversiLike.omf | Bin 37605 -> 0 bytes demos/orcaReversiLike.reloc | Bin 868 -> 0 bytes demos/qdProbe.bin | Bin 3360 -> 4114 bytes demos/qdProbe.c | 24 +- demos/qdProbe.map | 216 ++-- demos/qdProbe.o | Bin 1484 -> 2308 bytes demos/qdProbe.omf | Bin 37436 -> 37436 bytes demos/qdProbe.reloc | Bin 592 -> 592 bytes demos/reversi.bin | Bin 9225 -> 19505 bytes demos/reversi.c | 993 +++++++++++++----- demos/reversi.map | 448 +++++--- demos/reversi.o | Bin 9516 -> 28976 bytes demos/reversi.omf | Bin 38609 -> 40802 bytes demos/reversi.reloc | Bin 2284 -> 5668 bytes docs/USAGE.md | 32 +- runtime/build.sh | 9 +- runtime/src/libc.c | 50 +- runtime/src/libgcc.s | 13 +- runtime/src/math.c | 8 - runtime/src/qsort.c | 1 - runtime/src/snprintf.c | 48 +- runtime/src/softDouble.c | 58 +- runtime/src/softFloat.c | 2 - runtime/src/strtok.c | 1 - runtime/src/timeExt.c | 2 - screenshots/frame.png | 4 +- screenshots/minicad.png | 4 +- screenshots/orcaFrameLike.png | 3 - screenshots/orcaMiniCadLike.png | 3 - screenshots/orcaReversiLike.png | 3 - screenshots/qdProbe.png | 4 +- screenshots/reversi.png | 4 +- scripts/benchCycles.sh | 27 +- scripts/runInMame.sh | 12 +- scripts/runInMameWithGsosStub.sh | 5 +- scripts/runMultiSeg.sh | 5 +- src/link816/link816.cpp | 9 + .../lib/Target/W65816/W65816ISelLowering.cpp | 60 +- .../lib/Target/W65816/W65816ImgCalleeSave.cpp | 80 +- src/llvm/lib/Target/W65816/W65816InstrInfo.td | 11 + .../lib/Target/W65816/W65816LowerWide32.cpp | 33 +- .../Target/W65816/W65816PromoteFiToImg.cpp | 6 +- .../lib/Target/W65816/W65816StackRelToImg.cpp | 610 ++++++++++- 83 files changed, 3091 insertions(+), 2447 deletions(-) create mode 100644 benchmarks/dadd.c create mode 100644 benchmarks/ddiv.c create mode 100644 benchmarks/dmul.c delete mode 100644 demos/orcaFrameLike.bin delete mode 100644 demos/orcaFrameLike.c delete mode 100644 demos/orcaFrameLike.map delete mode 100644 demos/orcaFrameLike.o delete mode 100644 demos/orcaFrameLike.omf delete mode 100644 demos/orcaFrameLike.reloc delete mode 100644 demos/orcaMiniCadLike.bin delete mode 100644 demos/orcaMiniCadLike.c delete mode 100644 demos/orcaMiniCadLike.map delete mode 100644 demos/orcaMiniCadLike.o delete mode 100644 demos/orcaMiniCadLike.omf delete mode 100644 demos/orcaMiniCadLike.reloc delete mode 100644 demos/orcaReversiLike.bin delete mode 100644 demos/orcaReversiLike.c delete mode 100644 demos/orcaReversiLike.map delete mode 100644 demos/orcaReversiLike.o delete mode 100644 demos/orcaReversiLike.omf delete mode 100644 demos/orcaReversiLike.reloc delete mode 100644 screenshots/orcaFrameLike.png delete mode 100644 screenshots/orcaMiniCadLike.png delete mode 100644 screenshots/orcaReversiLike.png diff --git a/README.md b/README.md index 3e9c5d4..2ef9c86 100644 --- a/README.md +++ b/README.md @@ -71,18 +71,20 @@ docs/ this directory — INSTALL.md, USAGE.md, design notes ## Status -Stable enough to build real programs. Current quality vs commercial -Calypsi 5.16 (lower is better): +Stable enough to build real programs. Static instruction-count +ratio against commercial Calypsi 5.16 (lower is better): -| Benchmark | Our cyc/call | Calypsi cyc/call (approx) | -|---|---|---| -| sumOfSquares(50) | 16709 | ~16000 | -| popcount(0x12345678) | 2864 | ~2500 | -| memcmp(eq, 5) | 989 | ~700 | -| bsearch(arr, 8, 5) | 767 | ~600 | +| Benchmark | Ours (inst) | Calypsi (inst) | Ratio | +|---|---:|---:|---:| +| sumSquares | 26 | 31 | **0.84×** ✓ | +| evalAt | 472 | 254 | 1.86× | +| mul16to32 | 1 | 4 | **0.25×** ✓ | -Static-size for the canonical `sumSquares` benchmark: 37 inst (ours) -vs 31 inst (Calypsi) — **1.19×**. +Per-iteration cycle measurements (via MAME's HBL counter, 2026-05-20): +bsearch 127, dotProduct 144, fib 97, memcmp 113, popcount 93, +strcpy 91, sumOfSquares 126 (cyc/iter at 100 iters); +dadd 1157, ddiv 1261, dmul 1033 (cyc/iter at 10 iters — FP calls +are ~1000+ cyc each). See [STATUS.md](STATUS.md) for full language and runtime feature coverage, and [LLVM_65816_DESIGN.md](LLVM_65816_DESIGN.md) for diff --git a/SESSION_RECOVERY.md b/SESSION_RECOVERY.md index 87bcdac..2f56c84 100644 --- a/SESSION_RECOVERY.md +++ b/SESSION_RECOVERY.md @@ -1,4 +1,4 @@ -# Session Recovery — last updated 2026-05-08 +# Session Recovery — last updated 2026-05-20 Living recovery doc. Update on every meaningful change. If session is lost, read this top-to-bottom + the memory notes referenced inside, then reread @@ -6,11 +6,27 @@ the actual diffs in tree to ground assumptions. ## Headline state -- **Smoke**: 132/132 green (omfEmit `--stack-size` check is the new one). -- **Active config**: ptr32 (`p:32:16`), full IMG0..IMG15 caller-clobber on JSL, basic regalloc at -O1+. -- **Working tree**: 5 modified files (see below); all real fixes pending checkpoint. -- **Branch**: `main`, ahead of `origin/main` by recent checkpoint commits. -- **Bench wins this session**: popcount **8320 → 6888 cyc/call (17%)** from i32 shift inline. DP/Stack `~Direct` segment Loader-validated end-to-end. +- **Smoke**: 148/148 green. Demos 9/9 (helloBeep/helloText/helloWindow/ + orcaFrame/qdProbe/heavyRelocs/frame/reversi/minicad). +- **Active config**: ptr32 (`p:32:16`), full IMG0..IMG15 caller-clobber + on JSL, greedy regalloc at -O1+. +- **Branch**: `main`. +- **vs Calypsi static-inst ratio (2026-05-20)**: + sumSquares **0.84×** (26 vs 31 — we beat), + mul16to32 **0.25×** (1 vs 4 — we beat), + evalAt 1.86× (472 vs 254 — structural floor; ABI overhaul rejected). +- **Cycle benches (2026-05-20)**: + popcount 93, strcpy 91, bsearch 127, memcmp 113, fib 97, + dotProduct 144, sumOfSquares 126 cyc/iter (100 iters); + dadd 1157, ddiv 1261, dmul 1033 cyc/iter (10 iters). +- **Recent session wins (2026-05-20)**: + - 8 always-on peepholes + extended phase 4 in W65816StackRelToImg + (evalAt 498→472, fib -35%, 35 libc fns shrunk) + - __muldi3 32-bit short-circuit (dmul 1605→1033, -36%) + - case-(b) ImgCalleeSave bracket hoist enables phase 4 to elide + TAY/TYA round-trip in synergy + - FP cycle benches added (dadd/dmul/ddiv) with per-bench iter count + - Documented LSR-dp cycle mystery as HBL-counter wrap artifact ## Uncommitted, must keep @@ -337,15 +353,22 @@ in 30 minutes. Recommended. ## Next session candidates (ranked) -1. **Commit the uncommitted fixes.** They've earned it. -2. **u16*u16→u32 multiply path.** sumOfSquares is 982 cyc/iter, - bottlenecked by `__mulsi3` for what's really a 16x16 multiply. - If we add a `__umulhi3` libcall (i16,i16 → i32) and route - `MUL(zext(a), zext(b))` to it, sumOfSquares could ~halve. -3. **`while (x != 0)` for i32 should fold to `lda lo; ora hi; bne`.** - Currently materializes a boolean via SETCC and branches on it. - Combiner hook: `(brcond (setcc i32 x, 0, ne))` → - `(br_cc ne, lo|hi, 0)`. Big win in any i32-iteration loop. -4. **Greedy regalloc retry.** Cheap experiment, potentially big win. -5. **gmtime_r IR investigation.** Find which combine miscompiles - `days >= 365L + (leap?1:0)`. IR-level, not backend. +evalAt at 1.86× vs Calypsi is the structural floor for peephole work +(see `feedback_evalat_structural_gap.md`). Further gains need: + +1. **i64-by-pointer ABI** (rejected this session — diminishing returns). + Pass doubles by ptr instead of value: saves ~120 cyc per evalAt call. + Requires runtime rewrite, OMF compat checks, every double caller + updated. Risk:reward too high for the size of the gain. +2. **__divdf3 / __adddf3 algorithmic improvements**. ddiv 1261 cyc + could drop via Newton-Raphson reciprocal multiplication (a*1/b + instead of bit-by-bit long division). Major rewrite, but our + __muldi3 short-circuit makes the multiplications cheap now. +3. **Higher-resolution cycle timer**. HBL counter is 8-bit and wraps + at ~256 ticks; combining scan-line position + frame counter would + give per-bench resolution better than ±65 cyc. Would unblock + benchmarking sub-loop changes (e.g., the LSR-dp shift form). +4. **More peepholes from the audit**. Phase 4 STA_StackRel extension + landed but doesn't fire in current libc (frame sizes too large). + If callers shrink frames via better SSM, more functions become + eligible. diff --git a/STATUS.md b/STATUS.md index 2672198..2505bac 100644 --- a/STATUS.md +++ b/STATUS.md @@ -217,7 +217,7 @@ which runs correctly under MAME (apple2gs). image addresses. - `runtime/build.sh` builds crt0, libc, soft-float, soft-double, libgcc into linkable objects. -- `scripts/smokeTest.sh` runs 132 end-to-end checks at -O2: +- `scripts/smokeTest.sh` runs 148 end-to-end checks at -O2: scalar ops, control flow, calling conventions, MAME execution regressions, link816 bss-base safety + weak-symbol resolution + heap_end-vs-heap_start sanity, iigs/toolbox.h compile + link, @@ -244,23 +244,25 @@ which runs correctly under MAME (apple2gs). + dispatch + chained collisions over fprintf-to-mfs), scripts/bench.sh size-vs-Calypsi harness. 100% pass. -- `scripts/benchCyclesPrecise.sh` measures per-call cycle counts - via MAME's emulated time counter. Eight benchmarks under - `benchmarks/`. Current numbers (after W65816StackSlotMerge): - popcount 2864, bsearch 767, memcmp 989, strcpy 2216, - dotProduct 2131, fib(10) 12617, sumOfSquares 16709. Speed is - the optimization priority, not size. +- `scripts/benchCycles.sh` measures per-iteration cycle counts via + MAME's emulated HBL counter. Eleven benchmarks under + `benchmarks/` (eight int + three FP). Current numbers + (2026-05-20): + bsearch 127, crc32 <65, dotProduct 144, fib 97, memcmp 113, + popcount 93, strcpy 91, sumOfSquares 126 cyc/iter (100 iters); + dadd 1157, ddiv 1261, dmul 1033 cyc/iter (10 iters; FP benches + use fewer iters since each call is ~1000+ cyc). Speed is the + optimization priority, not size. - `compare/` holds three side-by-side C tests with our asm and Calypsi's listing for static-size comparison: `sumSquares`/`evalAt`/`mul16to32`. `bash compare/regen.sh` recompiles each under both `clang --target=w65816 -O2 -S` and `cc65816 --speed -O 2 --64bit-doubles` and prints an - ours/Calypsi instruction-count ratio. Current ratios (post - StackRelToImg 9-phase pipeline including saturating-max preheader - elimination): sumSquares **0.87×** (27 inst — we beat Calypsi's - 31), evalAt 2.10× (534 inst), mul16to32 **1.50×** (6 inst). - See `compare/README.md`. + ours/Calypsi instruction-count ratio. Current ratios (2026-05-20): + sumSquares **0.84×** (26 inst — we beat Calypsi's 31), + evalAt 1.86× (472 inst), mul16to32 **0.25×** (1 inst — we beat + Calypsi's 4). See `compare/README.md`. **Backend register allocation:** @@ -435,6 +437,36 @@ for the common-case C / minimal-C++ workload. Priority is speed the hi-half carry chain when one operand has known-zero high 16 bits. +- **W65816StackRelToImg peephole pipeline** (2026-05-20). Eight + always-on peepholes plus an extended phase 4 in the pre-emit + StackRelToImg pass: (1) `elidePhaBracket` with case-a single-store + bracket + case-b ImgCalleeSave multi-store with STA-hoist + + case-c STA_DP-only multi-pair + forward-walk liveness through + conditional branches; (2) `elideCallResultSaveSPReload` drops + STA/LDA $E0 round-trip in ADJCALLSTACKUP's Y-live i64-return + path; (3) `elideDeadStaCarry` drops first STA in i32-carry + STA/ADCE/STA pattern; (4) `elideRedundantLdaAfterPha`; (4b) + `elidePlaPhaPair` collapses consecutive PLA;PHA; (5) + `elideStoreForwarding` (gated to bail path + end-of-pass to + avoid IMG-slot reallocation cascade). Phase 4 extended to walk + past STX_DP/STY_DP between TYA and STA_DP with safety check + (post-STA op must redefine A) and to handle STA_StackRel + destination with offset compensation. Result: evalAt 498→472 + inst (1.96×→1.86× vs Calypsi), fib -35% cyc/iter (149→97), + popcount -11% (104→93), 35 libc functions get TAY/TYA bracket + elided. Case (b) hoists the body's first STA before the + ImgCalleeSave bracket, enabling the existing phase 4 to remove + PEI's TAY/TYA round-trip in a synergistic chain. + +- **__muldi3 32-bit short-circuit** (2026-05-20). When `a`'s high + 32 bits ($E4/$E6) are zero, use a 32-iter shift-and-add loop + instead of 64 iters. Fires on every `mulhi64Aligned` call from + softDouble.c (4× per `__muldf3`), which always passes zero- + extended u32 operands. Result: **dmul 1605→1033 cyc/iter + (-36%)**. Single-side check (just `a`) is correct since `b`'s + high half being non-zero doesn't affect correctness — iters 32-63 + would just shift b without adding. + **Open limitations:** - **Multi-bank BSS** — full support up to 4 banks (256KB). link816 @@ -445,7 +477,7 @@ for the common-case C / minimal-C++ workload. Priority is speed 0xFF00 so the 16-bit `cpx #__bss_segN_size` loop comparison doesn't wrap to 0 on a full-bank segment (a single full bank is split into a 0xFF00-byte primary + 0x100-byte tail in the same - bank). Smoke 137/137 validates BSS spanning bank 3 + bank 4 + bank). Smoke validates BSS spanning bank 3 + bank 4 (100KB) is zeroed end-to-end. Note: program access to non-DBR bank globals still requires DBR management — the compiler emits DBR-relative absolute for global accesses, so accessing BSS in @@ -495,5 +527,5 @@ for the common-case C / minimal-C++ workload. Priority is speed actually use those slots (most don't). Fixed picol `expr 1+2 == 4` (now `3`) and a class of recursive double-fn miscompiles with compound `||` conditions — see `feedback_picol_expr_compound_or.md`. - Smoke 149/149 green including a new orBug regression test guarding + Smoke green including a new orBug regression test guarding the fix. diff --git a/benchmarks/dadd.c b/benchmarks/dadd.c new file mode 100644 index 0000000..6b7feb6 --- /dev/null +++ b/benchmarks/dadd.c @@ -0,0 +1,4 @@ +// Soft-double addition. Lowers to __adddf3. +double dadd(double a, double b) { + return a + b; +} diff --git a/benchmarks/ddiv.c b/benchmarks/ddiv.c new file mode 100644 index 0000000..2099149 --- /dev/null +++ b/benchmarks/ddiv.c @@ -0,0 +1,4 @@ +// Soft-double division. Lowers to __divdf3. +double ddiv(double a, double b) { + return a / b; +} diff --git a/benchmarks/dmul.c b/benchmarks/dmul.c new file mode 100644 index 0000000..f63938d --- /dev/null +++ b/benchmarks/dmul.c @@ -0,0 +1,4 @@ +// Soft-double multiplication. Lowers to __muldf3. +double dmul(double a, double b) { + return a * b; +} diff --git a/compare/README.md b/compare/README.md index 05ee9d4..fd21a15 100644 --- a/compare/README.md +++ b/compare/README.md @@ -22,14 +22,14 @@ Recompiles every `*.c` in this directory under both compilers and prints an instruction-count summary: ``` -test ours calypsi ratio ----- ---- ------- ----- -evalAt 419 268 1.56x -mul16to32 12 11 1.09x -sumSquares 72 31 2.32x +test ours calypsi ratio +---- ---- ------- ----- +evalAt 472 254 1.86x +mul16to32 1 4 0.25x +sumSquares 26 31 0.84x ``` -(Numbers above are illustrative — re-run to see current state.) +(Numbers above are current as of 2026-05-20 — re-run for latest.) ## Adding a new comparison @@ -41,4 +41,4 @@ The summary counts asm-line opcodes (lda/sta/jsl/...) on our side and listing lines that begin with a hex byte (Calypsi's emit-byte column) on theirs. Both metrics are static instruction counts, NOT bytes. They underestimate calls-to-runtime (each libcall counts as one `jsl`, not the body it expands to). -For cycle counts, use `scripts/benchCyclesPrecise.sh`. +For cycle counts, use `scripts/benchCycles.sh`. diff --git a/compare/evalAt.calypsi.lst b/compare/evalAt.calypsi.lst index 2a52687..77c2e5d 100644 --- a/compare/evalAt.calypsi.lst +++ b/compare/evalAt.calypsi.lst @@ -1,7 +1,7 @@ ############################################################################### # # # Calypsi ISO C compiler for 65816 version 5.16 # -# 15/May/2026 00:38:15 # +# 20/May/2026 17:33:54 # # Command line: --speed -O 2 --64bit-doubles evalAt.c -o # # /tmp/evalAt.calypsi.elf --list-file evalAt.calypsi.lst # # # diff --git a/compare/evalAt.ours.s b/compare/evalAt.ours.s index c8f8627..c97cdd6 100644 --- a/compare/evalAt.ours.s +++ b/compare/evalAt.ours.s @@ -8,7 +8,7 @@ evalAt: ; @evalAt tay tsc sec - sbc #0x2e + sbc #0x32 tcs tya pha @@ -24,12 +24,11 @@ evalAt: ; @evalAt sta 0x3, s pla stx 0xc0 - sta 0x1b, s + sta 0x19, s clc adc #0x2 sta 0x1f, s lda 0xc0 - sta 0x21, s adc #0x0 sta 0x21, s lda 0x1f, s @@ -38,43 +37,36 @@ evalAt: ; @evalAt sta 0xe2 ldy #0x0 lda [0xe0], y - sta 0x1f, s - pha + sta 0x1d, s lda 0xc0 - sta 0x2f, s - pla - lda 0x1b, s + sta 0x31, s + lda 0x19, s sta 0xe0 - lda 0x2d, s + lda 0x31, s sta 0xe2 lda [0xe0], y sta 0x21, s - lda 0x32, s + lda 0x36, s sta 0xb, s lda #0x0 sta 0xc4 sta 0xc6 lda 0x21, s sta 0xe0 - lda 0x1f, s + lda 0x1d, s sta 0xe2 lda [0xe0], y - and #0xff - sta 0x1d, s + sta 0x1b, s sep #0x20 clc adc #0xd0 rep #0x20 and #0xff cmp #0xa - pha lda 0xc4 sta 0xc8 - pla - pha lda 0xc6 sta 0xca - pla bcc .LBB0_1 ; %bb.15: ; %entry brl .LBB0_4 @@ -83,46 +75,43 @@ evalAt: ; @evalAt inc a sta 0x21, s bne .Ltmp0 - lda 0x1f, s + lda 0x1d, s inc a - sta 0x1f, s + sta 0x1d, s .Ltmp0: lda #0x0 sta 0x15, s sta 0x13, s sta 0x11, s sta 0xf, s - lda 0x1f, s + lda 0x1d, s sta 0x17, s .LBB0_2: ; %while.body ; =>This Inner Loop Header: Depth=1 - sta 0x1f, s - lda 0x1b, s + sta 0x1d, s + lda 0x19, s tax - pha lda 0xc0 - sta 0x2d, s - pla + sta 0x2f, s txa sta 0xe0 - lda 0x2b, s + lda 0x2f, s sta 0xe2 lda 0x21, s ldy #0x0 sta [0xe0], y - lda 0x1b, s + lda 0x19, s clc adc #0x2 sta 0xd, s lda 0xc0 - sta 0x19, s adc #0x0 - sta 0x19, s + sta 0x1f, s lda 0xd, s sta 0xe0 - lda 0x19, s - sta 0xe2 lda 0x1f, s + sta 0xe2 + lda 0x1d, s sta [0xe0], y pea 0x4024 lda #0x0 @@ -137,30 +126,27 @@ evalAt: ; @evalAt tax lda 0x21, s jsl __muldf3 - sta 0xe0 + sta 0x2b, s tsc clc adc #0xc tcs - lda 0xe0 - sta 0x19, s txa sta 0x15, s tya sta 0x13, s lda 0xf0 sta 0x11, s - lda 0x1d, s + lda 0x1b, s sep #0x20 clc adc #0xd0 rep #0x20 and #0xff - sta 0x1d, s + sta 0x1b, s ldx #0x0 - lda 0x1d, s jsl __floatunsidf - sta 0x1d, s + sta 0x1b, s txa sta 0xf, s tya @@ -171,7 +157,7 @@ evalAt: ; @evalAt lda 0x13, s tax phx - lda 0x23, s + lda 0x21, s pha lda 0x19, s pha @@ -179,15 +165,13 @@ evalAt: ; @evalAt pha lda 0x21, s tax - lda 0x25, s + lda 0x2b, s jsl __adddf3 - sta 0xe0 + sta 0x21, s tsc clc adc #0xc tcs - lda 0xe0 - sta 0x15, s txa sta 0x13, s tya @@ -203,7 +187,7 @@ evalAt: ; @evalAt sta 0x21, s txa lda 0xd0 - sta 0x1d, s + sta 0x1f, s lda 0x17, s adc #0x0 sta 0x17, s @@ -215,14 +199,13 @@ evalAt: ; @evalAt sta 0xc4 lda 0x13, s sta 0xc6 - lda 0x1d, s - sta 0xe0 lda 0x1f, s + sta 0xe0 + lda 0x1d, s sta 0xe2 ldy #0x0 lda [0xe0], y - and #0xff - sta 0x1d, s + sta 0x1b, s sep #0x20 clc adc #0xd0 @@ -241,17 +224,17 @@ evalAt: ; @evalAt sta 0x21, s lda 0x17, s adc #0xffff - sta 0x1f, s + sta 0x1d, s .LBB0_4: ; %while.cond7.preheader lda 0xb, s eor #0x8000 sta 0xb, s - lda 0x1d, s + lda 0x1b, s brl .LBB0_5 .LBB0_11: ; %if.then33 ; in Loop: Header=BB0_5 Depth=1 lda 0xc6 - sta 0x1d, s + sta 0x1b, s lda 0xc4 sta 0x15, s lda 0xca @@ -260,7 +243,7 @@ evalAt: ; @evalAt sta 0x11, s lda 0x17, s pha - lda 0x1b, s + lda 0x1f, s pha lda 0x23, s pha @@ -270,28 +253,26 @@ evalAt: ; @evalAt pha lda 0x1b, s pha - lda 0x29, s + lda 0x27, s tax lda 0x21, s jsl __muldf3 .LBB0_12: ; %cleanup ; in Loop: Header=BB0_5 Depth=1 - sta 0xe0 + sta 0x2d, s tsc clc adc #0xc tcs - lda 0xe0 - sta 0x21, s txa sta 0x1f, s tya sta 0x1d, s lda 0xf0 - sta 0x19, s + sta 0x1b, s lda 0x1d, s sta 0xc8 - lda 0x19, s + lda 0x1b, s sta 0xca lda 0x21, s sta 0xc4 @@ -299,12 +280,11 @@ evalAt: ; @evalAt sta 0xc6 .LBB0_13: ; %cleanup ; in Loop: Header=BB0_5 Depth=1 - lda 0x1b, s + lda 0x19, s clc adc #0x2 sta 0x1f, s lda 0xc0 - sta 0x21, s adc #0x0 sta 0x21, s lda 0x1f, s @@ -313,13 +293,11 @@ evalAt: ; @evalAt sta 0xe2 ldy #0x0 lda [0xe0], y - sta 0x1f, s - lda 0x1b, s + sta 0x1d, s + lda 0x19, s tax - pha lda 0xc0 - sta 0x25, s - pla + sta 0x23, s txa sta 0xe0 lda 0x23, s @@ -327,26 +305,24 @@ evalAt: ; @evalAt lda [0xe0], y sta 0x21, s sta 0xe0 - lda 0x1f, s + lda 0x1d, s sta 0xe2 lda [0xe0], y - and #0xff .LBB0_5: ; %while.cond7 ; =>This Inner Loop Header: Depth=1 - sta 0x1d, s + sta 0x1b, s sep #0x20 clc adc #0xd6 rep #0x20 and #0xff - sta 0x19, s - lda 0x19, s + sta 0x1f, s pha lda #0x2b jsl __lshrhi3 ply sta 0x17, s - lda 0x19, s + lda 0x1f, s cmp #0x6 bcc .LBB0_6 ; %bb.17: ; %while.cond7 @@ -357,23 +333,53 @@ evalAt: ; @evalAt and #0x1 sta 0x17, s lda #0x0 - sta 0x29, s + sta 0x2d, s lda 0x17, s - ora 0x29, s + ora 0x2d, s bne .LBB0_7 ; %bb.18: ; %while.cond7 brl .LBB0_14 .LBB0_7: ; %switch.lookup ; in Loop: Header=BB0_5 Depth=1 - lda 0x19, s + lda #0x0 asl a - tax - lda .Lswitch.table.evalAt, x - sta 0x19, s - eor #0x8000 + sta 0x17, s + lda 0x1f, s + asl a + lda #0x0 + rol a + sta 0x2b, s + lda 0x17, s + ora 0x2b, s + sta 0x17, s + lda 0x1f, s + asl a + sta 0x1f, s + lda #.Lswitch.table.evalAt + sta 0x29, s + lda 0x1f, s + clc + adc 0x29, s + sta 0x1f, s + lda 0xbe sta 0x27, s + lda 0x17, s + adc 0x27, s + sta 0x17, s + lda 0x1f, s + sta 0xe0 + lda 0x17, s + sta 0xe2 + ldy #0x0 + lda [0xe0], y + sta 0x1f, s + tax + eor #0x8000 + sta 0x1f, s + txa + sta 0x17, s lda 0xb, s - cmp 0x27, s + cmp 0x1f, s bcc .LBB0_8 ; %bb.19: ; %switch.lookup brl .LBB0_14 @@ -383,16 +389,14 @@ evalAt: ; @evalAt inc a sta 0x21, s bne .Ltmp1 - lda 0x1f, s + lda 0x1d, s inc a - sta 0x1f, s + sta 0x1d, s .Ltmp1: - lda 0x1b, s + lda 0x19, s tax - pha lda 0xc0 - sta 0x27, s - pla + sta 0x25, s txa sta 0xe0 lda 0x25, s @@ -400,41 +404,39 @@ evalAt: ; @evalAt lda 0x21, s ldy #0x0 sta [0xe0], y - lda 0x1b, s + lda 0x19, s sta 0xd0 clc adc #0x2 - sta 0x17, s + sta 0x1f, s lda 0xd0 sta 0x21, s lda 0xc0 adc #0x0 sta 0x15, s - lda 0x17, s + lda 0x1f, s sta 0xe0 lda 0x15, s sta 0xe2 - lda 0x1f, s + lda 0x1d, s sta [0xe0], y - lda 0x19, s + lda 0x17, s pha ldx 0xc0 lda 0x23, s jsl evalAt - sta 0xe0 + sta 0x23, s tsc clc adc #0x2 tcs - lda 0xe0 - sta 0x21, s txa sta 0x1f, s tya - sta 0x19, s + sta 0x1d, s lda 0xf0 sta 0x17, s - lda 0x1d, s + lda 0x1b, s and #0xff cmp #0x2a bne .LBB0_9 @@ -451,7 +453,7 @@ evalAt: ; @evalAt .LBB0_10: ; %if.then29 ; in Loop: Header=BB0_5 Depth=1 lda 0xc6 - sta 0x1d, s + sta 0x1b, s lda 0xc4 sta 0x15, s lda 0xca @@ -460,7 +462,7 @@ evalAt: ; @evalAt sta 0x11, s lda 0x17, s pha - lda 0x1b, s + lda 0x1f, s pha lda 0x23, s pha @@ -470,7 +472,7 @@ evalAt: ; @evalAt pha lda 0x1b, s pha - lda 0x29, s + lda 0x27, s tax lda 0x21, s jsl __adddf3 @@ -506,7 +508,7 @@ evalAt: ; @evalAt sta 0xe0 tsc clc - adc #0x2e + adc #0x32 tcs lda 0xe0 rtl diff --git a/compare/mul16to32.calypsi.lst b/compare/mul16to32.calypsi.lst index d5095d8..7d15d96 100644 --- a/compare/mul16to32.calypsi.lst +++ b/compare/mul16to32.calypsi.lst @@ -1,7 +1,7 @@ ############################################################################### # # # Calypsi ISO C compiler for 65816 version 5.16 # -# 15/May/2026 00:38:15 # +# 20/May/2026 17:33:54 # # Command line: --speed -O 2 --64bit-doubles mul16to32.c -o # # /tmp/mul16to32.calypsi.elf --list-file # # mul16to32.calypsi.lst # diff --git a/compare/sumSquares.calypsi.lst b/compare/sumSquares.calypsi.lst index dbbce23..6c98d04 100644 --- a/compare/sumSquares.calypsi.lst +++ b/compare/sumSquares.calypsi.lst @@ -1,7 +1,7 @@ ############################################################################### # # # Calypsi ISO C compiler for 65816 version 5.16 # -# 15/May/2026 00:38:15 # +# 20/May/2026 17:33:54 # # Command line: --speed -O 2 --64bit-doubles sumSquares.c -o # # /tmp/sumSquares.calypsi.elf --list-file # # sumSquares.calypsi.lst # diff --git a/demos/README.md b/demos/README.md index f957c02..2057d49 100644 --- a/demos/README.md +++ b/demos/README.md @@ -67,28 +67,27 @@ 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` +### `frame.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. +Full port of ORCA-C's `Frame.cc` sample. Builds the +Apple+File+Edit menu bar via the real ROM Menu Manager +(`NewMenu` / `InsertMenu` / `FixAppleMenu` / `FixMenuBar` / +`DrawMenuBar`) and renders the original "About Frame" dialog +(white-filled framed rect with the 1989 Byte Works copyright +text and an OK button). -### `orcaMiniCadLike.c` +### `minicad.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`. +Full port of ORCA-C's `MiniCAD.cc` sample. Apple+File+Edit+ +Options menu bar + a windowed canvas with three seeded line-art +patterns (curve-stitching, sunburst, Star of David). -### `orcaReversiLike.c` +### `reversi.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. +Full Othello game ported from ORCA-C's `Reversi.cc`. 100-byte +sentinel-bordered board, 8-direction capture detection, 1-ply +AI with corner/edge weighting, QD-rendered board with black/white +pieces. ### `qdProbe.c` diff --git a/demos/frame.bin b/demos/frame.bin index 7976cd826fa955531964890c02f3f2be274deb60..0334f209b9560be0785a2e9af695bf07e2e13f79 100644 GIT binary patch delta 2280 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 (or cmd-Q) +// exits. The "About Frame" item in the Apple menu shows the original +// 4-line copyright dialog. +// +// Differences from the original: +// - The watchdog at the bottom of the loop forces a clean exit so +// the headless test (`demos/test.sh frame`) can verify $70 = $99. +// In interactive use the watchdog is benign. #include "iigs/toolbox.h" #include "iigs/desktop.h" @@ -14,60 +20,131 @@ #define apple_About 257 #define file_Quit 256 +#define wInSpecial 25 +#define wInMenuBar 3 -typedef struct { short v1, h1, v2, h2; } Rect; +#define norml 0 +#define stop 1 +#define note 2 +#define caution 3 + +#define buttonItem 10 +#define statText 136 +#define itemDisable 0x8000 -// 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"; +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 void drawAbout(void) { - Rect outer; - outer.h1 = 180; outer.v1 = 50; - outer.h2 = 460; outer.v2 = 107; +typedef struct { + short itemID; + short itemRectV1, itemRectH1, itemRectV2, itemRectH2; + unsigned short itemType; + void *itemDescr; + short itemValue; + short itemFlag; + void *itemColor; +} ItemTemplate; - 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); +typedef struct { + short atRectV1, atRectH1, atRectV2, atRectH2; + short atBtnHorz; + short atBeep0, atBeep1, atBeep2, atBeep3; + void *atSound; + void *atResv1; + void *atResv2; + void *atItemList[8]; +} AlertTemplate; - Rect ok; - ok.h1 = 395; ok.v1 = 88; - ok.h2 = 445; ok.v2 = 102; - FrameRect(&ok); - MoveTo(412, 98); - DrawString((void *)btnOk); + +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 unsigned char gAboutMsg[] = + "\x3a" "Frame 1.0\r" + "Copyright 1989\r" + "Byte Works, Inc.\r\r" + "By Mike Westerfield"; + +static WmTaskRec gEvent; +static volatile unsigned short gDone; + + +static void doAlert(unsigned short kind, void *msg) { + static unsigned char okStr[] = "\x02OK"; + static ItemTemplate button = { + 1, 36, 15, 0, 0, buttonItem, okStr, 0, 0, (void *)0 + }; + static ItemTemplate message = { + 100, 5, 100, 90, 280, itemDisable | statText, (void *)0, 0, 0, (void *)0 + }; + static AlertTemplate alertRec = { + 50, 180, 107, 460, + 2, + 0x80, 0x80, 0x80, 0x80, + (void *)0, (void *)0, (void *)0, + { (void *)0, (void *)0, (void *)0, (void *)0, + (void *)0, (void *)0, (void *)0, (void *)0 } + }; + + SetForeColor(0); + SetBackColor(15); + + message.itemDescr = msg; + alertRec.atItemList[0] = (void *)&button; + alertRec.atItemList[1] = (void *)&message; + alertRec.atItemList[2] = (void *)0; + + switch (kind) { + case norml: (void)Alert(&alertRec, (void *)0); break; + case stop: (void)StopAlert(&alertRec, (void *)0); break; + case note: (void)NoteAlert(&alertRec, (void *)0); break; + case caution: (void)CautionAlert(&alertRec, (void *)0); break; + default: break; + } +} + + +static void menuAbout(void) { + doAlert(note, gAboutMsg); +} + + +static void handleMenu(unsigned short menuNum) { + switch (menuNum) { + case apple_About: menuAbout(); break; + case file_Quit: gDone = 1; break; + default: break; + } + HiliteMenu(0, (unsigned short)(gEvent.wmTaskData >> 16)); } @@ -85,12 +162,26 @@ int main(void) { unsigned short userId = startdesk(640); (void)userId; + paintDesktopBackdrop(); // white desktop (WM dither -> noise in + // our 640 B/W palette; paint directly) initMenus(); + gEvent.wmTaskMask = 0x1FFFL; ShowCursor(); - for (volatile unsigned long s = 0; s < 100000UL; s++) { } - drawAbout(); - for (volatile unsigned long s = 0; s < 200000UL; s++) { } + gDone = 0; + unsigned short watchdog = 0; + do { + unsigned short event = TaskMaster(0x076E, &gEvent); + switch (event) { + case wInSpecial: + case wInMenuBar: + handleMenu((unsigned short)gEvent.wmTaskData); + break; + default: + break; + } + watchdog++; + } while (!gDone && watchdog < 4000); *(volatile unsigned char *)0x70 = 0x99; return 0; diff --git a/demos/frame.map b/demos/frame.map index cee1dc6..3f57018 100644 --- a/demos/frame.map +++ b/demos/frame.map @@ -1,19 +1,19 @@ # section layout -.text : 0x001000 .. 0x0024b3 ( 5299 bytes) -.rodata : 0x0024b3 .. 0x0025b2 ( 255 bytes) -.bss : 0x00a000 .. 0x00a00a ( 10 bytes) +.text : 0x001000 .. 0x002286 ( 4742 bytes) +.rodata : 0x002286 .. 0x0023f2 ( 364 bytes) +.bss : 0x00a000 .. 0x00a038 ( 56 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 + 615 /home/scott/claude/llvm816/demos/frame.o + 45465 /home/scott/claude/llvm816/runtime/libc.o + 15382 /home/scott/claude/llvm816/runtime/snprintf.o + 13322 /home/scott/claude/llvm816/runtime/extras.o + 8398 /home/scott/claude/llvm816/runtime/softFloat.o + 16151 /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 + 1565 /home/scott/claude/llvm816/runtime/desktop.o 2540 /home/scott/claude/llvm816/runtime/libgcc.o # global symbols (sorted by address) @@ -28,120 +28,121 @@ 0x000000 __bss_seg3_bank 0x000000 __bss_seg3_lo16 0x000000 __bss_seg3_size -0x00000a __bss_seg0_size -0x00000a __bss_size +0x000038 __bss_seg0_size +0x000038 __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 +0x001321 CtlStartUp +0x001331 NoteAlert +0x00134d EMStartUp +0x00136c FMStartUp +0x00137c LEStartUp +0x00138c LoadOneTool +0x00139c NewHandle +0x0013c2 MenuStartUp +0x0013d2 HiliteMenu +0x0013e2 InsertMenu +0x0013f7 NewMenu +0x001411 QDStartUp +0x001427 TaskMaster +0x00143e startdesk +0x001868 paintDesktopBackdrop +0x00189a __jsl_indir +0x00189d __mulhi3 +0x0018bc __umulhisi3 +0x001913 __ashlhi3 +0x001922 __lshrhi3 +0x001932 __ashrhi3 +0x001945 __udivhi3 +0x001951 __umodhi3 +0x00195d __divhi3 +0x001977 __modhi3 +0x001991 __divmod_setup +0x0019c4 __udivmod_core +0x0019e2 __mulsi3 +0x001a9b __ashlsi3 +0x001ab0 __lshrsi3 +0x001ac5 __ashrsi3 +0x001adf __udivmodsi_core +0x001b17 __udivsi3 +0x001b2b __umodsi3 +0x001b3f __divsi3 +0x001b66 __modsi3 +0x001b8d __divmodsi_setup +0x001bde __divmoddi4_stash +0x001bfb __retdi +0x001c08 __ashldi3 +0x001c2b __lshrdi3 +0x001c4e __ashrdi3 +0x001c74 __muldi3 +0x001ccf __ucmpdi2 +0x001cf8 __cmpdi2 +0x001d2f __udivdi3 +0x001d38 __umoddi3 +0x001d51 __udivmoddi_core +0x001d9e __divdi3 +0x001dbd __moddi3 +0x001dea __absdi_a +0x001df2 __absdi_b +0x001dfa __negdi_a +0x001e18 __negdi_b +0x001e36 setjmp +0x001e5e longjmp +0x001e88 __umulhisi3_qsq +0x002286 __rodata_start +0x002286 __text_end +0x002286 gChainPath +0x00229a editMenuStr +0x0022f3 fileMenuStr +0x002320 appleMenuStr +0x00233f gAboutMsg +0x00237f doAlert.okStr +0x002384 doAlert.button +0x00239c doAlert.message +0x0023b4 doAlert.alertRec +0x0023f2 __init_array_end +0x0023f2 __init_array_start +0x0023f2 __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 +0x00a000 gEvent +0x00a02c gDone +0x00a02e gUserId +0x00a030 gDpHandle +0x00a034 gDpBase +0x00a036 __indirTarget +0x00a038 __bss_end +0x00a038 __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 +CtlStartUp = 0x001321 +EMStartUp = 0x00134d +FMStartUp = 0x00136c +HiliteMenu = 0x0013d2 +InsertMenu = 0x0013e2 +LEStartUp = 0x00137c +LoadOneTool = 0x00138c +MenuStartUp = 0x0013c2 +NewHandle = 0x00139c +NewMenu = 0x0013f7 +NoteAlert = 0x001331 +QDStartUp = 0x001411 +TaskMaster = 0x001427 +__absdi_a = 0x001dea +__absdi_b = 0x001df2 +__ashldi3 = 0x001c08 +__ashlhi3 = 0x001913 +__ashlsi3 = 0x001a9b +__ashrdi3 = 0x001c4e +__ashrhi3 = 0x001932 +__ashrsi3 = 0x001ac5 __bss_bank = 0x000000 -__bss_end = 0x00a00a +__bss_end = 0x00a038 __bss_lo16 = 0x00a000 __bss_seg0_bank = 0x000000 __bss_seg0_lo16 = 0x00a000 -__bss_seg0_size = 0x00000a +__bss_seg0_size = 0x000038 __bss_seg1_bank = 0x000000 __bss_seg1_lo16 = 0x000000 __bss_seg1_size = 0x000000 @@ -151,63 +152,66 @@ __bss_seg2_size = 0x000000 __bss_seg3_bank = 0x000000 __bss_seg3_lo16 = 0x000000 __bss_seg3_size = 0x000000 -__bss_size = 0x00000a +__bss_size = 0x000038 __bss_start = 0x00a000 -__cmpdi2 = 0x001f25 -__divdi3 = 0x001fcb -__divhi3 = 0x001b8a -__divmod_setup = 0x001bbe -__divmoddi4_stash = 0x001e0b -__divmodsi_setup = 0x001dba -__divsi3 = 0x001d6c +__cmpdi2 = 0x001cf8 +__divdi3 = 0x001d9e +__divhi3 = 0x00195d +__divmod_setup = 0x001991 +__divmoddi4_stash = 0x001bde +__divmodsi_setup = 0x001b8d +__divsi3 = 0x001b3f __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 +__heap_start = 0x00a038 +__indirTarget = 0x00a036 +__init_array_end = 0x0023f2 +__init_array_start = 0x0023f2 +__jsl_indir = 0x00189a +__lshrdi3 = 0x001c2b +__lshrhi3 = 0x001922 +__lshrsi3 = 0x001ab0 +__moddi3 = 0x001dbd +__modhi3 = 0x001977 +__modsi3 = 0x001b66 +__muldi3 = 0x001c74 +__mulhi3 = 0x00189d +__mulsi3 = 0x0019e2 +__negdi_a = 0x001dfa +__negdi_b = 0x001e18 +__retdi = 0x001bfb +__rodata_end = 0x0023f2 +__rodata_start = 0x002286 __start = 0x001000 -__text_end = 0x0024b3 +__text_end = 0x002286 __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 +__ucmpdi2 = 0x001ccf +__udivdi3 = 0x001d2f +__udivhi3 = 0x001945 +__udivmod_core = 0x0019c4 +__udivmoddi_core = 0x001d51 +__udivmodsi_core = 0x001adf +__udivsi3 = 0x001b17 +__umoddi3 = 0x001d38 +__umodhi3 = 0x001951 +__umodsi3 = 0x001b2b +__umulhisi3 = 0x0018bc +__umulhisi3_qsq = 0x001e88 +appleMenuStr = 0x002320 +doAlert.alertRec = 0x0023b4 +doAlert.button = 0x002384 +doAlert.message = 0x00239c +doAlert.okStr = 0x00237f +editMenuStr = 0x00229a +fileMenuStr = 0x0022f3 +gAboutMsg = 0x00233f +gChainPath = 0x002286 +gDone = 0x00a02c +gDpBase = 0x00a034 +gDpHandle = 0x00a030 +gEvent = 0x00a000 +gUserId = 0x00a02e +longjmp = 0x001e5e main = 0x0010ba -setjmp = 0x002063 -startdesk = 0x0016e1 +paintDesktopBackdrop = 0x001868 +setjmp = 0x001e36 +startdesk = 0x00143e diff --git a/demos/frame.o b/demos/frame.o index b560f0d71e8c950b14e8115f5429e6c3f4926499..3c3d56b57e956bf84c97315876a2cdf056b2f8ed 100644 GIT binary patch literal 2904 zcmbVNU2GIp6h7N&X-ip_mY-4@=pr0is4G}~nLA~QCK_*Z=6vTn z-#z!-JF~a1?me*2<#IhDFG2;zn z*A{0(Xl^E54w5D(7wYIoT9EKKLv$H})%>W1ZFo*1%N55^5t; z8<$Y^Ow}(fR>xf3V~!62lz3;8lh`$Oh7-pj{cZChTLx7{VO`TLT6o{H;bWe0*E{ph zn;D{cFP}p}%HJ%M4@wG;~k7AK&t32I~rG$Q7Sq3 z9RK3Bk_R6f(Q@-?KcZAdQ94fRU9V5s9Qz=BN(s8*DxoRy=gj^qjwF?I%sZiG^|+Sy z2HRx6?2qA~o5lGHU@i;D+Qu=A}?qRKjzdd5oOYkmQMlZuN_KElq z{A;iV5x2tgXo0zKV&4c{BH};cH(<>^GhRmD!P599TnLqdJ$ zkdTjq_!?FUWBn&W5JLks*w1GoX15B4-^AkJ*l`?YzH%{Z=}$fp2OSf5e&ZAQHBZET z#1acJ+F??)327%>iQB?_Hd2j+4>DeD;iGV@;qyPvywD^V3ym%`{7xnunzIhghpbsa z#J$Z5ybk_Lf%)Ct6By2XAClO}FNjNVmVdxMaNys7%fN4hJp|_Z+#bJM#=PYkU}-G? zMguU{*#f^A#&aLS`vf0=Zx#F+bXMR# z_;&^Fg}*HDD)>2p`{6$qcmVzff%*IW87A?eVLV`7?DuzI-V67PE5YRXJUzhn-s>3G znp0_$L(>S%XVMDW;lMs%uK5+F{0ftB4*ZQTE0;>ks#Y$qte_$F40Tr$X^QQgP}2tSosu#^Sl3C#_0H-Sj4UacOwydn!6&z(j;fqq+<3WrywWYP_jl8 zb4X63H~HD2BR+7E1jWqjeNc~)%y-_15{=@1j8SZlmR1+brc_;5Vvl2mH}||6p;7*~ zAV)~njjW-B;ZLVbZ#EEB424EUlKL2Gwpp*?KRs*toja7h71sA?Q%IY`x(o4sM9jZ) z=is}E$44-paF2OxM(zewCG1BR{&G55nce17x{3@t78_#QMeVtd%7TTqy5 z+k0W%F?%uawr(3Z=ek=_oY&!Xxo3ObPGFwScN>rUD4epO`Q#kiobYhwP`H3&u!hGM oFzLV}4Q>iXeyq#?i+NohwvO)*yI1C;s5b?U^ZXy2%k#bS7d0;l&;S4c literal 3328 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 QJg_@_WmuX)kLrPc1F~IdHvj+t delta 3469 zcma)8eQaA-6+iD?KYzxtv&8vw9X~(UGohqw7}K&&Llcn5MJf#Kvxtw4DI>-$tIA+) z1$|YXUW+nyOE9QZMG(EK*TzAex@J|kinXkh76KD%rTu}J05|HQl8ut06pf-boO7=o zH>)casXFiXJHK=8Ip==3zn)M}99Boa77UI8e1QLcuZ|to$M&=ZI*TCwf@6pJl;GIk z?ofioh|&=|mMI_09BtiG9tU`-yw5-WXJfjvc%PDJnp)kSS7G9e?f}f{uT8Bk7L>cq zK8TlgtH$|Oa8FH^rdJzRu*F>dDbqE*t7VF9qli3pIzpfz%_89 zZ24qJMucQU$cggI_#RyDC_~axxNk-UT3tJ;5uqWWn6MxK<1DRMX|A#KSvEYV%4{i- zEhP*1v@Ae)?6d88FE-_##fD^KOjO3OvbPkhOd|>Qt)ZmaJ43e2N%FGn;XYyr`=HLw0;|}DPm8A&`OG7CFQUlt2QY1zV4WwqcNFcPB?@53p|Bs96E>wHTf+l z{X$u8^2KVAA3b4m?-HV%#Q!-wxc+SI^u$F>ymERhCQb`yGxvv=j}dP3jE9ayDRSO=b=1-xXX121d^IHP0Q39Jh5+RqC@)P$lY6dg3LiE39~k?I-8;bLt} z_R}V6Ypc}Op2vf%aF)k|ToJ^CASMKyW?Q)_oYlT-tu_mFvw2gm;>wJQD?`01)T@Ma zgA~B3?_0uPOB=pxNi-9{W&%h@mp*PU5wUm#*EVVVb(#qaMfhVj6B6psO}&VHtM$TG z_QJ52&KsJs%WgTxy*VeU(uFIo_58T_rl;TBGwaUg(B*hs;tO`U#ynVIDv_S`Hz^(x z%$ao)_xAn$Gk5^3bk0%50z+16AB+D3057-S(D4@IpOqTHJEe}B)}8qL z@;l`$QsTyyJmXd`vAvQ_?k`Vr`A*>$r}lZrOQT>Vd3t8IiVs{Aza1tPJp$u7p2_ia zj%N*9ti;pntu*phf~TyW_B^OoiuYi2BDXjVyf>SZHMRinG0w$AaXWW9zU6$5Uwk@& z3RCRyc9~JkO^Z2=f?ZTtDGo-3#RZbq8eEFuGHdYNO=3mH0_G-Nw5G!rtZvk4sOiQi zEIVbqUeUGOs7qN{)Ok^pMQtieLckg*VQg8Lb7ITov=Upq>}?aZ;zAir;KASw4MVJz zHU=<7={#8J68zFi(In$EXr8{|Cn+VaZvrzU^LR0Ea41NkU@3xE554%l)$xj-GxU1R zy6$SQzpl3$9IWfD#x~UT%2+Geo?j&niAhy=P@$b*wed8;7{PY1nk8%^i2pN)NEjyA z0#-=E0KwbvhfG3^AWn)&s1R&~Nt{oDQYS{NJ8(dW>VVi9M2eVa?WK~l!z;}LRS&)w zJY4*t-*^mvWOzrF#^haf+pG>j2iiT$jJQlOd4n}MO;%W-$UV9#-neNo5n4+{FJIDWh{?_TOwVIeTIVQGopufkBpQ~YM| zP}_0czUY?w-n$U>puaOX>0a!+h8b6d=2H!cL-X!M@rq#93*2kZ>BwE8+$R(GSm%3rMeN}JM z^`wpp_v!-Ev-*L7IobKYE41CYTPQ*$O8CecNHG1*YFFN~T9 z!#tn+!ueA(wE^Bo`1EPmj#NirolDG~Su()=Pk z;a|`&%O@n+BguaM>)I8Q!2^al6rtxOas@JBLc#|cM8u#pUkNvaQ93BimheeJTP6Cb zMEfOj8bgifyC%);5rMug&Et_>5%fJJQC_0AB>GdNjSBt3yOAW>ze?wOku0J2rRIv% Vd?+RVm6F?{Lb6Jl)zSVa{120#tEm70 diff --git a/demos/frame.reloc b/demos/frame.reloc index 12949c8b02c454d18c7f413fa4b2392929ee4ef5..d3797677b9eb80ffc7236a6fe478e11a31f1e1fa 100644 GIT binary patch literal 1348 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 delta 2583 zcmZuyU5pb|6h6~wDc#cT4ny17?e0!z>ULdlgQ&O_34+3=imrtCi$?y{$r>~ff3n7u z>`jSoY~0P5pot+vFN54hqDG?$QKI;u=!3kO_+l+)gG9+j8>0rdo_lAyRpFtXbHDqY zbG|d@-ZLk+o*16KMtWdoxI1woS38k=H+it;0K8W#-{*X1-q}0zP@j^|X;uJ^pUzYO z>X}dSxtW(oifbXw4g}1%QegJ{$=Ua;%Q%l0c z!~_dEWCRg9QmRdr>g;F^^Bt|1WHjLsq$`idDKwfbJ>e z?Fy7PI_v`|-|Db_D6eMnMZ+b@!>+7yaCu|A02C>7;V%??`fkW zz&7|Os%%wv9k8`Nx}%K_0~_&Bd?}`|Ji(vOf;v z8aH?KbF>(yv9=%2E|$y55N00|OU(XCjtuhbgChF?W*_)}cBLJKgm@m+&-0wfqiVau zMDdT6A*pnrcVgvzs5iorOrECV0$e&Y4lqQ%a< zWRHt&ZE?|TaXo@aB~JefDY#j)ZUTPgiOTzn-Btudvbe0$EWdZfI@;pmVk2wVP`*CI zyDApEt)7n|d<=0{5sfp6*BL)^pa-pYW!xoks-6kM!ZL=-MKBlQTMAXOaiY_htk13D z_jE4e-OZwv!db-Lc=aiO(;1{5$8$9=7$Rov~8wVBM`3+!{_K*S=%v;HLIE%_r3OzZjkUmm$&15S=6T$))My>1&VQ zod4-Me19Zcs00Fh<8fk?#~f5sC^QnE(!oLna2|%uZ^am&AjTBY*%mR4Tf>+d-Ynnh zkd=IHuk>D+eyCQZ3rD~x-{Y`pz^-P`90*{ayTE=??YMf(DbRre%@*jO`M1bHvujB9 z#F#_+s6kd}7D&XPE9`gF=bB2l35x| zA0=6;lOYToKs7@cTt^A!Tj;`hU2UF@0tS&6M9v_383k&X&-*-_n>-%Pk^!WIaC?A@ zHh3xdtoe~oODu#dR1ynfk{-%_0Dip=6Qhz8d-gBOzK&~FFOY5wtXp^}bo-0M6VkAK zLvovfXN&5sOJ`_Szr8b&uzM4W?T?emB4*EGw`i8%3f|Rmufd&Y9z07Tys4F-!@JDl z+^leuE+zasco0|+NYp(`!i^3bhTepVh=Cx}FbQ!jAu6MSP-}*VXatwxQXQ|jOgD%4 zcT~miD0*S62n}dt9BBO8;S&u4^TpG@!EHm$p}n=TH)fzn@@H;v3u0~zjLb8_Zw zV{#oQy0ib={Iyhb8(7`%r61itO0zApGVjiIakm}rMSOl`y#Gw^k>JjUa{$}%w--1FaMXHYF9bL3vGzmw?x*%!Pwsmf&da;xh6J!={_rL3(&0->=JER`?UKF!%XhNew opens a drawing window (up to +// 4), click+drag inside a window's content rubber-bands a line, +// release commits it. File>Close closes the front window. Each +// window's lines are remembered so the WM can repaint on update. #include "iigs/toolbox.h" #include "iigs/desktop.h" +#define apple_About 257 +#define file_Quit 256 +#define file_New 258 +#define file_Close 255 + +#define wInMenuBar 3 +#define wInSpecial 25 +#define wInGoAway 17 #define wInContent 19 -#define fVis 0x0020 -#define fMove 0x0080 -#define fClose 0x4000 + +#define mUpMask 0x0002 + +#define modeCopy 0 +#define modeXOR 2 + +#define topMost ((void *)-1L) +#define bottomMost ((void *)0) + +#define maxWindows 4 +#define maxLines 50 + +#define norml 0 +#define stop 1 +#define note 2 +#define caution 3 +#define buttonItem 10 +#define statText 136 +#define itemDisable 0x8000 typedef struct { short v1, h1, v2, h2; } Rect; +typedef struct { short v, h; } Point; +typedef struct { Point p1, p2; } LineRec; + + +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; + + +typedef struct { + unsigned short wmWhat; + unsigned long wmMessage; + unsigned long wmWhen; + short wmWhereV, wmWhereH; + unsigned short wmModifiers; +} EventRec; + typedef struct { unsigned short paramLength; @@ -44,106 +95,282 @@ typedef struct { } NewWindowParm; -typedef struct { short v1, h1, v2, h2; } LineRec; +typedef struct { + short itemID; + short itemRectV1, itemRectH1, itemRectV2, itemRectH2; + unsigned short itemType; + void *itemDescr; + short itemValue; + short itemFlag; + void *itemColor; +} ItemTemplate; + +typedef struct { + short atRectV1, atRectH1, atRectV2, atRectH2; + short atBtnHorz; + short atBeep0, atBeep1, atBeep2, atBeep3; + void *atSound; + void *atResv1; + void *atResv2; + void *atItemList[8]; +} AlertTemplate; -static unsigned char gTitle[] = "\x07MiniCAD"; +typedef struct { + void *wPtr; + unsigned char *name; + unsigned short numLines; + LineRec lines[maxLines]; +} WindowRecord; -// 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 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\\N258*Nn\r" + "--Close\\N255V\r" + "--Quit\\N256*Qq\r" + ".\r"; + +static unsigned char appleMenuStr[] = ">>@\\XN1\r" + "--About...\\N257V\r" + ".\r"; + +static unsigned char gAboutMsg[] = + "\x3d" "Mini-CAD 1.0\r" + "Copyright 1989\r" + "Byte Works, Inc.\r\r" + "By Mike Westerfield"; + +static unsigned char gTitle0[] = "\x07Paint 1"; +static unsigned char gTitle1[] = "\x07Paint 2"; +static unsigned char gTitle2[] = "\x07Paint 3"; +static unsigned char gTitle3[] = "\x07Paint 4"; + +static WindowRecord gWindows[maxWindows] = { + { (void *)0, gTitle0, 0, { { {0,0}, {0,0} } } }, + { (void *)0, gTitle1, 0, { { {0,0}, {0,0} } } }, + { (void *)0, gTitle2, 0, { { {0,0}, {0,0} } } }, + { (void *)0, gTitle3, 0, { { {0,0}, {0,0} } } } }; -static NewWindowParm gWp; +static WmTaskRec gEvent; +static volatile unsigned short gDone; -// 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)); +static void doAlert(unsigned short kind, void *msg) { + static unsigned char okStr[] = "\x02OK"; + static ItemTemplate button = { + 1, 36, 15, 0, 0, buttonItem, okStr, 0, 0, (void *)0 + }; + static ItemTemplate message = { + 100, 5, 100, 90, 280, itemDisable | statText, (void *)0, 0, 0, (void *)0 + }; + static AlertTemplate alertRec = { + 50, 180, 107, 460, 2, 0x80, 0x80, 0x80, 0x80, + (void *)0, (void *)0, (void *)0, + { (void *)0, (void *)0, (void *)0, (void *)0, + (void *)0, (void *)0, (void *)0, (void *)0 } + }; + SetForeColor(0); + SetBackColor(15); + message.itemDescr = msg; + alertRec.atItemList[0] = (void *)&button; + alertRec.atItemList[1] = (void *)&message; + alertRec.atItemList[2] = (void *)0; + switch (kind) { + case norml: (void)Alert(&alertRec, (void *)0); break; + case stop: (void)StopAlert(&alertRec, (void *)0); break; + case note: (void)NoteAlert(&alertRec, (void *)0); break; + case caution: (void)CautionAlert(&alertRec, (void *)0); break; + default: break; } } -// 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)); +// Window-content def-proc. The WM calls this with DBR set to our +// bank (Loader sets up the JSL chain). We use GetWRefCon on the +// current port to know which gWindows[] entry to redraw. +static void drawWindow(void) { + unsigned long refcon = (unsigned long)GetWRefCon(GetPort()); + unsigned short i = (unsigned short)refcon; + if (i >= maxWindows) return; + WindowRecord *wp = &gWindows[i]; + if (wp->numLines == 0) return; + SetPenMode(modeCopy); + SetSolidPenPat(0); + SetPenSize(2, 1); + for (unsigned short j = 0; j < wp->numLines; j++) { + LineRec *lp = &wp->lines[j]; + MoveTo(lp->p1.h, lp->p1.v); + LineTo(lp->p2.h, lp->p2.v); } } -// 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)); +static void doNew(void) { + static NewWindowParm wp; + unsigned short i = 0; + while (i < maxWindows && gWindows[i].wPtr != (void *)0) i++; + if (i >= maxWindows) return; + gWindows[i].numLines = 0; + + unsigned char *p = (unsigned char *)℘ + for (unsigned short k = 0; k < sizeof wp; k++) p[k] = 0; + wp.paramLength = (unsigned short)sizeof wp; + wp.wFrameBits = 0x4007 | 0x0020 | 0x0080 | 0x0400 | 0x4000; // fTitle+fClose+fVis+fMove+fGrow + wp.wTitle = gWindows[i].name; + wp.wRefCon = (unsigned long)i; + wp.wMaxHeight = 188; + wp.wMaxWidth = 615; + wp.wPosition.v1 = (short)(25 + i * 10); + wp.wPosition.h1 = (short)(10 + i * 10); + wp.wPosition.v2 = (short)(180 + i * 10); + wp.wPosition.h2 = (short)(600 + i * 10); + wp.wContDefProc = (void *)&drawWindow; + wp.wPlane = topMost; + gWindows[i].wPtr = NewWindow(&wp); + if (i == maxWindows - 1) { + DisableMItem(file_New); + } +} + + +static void doClose(void) { + void *fw = FrontWindow(); + if (!fw) return; + unsigned short i = (unsigned short)(unsigned long)GetWRefCon(fw); + if (i >= maxWindows) return; + CloseWindow(gWindows[i].wPtr); + gWindows[i].wPtr = (void *)0; + EnableMItem(file_New); +} + + +static void menuAbout(void) { + doAlert(note, gAboutMsg); +} + + +static void sketch(void) { + void *fw = FrontWindow(); + if (!fw) return; + unsigned short i = (unsigned short)(unsigned long)GetWRefCon(fw); + if (i >= maxWindows) return; + if (gWindows[i].numLines >= maxLines) { + static unsigned char fullMsg[] = + "\x3a" "The window is full -\r" + "more lines cannot be\r" + "added."; + doAlert(stop, fullMsg); + return; + } + + StartDrawing(fw); + SetSolidPenPat(15); + SetPenSize(2, 1); + SetPenMode(modeXOR); + + Point firstPt; + firstPt.h = gEvent.wmWhereH; + firstPt.v = gEvent.wmWhereV; + GlobalToLocal(&firstPt); + MoveTo(firstPt.h, firstPt.v); + LineTo(firstPt.h, firstPt.v); + Point endPt = firstPt; + + EventRec ev; + while (!GetNextEvent(mUpMask, &ev)) { + Point cur; + cur.h = ev.wmWhereH; + cur.v = ev.wmWhereV; + GlobalToLocal(&cur); + if (cur.h != endPt.h || cur.v != endPt.v) { + MoveTo(firstPt.h, firstPt.v); + LineTo(endPt.h, endPt.v); + MoveTo(firstPt.h, firstPt.v); + LineTo(cur.h, cur.v); + endPt = cur; + } + } + + // Erase final XOR line. + MoveTo(firstPt.h, firstPt.v); + LineTo(endPt.h, endPt.v); + + if (firstPt.h != endPt.h || firstPt.v != endPt.v) { + unsigned short n = gWindows[i].numLines++; + gWindows[i].lines[n].p1 = firstPt; + gWindows[i].lines[n].p2 = endPt; + SetPenMode(modeCopy); + SetSolidPenPat(0); + MoveTo(firstPt.h, firstPt.v); + LineTo(endPt.h, endPt.v); + } +} + + +static void handleMenu(unsigned short menuNum) { + switch (menuNum) { + case apple_About: menuAbout(); break; + case file_Quit: gDone = 1; break; + case file_New: doNew(); break; + case file_Close: doClose(); break; + default: break; + } + HiliteMenu(0, (unsigned short)(gEvent.wmTaskData >> 16)); +} + + +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; + paintDesktopBackdrop(); - paintMenuBarTitles(menuTitles, 4); + initMenus(); + gEvent.wmTaskMask = 0x1FFFL; 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); + // Open one window so the demo has visible content immediately. + doNew(); - if (win) { - BeginUpdate(win); - SetPort(win); - SetSolidPenPat(0); + gDone = 0; + unsigned short watchdog = 0; + do { + unsigned short event = TaskMaster(0x076E, &gEvent); + switch (event) { + case wInSpecial: + case wInMenuBar: + handleMenu((unsigned short)gEvent.wmTaskData); + break; + case wInGoAway: + doClose(); + break; + case wInContent: + sketch(); + break; + default: + break; + } + watchdog++; + } while (!gDone && watchdog < 4000); - // 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; } diff --git a/demos/minicad.map b/demos/minicad.map index bae295a..999566f 100644 --- a/demos/minicad.map +++ b/demos/minicad.map @@ -1,19 +1,19 @@ # section layout -.text : 0x001000 .. 0x002638 ( 5688 bytes) -.rodata : 0x002638 .. 0x0026ad ( 117 bytes) -.bss : 0x00a000 .. 0x00a058 ( 88 bytes) +.text : 0x001000 .. 0x003102 ( 8450 bytes) +.rodata : 0x003102 .. 0x00393a ( 2104 bytes) +.bss : 0x00a000 .. 0x00a086 ( 134 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 + 4058 /home/scott/claude/llvm816/demos/minicad.o + 43132 /home/scott/claude/llvm816/runtime/libc.o + 14895 /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 + 1349 /home/scott/claude/llvm816/runtime/desktop.o 2540 /home/scott/claude/llvm816/runtime/libgcc.o # global symbols (sorted by address) @@ -28,126 +28,154 @@ 0x000000 __bss_seg3_bank 0x000000 __bss_seg3_lo16 0x000000 __bss_seg3_size -0x000058 __bss_seg0_size -0x000058 __bss_size +0x000086 __bss_seg0_size +0x000086 __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 +0x001eee drawWindow +0x002094 memset +0x0020f4 CtlStartUp +0x002104 NoteAlert +0x002120 StopAlert +0x00213c EMStartUp +0x00215b GetNextEvent +0x002172 FMStartUp +0x002182 LEStartUp +0x002192 LoadOneTool +0x0021a2 NewHandle +0x0021c8 MenuStartUp +0x0021d8 HiliteMenu +0x0021e8 InsertMenu +0x0021fd NewMenu +0x002217 QDStartUp +0x00222d GetPort +0x00223d GlobalToLocal +0x00224f LineTo +0x00225f MoveTo +0x00226f SetPenSize +0x00227f CloseWindow +0x002291 FrontWindow +0x0022a1 GetWRefCon +0x0022bb NewWindow +0x0022d5 StartDrawing +0x0022e7 TaskMaster +0x0022fe startdesk +0x0026e4 paintDesktopBackdrop +0x002716 __jsl_indir +0x002719 __mulhi3 +0x002738 __umulhisi3 +0x00278f __ashlhi3 +0x00279e __lshrhi3 +0x0027ae __ashrhi3 +0x0027c1 __udivhi3 +0x0027cd __umodhi3 +0x0027d9 __divhi3 +0x0027f3 __modhi3 +0x00280d __divmod_setup +0x002840 __udivmod_core +0x00285e __mulsi3 +0x002917 __ashlsi3 +0x00292c __lshrsi3 +0x002941 __ashrsi3 +0x00295b __udivmodsi_core +0x002993 __udivsi3 +0x0029a7 __umodsi3 +0x0029bb __divsi3 +0x0029e2 __modsi3 +0x002a09 __divmodsi_setup +0x002a5a __divmoddi4_stash +0x002a77 __retdi +0x002a84 __ashldi3 +0x002aa7 __lshrdi3 +0x002aca __ashrdi3 +0x002af0 __muldi3 +0x002b4b __ucmpdi2 +0x002b74 __cmpdi2 +0x002bab __udivdi3 +0x002bb4 __umoddi3 +0x002bcd __udivmoddi_core +0x002c1a __divdi3 +0x002c39 __moddi3 +0x002c66 __absdi_a +0x002c6e __absdi_b +0x002c76 __negdi_a +0x002c94 __negdi_b +0x002cb2 setjmp +0x002cda longjmp +0x002d04 __umulhisi3_qsq +0x003102 __rodata_start +0x003102 __text_end +0x003102 gChainPath +0x003116 editMenuStr +0x00316f fileMenuStr +0x0031aa appleMenuStr +0x0031c6 gWindows +0x00382e gTitle0 +0x003837 gTitle1 +0x003840 gTitle2 +0x003849 gTitle3 +0x003852 gAboutMsg +0x003895 doAlert.okStr +0x00389a doAlert.button +0x0038b2 doAlert.message +0x0038ca doAlert.alertRec +0x003908 sketch.fullMsg +0x00393a __init_array_end +0x00393a __init_array_start +0x00393a __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 +0x00a000 gEvent +0x00a02c gDone +0x00a02e doNew.wp +0x00a07c gUserId +0x00a07e gDpHandle +0x00a082 gDpBase +0x00a084 __indirTarget +0x00a086 __bss_end +0x00a086 __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 +CloseWindow = 0x00227f +CtlStartUp = 0x0020f4 +EMStartUp = 0x00213c +FMStartUp = 0x002172 +FrontWindow = 0x002291 +GetNextEvent = 0x00215b +GetPort = 0x00222d +GetWRefCon = 0x0022a1 +GlobalToLocal = 0x00223d +HiliteMenu = 0x0021d8 +InsertMenu = 0x0021e8 +LEStartUp = 0x002182 +LineTo = 0x00224f +LoadOneTool = 0x002192 +MenuStartUp = 0x0021c8 +MoveTo = 0x00225f +NewHandle = 0x0021a2 +NewMenu = 0x0021fd +NewWindow = 0x0022bb +NoteAlert = 0x002104 +QDStartUp = 0x002217 +SetPenSize = 0x00226f +StartDrawing = 0x0022d5 +StopAlert = 0x002120 +TaskMaster = 0x0022e7 +__absdi_a = 0x002c66 +__absdi_b = 0x002c6e +__ashldi3 = 0x002a84 +__ashlhi3 = 0x00278f +__ashlsi3 = 0x002917 +__ashrdi3 = 0x002aca +__ashrhi3 = 0x0027ae +__ashrsi3 = 0x002941 __bss_bank = 0x000000 -__bss_end = 0x00a058 +__bss_end = 0x00a086 __bss_lo16 = 0x00a000 __bss_seg0_bank = 0x000000 __bss_seg0_lo16 = 0x00a000 -__bss_seg0_size = 0x000058 +__bss_seg0_size = 0x000086 __bss_seg1_bank = 0x000000 __bss_seg1_lo16 = 0x000000 __bss_seg1_size = 0x000000 @@ -157,67 +185,75 @@ __bss_seg2_size = 0x000000 __bss_seg3_bank = 0x000000 __bss_seg3_lo16 = 0x000000 __bss_seg3_size = 0x000000 -__bss_size = 0x000058 +__bss_size = 0x000086 __bss_start = 0x00a000 -__cmpdi2 = 0x0020aa -__divdi3 = 0x002150 -__divhi3 = 0x001d0f -__divmod_setup = 0x001d43 -__divmoddi4_stash = 0x001f90 -__divmodsi_setup = 0x001f3f -__divsi3 = 0x001ef1 +__cmpdi2 = 0x002b74 +__divdi3 = 0x002c1a +__divhi3 = 0x0027d9 +__divmod_setup = 0x00280d +__divmoddi4_stash = 0x002a5a +__divmodsi_setup = 0x002a09 +__divsi3 = 0x0029bb __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 +__heap_start = 0x00a086 +__indirTarget = 0x00a084 +__init_array_end = 0x00393a +__init_array_start = 0x00393a +__jsl_indir = 0x002716 +__lshrdi3 = 0x002aa7 +__lshrhi3 = 0x00279e +__lshrsi3 = 0x00292c +__moddi3 = 0x002c39 +__modhi3 = 0x0027f3 +__modsi3 = 0x0029e2 +__muldi3 = 0x002af0 +__mulhi3 = 0x002719 +__mulsi3 = 0x00285e +__negdi_a = 0x002c76 +__negdi_b = 0x002c94 +__retdi = 0x002a77 +__rodata_end = 0x00393a +__rodata_start = 0x003102 __start = 0x001000 -__text_end = 0x002638 +__text_end = 0x003102 __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 +__ucmpdi2 = 0x002b4b +__udivdi3 = 0x002bab +__udivhi3 = 0x0027c1 +__udivmod_core = 0x002840 +__udivmoddi_core = 0x002bcd +__udivmodsi_core = 0x00295b +__udivsi3 = 0x002993 +__umoddi3 = 0x002bb4 +__umodhi3 = 0x0027cd +__umodsi3 = 0x0029a7 +__umulhisi3 = 0x002738 +__umulhisi3_qsq = 0x002d04 +appleMenuStr = 0x0031aa +doAlert.alertRec = 0x0038ca +doAlert.button = 0x00389a +doAlert.message = 0x0038b2 +doAlert.okStr = 0x003895 +doNew.wp = 0x00a02e +drawWindow = 0x001eee +editMenuStr = 0x003116 +fileMenuStr = 0x00316f +gAboutMsg = 0x003852 +gChainPath = 0x003102 +gDone = 0x00a02c +gDpBase = 0x00a082 +gDpHandle = 0x00a07e +gEvent = 0x00a000 +gTitle0 = 0x00382e +gTitle1 = 0x003837 +gTitle2 = 0x003840 +gTitle3 = 0x003849 +gUserId = 0x00a07c +gWindows = 0x0031c6 +longjmp = 0x002cda main = 0x0010ba -memset = 0x001618 -menuTitles = 0x00264c -optsTitle = 0x00266b -paintDesktopBackdrop = 0x001c1a -paintMenuBarTitles = 0x001b5e -setjmp = 0x0021e8 -startdesk = 0x0017a7 +memset = 0x002094 +paintDesktopBackdrop = 0x0026e4 +setjmp = 0x002cb2 +sketch.fullMsg = 0x003908 +startdesk = 0x0022fe diff --git a/demos/minicad.o b/demos/minicad.o index 717c10ab8119cf51db11ca0ba788ff1d6533a213..d37a62a2dfc5bc4bae392d240c090fe21eab899f 100644 GIT binary patch literal 11028 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 diff --git a/demos/minicad.omf b/demos/minicad.omf index 3cbb43eab8e748742539d99d5b90f27110886b00..d2a4d3b8736d462f5f0c0c2aac04b08d824a665e 100644 GIT binary patch literal 38870 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 Y4O`kEBrWL$NM6h+L~@|l^S#Lb0qc0IO#lD@ delta 3645 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 BDJK8` literal 1732 zcmYk-O-R&17{~F+-AuFcjijU~f<=k~J4j{HyNkhAtEd@TSz%I9*bBYOh8H~)xFkd& zK_Q4#(7_P81RWHVAPCD#5G`E{mPiT;ioSpT&(QBM%!l7T&*;t!v;EGwwG7wqTn^KE zMvFO)pOuCAUU3s{wwgmYvBrGa-+o zS4zHB^0?&nlDA3TDftD-yCv_F{I28=B_EM|RPqeIWaqnz%Qdh#yaQGE_>$1=__oyy z;wzSqO8unNf0UX?^#A^>#D3qZC9jn{DQ*>?l=}0M-xT+X)A)v+^``mGoie{--f#En z9sXc<{u54G{u4Ktm*zRwXs*P*w+8>Q-a5(8;Xcb#lBdPb@r2d9kbGS7DakW<*y^)V zGbc3#`Me8OQ-=Ne71;mJ8}XRc)JV-vscDcr!8_r5A7Fpa-{MmCh+}s9cw_u~mBQ5} z;hQ!f{);bjuefS%A+vW8-felQ(7ecb05=;VEtL~cf7qY%zsF}oXqDd zu#-K-_AT_KEdqQIgOuM-o@;DuVdfa ojeYMe?0fHF-}^{Bf+rcl{sg}RZH(aTlFUcVjm#b97UnbNe}9*i5dZ)H diff --git a/demos/orcaFrameLike.bin b/demos/orcaFrameLike.bin deleted file mode 100644 index 6aee66e89dc36868bc1acf6f031d3e8446b0a820..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4249 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 A)Bpeg diff --git a/demos/orcaFrameLike.c b/demos/orcaFrameLike.c deleted file mode 100644 index 19529fe..0000000 --- a/demos/orcaFrameLike.c +++ /dev/null @@ -1,160 +0,0 @@ -// 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; -} diff --git a/demos/orcaFrameLike.map b/demos/orcaFrameLike.map deleted file mode 100644 index ca1df87..0000000 --- a/demos/orcaFrameLike.map +++ /dev/null @@ -1,183 +0,0 @@ -# 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 diff --git a/demos/orcaFrameLike.o b/demos/orcaFrameLike.o deleted file mode 100644 index d24b87575177a78cebd367c13c796df6496f8370..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1416 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 diff --git a/demos/orcaFrameLike.reloc b/demos/orcaFrameLike.reloc deleted file mode 100644 index 074de1e31b4a0a7badec23e898102a909653b67c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 868 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 A!vFvP diff --git a/demos/orcaMiniCadLike.c b/demos/orcaMiniCadLike.c deleted file mode 100644 index 66b35a3..0000000 --- a/demos/orcaMiniCadLike.c +++ /dev/null @@ -1,155 +0,0 @@ -// 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; -} diff --git a/demos/orcaMiniCadLike.map b/demos/orcaMiniCadLike.map deleted file mode 100644 index e4d6c53..0000000 --- a/demos/orcaMiniCadLike.map +++ /dev/null @@ -1,201 +0,0 @@ -# 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 diff --git a/demos/orcaMiniCadLike.o b/demos/orcaMiniCadLike.o deleted file mode 100644 index a72980ab91b2f441155be703fd4d32018699d5f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2304 zcma)8UuauZ82^&n>^6(Fn_X#2smm;r`moz1UH@zYshjQk&=tov`=ZEAa+h72x z&7!jy3o;Pv(^LezT?R`ZhRg?rvChp0jWQVw1wkae+vAa=w+f( zwfYG~9;~fZBF&3bB9hvdtkrDv#v)yAdLK~_Hi$OH2*qxw$!@;vO*0o`uSV zg;l6aL>DVe?`C?pOINEd*Uen_R<4V=F2P+{fm_D^F3MXXUU%`zU|x{l2)s1H%p_xk z%36xbg`&?<6yH61i^%aUI|`Rr1EnXa7%Ii77%ZKmqUwakOTBIrjympyL_3ZeHvg@{ z7z~@e@N`09vl(GdsC=I8ZRR=@HhU;+`Z*(!iC%+(Dt1C$b~?9gg%et+I6<*B7b~9f zd8HU~LpnrAhX?_ymVEqRwH&zw^eMj>F1FlEH8lWLrFCHnI>8>b*zN?B_I2X!v3jkq zMoJ&PH-pz5L6WO@8cx6m(;}b+0WItFh(5dm@fNunx5hS6W1FloY@)<~qnccr>#$Qe z>=X`8V6#m}-Nc(Mw+ippN4LCKYgy%%UDa(_yjjE+gLuQF9y4?1k>{Q#N@nz2Ix=hI z3#OHe#QU|V7EPOWr1y+%&lC>!^+7rFYC=m|*}hC>HoGrt6>30Z&*ad7;beboe{Asd zP(0CpU?4d-Fq{||h{jX#;g}v9jQ0-@>514gc<$D5sZMR8hqZgjw1U5b(mo04qX2y* z^`OwVNzD}s?Da#TZ8Rl`AN)j5Am2-M4m*Ig2EG1U!1lKr?A;Cevkm%agTC0HhZ^)2 z=t{Fo@*QeIo$ZiOiF+XV8O+BZPhk4dCWpL;sqjW%yo||w6J&<5+!|Z*W03DiJP!G> z#O!umVjKnfLgK@aD-w@D-jPWCuL3LEnI-xYll%G$ z@*!pb_&8p`KfsFIC_i-NF%TGCjCsQ__A-9l#YcfT&o0PG=38C<_Ckh2hPtDLVYt}ev(S(^}q2-N? zE+Vz8Zsw?9>v=n66sAebS+=1aojkP&-xjhlsd=rIB?}U9a}0!2Uf=N z*pmDE>)LqbbIs#8W}_e9ZEtw_CO~k^h%_uh`5i_+dR!0N_*e~K@?G+3+z!Cs8gF>1 zzXHLz>;2@_6RzHK_ewv$zdYIykaeM0*^lRGDFumT-b*YAFW)S5Wuj`a3!7fY260XD b3W;3I-@x>0Wu5cwKoZWw|I%>3e4PISy{V_s diff --git a/demos/orcaMiniCadLike.omf b/demos/orcaMiniCadLike.omf deleted file mode 100644 index 789963e557d6837fadb889fc4a3327c78f0239bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37835 zcmeH~dwf$>w#WBLPM&?8mbRo6N(ePlMFa+&@)#zRQd5M=qoSyzg-Mx)A_K_v@~olh zDUY!>fFpv6A*ZL)bi@meSA~lRwIDDK6Sxcl*KtnIq?wSL8%nL6(#w#$_StPg_bR4e_CbvwHL~6349Aps1Wa3Z*qDOUkwfMHGC~77qWLDph*2-KUOWH86%YdOCgVb_+snP_wHD z!C&!cvtRGE)DJ@I)~)liUiS#_2qSoD8!!8JSYTqiB!7|DJsi7-6L&lgKD*aF4Eu)N z;nRBE+1Qt@_{5_SwoFx5==FP1U4hr1j_PdQx~X31yw2kFpF(wJ7_!x=y#5kYhrE#L zM_x;3I&!PGxfwyNW&-N!=aIlP3u?=e^uCAYbmY%L?gamMi*f!=S?W7I_2I|_6$r} zho?*=nKG=bEe^SELv?@v_obQ+{Ug9r`0k>MbU~Fdh~20C{;)6mE}edtW>Wgf)ynup!Euu9_)Up+fm3Q`+I=bmj;ZLq z>!m*Su3GGr@3rP*Ck@mlRefys-Jax}A9xae;2A#PxwA)Ka(`b0emcN+>!4kwtqQlM zuEYz=W4Cu@9E0=agG&bKEG2NT;N#Y8bF2MxyzW8xxRbpkXp|G;pXYU_VsGCDQty(Q z1x^3<(D*%YxZy;&RIukcc=oB47w#|d+69B19N*Q-TLj%Cw+{Sp6KLEiCMRNGqozPM zWAFL`;WMwa2iHQXC9d3G(3wv+P|l}U9({(}9wYH25R<5wE=KK7MwY4YPTYhqdBB@J z;DuAGb|*m#DtLVow4sJ(Ejf^av$@-GYG@Vi8N@z|;Yvap zd^O?e!Rdo}TgLQN%NVF;_hk(9l1aS2OvM8;uSa{^{PC1}6&O$~QCgzRL|KT+CCW;a zji>^m3W+Krs*I?`L^+6BLX?ZBYNBe0swK)xl#i$eq8f=hMpO$?twfz9N+L=oDo9j_ zDD*Cw9~eA8qO?SriLwxtOO%x;8&L&B6%tiMR2fl=iEV+$fHP_ua`9vCS~rk}IM=1*NYyevxje`PtgI36EjY!>DGf4Fj>ZY3$? z2sy$~%!G?2nZytj3yI zaxFbm{cXIG4?+2``AC)+x#KxnY2KOz&I=JSmZw4;h6-p3f4x*z^p8Ygg!%r6BL-zX zoL!6=)QFGu=fEqp{R74D!|3)vxXcl8M1366hOAL-M2wyYdvy8jVLlp)oC!qAc&S!~ z_JV?zhuJ$KqTG=#h60=@H3n-XJ}AnKp<2vA4m<_^(W0aY_ERkn5~=_#zdblWHQZ0t z%OO$fgQ;K?Bjq7J0*H0mpf$85(AF3c!0j^?=T4UO<6&B<~$TK*g z1z15(O1>Cv5Av`U?IAuEf*+q3z6Z_x)sQ>-At13YCc+By+3+ZK;PuTA!+i_Phs6jy zI^joaL`fY8gT>Aeqy1s<%D%9eQq9qUrzgSs4;4G`@^^?*f2<_ReX%mEWKhuaA-o?T z5O0SLG1wm%6hnQ1Au^4=Xu-&bg+x9gB=b>$<6~uF2&XlPa`OOJGC4utbPTqCqCyNW zWA(Lobs&D{M(PhK3M~mLym83>dxfNkA>)#PsA#-;bKHC}+tKOha&$X-yf!3;X2RwR zF2y@>DL%hT;c#Y|#Ln_C-zj#LNBAzWyFAKwi#_Erz6UQKUdAnflVT@qoGwV|hTI-L zR6QD(7DFduflM)YA_{w4J`o8RMd?I1z{1b1N)PK-p-Q+uE0w@v*m@yY12D1wbDFt$ zSoP<(ARiun&_VO9J7(6;&)RA2vUXd0^2JU#mc3$EdxXC!cDG0QTVhXp%#*?Qh__&V zH({o|FlWiYARadNXJty4Gh%trV6RyoW{wQQFYWD6n>&Y9PsL4$p}Pj}V$vU+dP@v( zIIT>Kf#q__@&QA;#7o%7$`5!r1VOAqe29#O`7qWIK7vh@k75&pt;0)jORMpJ0NW*j z@v6YcW`Y_6{jApE>F>N53( z`c?XU`hXr8#u^qGb{JX>-G)5lb4HJ`)p)}=Cc%-gC*fRzKGBxACh=fmBr!MX`J~-R z7m~Q-S;Z#%&_~pT^gVRilOb1LTYfjd_tj?^$A#V)1I%G<=Cp(xu zap-G9gF`0`+deEj%$DkbYHRcJu7$r>iaL>KXp{YC}ZBryi0ku2bvy8eQ@1_!3Rr59~zzekmsSB4>`wN z98>u42M>=J>lus2tr*ufZr=FT@sIw<|D&N3JQLVQ);S;U~2}VW(D4Wq#`VDYCh2%(UuhY(Z^-Vfw4nxx&{Avu5m_ zkz3SUH14ra9<$j`+2emYnE7larzg_Dmdqd&V@^FEp4crx$OF~H(#_Z4=>;T%SkJO zD_&bUaaC}Y=cOsDudaUMp9){@e0kqL&sl@k9$33*UE2EA^)GM8+xYcHPgUV7H(q() z<=8Z&`dsxEx2>k9<{-bcHh1$kn|E(1-O6qIa@*El6}`&VwbX5T%~p>*$2^<17wlkn zp4_?h^;y5>-nj6_?p@EnnY%l(`{156Z`t0~zjN-LJ$oJRj`7~`w(j%zo)hvKx*J-> z9gT~AGqwr&1O9!@tA1PfUgrL*`;WZu`4`85i3gKE2!3$*ciTU#_*dIUrjM_GeCCse zLsf?t{@a8j+^5k`PakdktmfF_goGLy&`V9B`uHRq&^5`EL z&TjkT%D~g-Z0AS)d+LSW3&B5~y?E%WhD)By8?HG2W5L&je;)tMh`(?WYU^lglh6OP zHTY4xKlJwBJmH$FYa`45(-D23`>X5^orKwg1iD zRQ-dwm4+Ukzi@u(jM)#*FP%28bj%a;iXYR>b}n~LpH_%(2Ku1{C;>`<5}*Vq0ZM=p zpaduZN`Mle1SkPYfD)htC;>`<5}*Vq0ZM=ppaduZN`Mle1SkPYfD)htC;>`<5}*Vq z0ZM=ppaduZN`Mle1SkPYfD)htC;>`<5}*Vq0ZM=ppaduZN`Mle1SkPYfD)htC;>`< z5}*Vq0ZM=ppaduZN`Mle1SkPYfD)htC;>`<5}*Vq0ZM=ppaduZN`Mle1SkPYfD)ht zC;>`<5}*Vq0ZM=ppaduZN`Mle1SkPYfD)htC;>`<5}*Vq0ZM=ppaduZO5p!Hf$vl( z414tDjyZzO5vCcNKQVi-`3tiR8@)=x=6%&!7SeMyB{(l%Q-akD%^Y0w zSu$nW%s!j;GRwl?r`JoN3yrIApL^DK?6zhlrY?&B5=RL!3_%=Zo5F zYH+S0&aK3`Q#%Gn?j=rvI6oxHrB~j!QxD`-=!D*t4CV?kg@z*rP;-b`VAzV)LZVg> z^%7CpMkQ}7F+&r+GD757V)7IC1W=QSdV#3LM7@}J5s#fB<~lK>k`(8INySMpHjbzX tMC~FAA+PEeg3z8&}OO%CDk`NnBVoHj#ri8_m5(|kE%`D`SjZ!S6$U+uM zE-Trflw3B-M)(8x{+j3HUA&#oJiYJvoz9#==UgS_R-8*_siq=w2j0j} zI2Lj)g>{TNp#n##Y0b_XU*YVuL{CnVb0O`MhnE=)W(#nt@^T#0KDD?*c`NReBRE|i z!EN$5Zk40BMV`XV@+>Zu=W&U=gp=hs_V=@9yotY46K6ier}8P@lkf1l{EQdn5SRTT z@8cV}jJxU9cN+sMZ^vQf1GqNL{0{c7Gj7ClRFF5Be8}X(CLhgq?q2=Z#$U!2 zIsZLXxQhz*uQz#v$yZIjjo+xCe~0x$-evXs9N=%|$E^N5XV}l4V?TR|{p=I=v+u^A II8Xn}AM%lJX#fBK diff --git a/demos/orcaReversiLike.bin b/demos/orcaReversiLike.bin deleted file mode 100644 index 6aee66e89dc36868bc1acf6f031d3e8446b0a820..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4249 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 A)Bpeg diff --git a/demos/orcaReversiLike.c b/demos/orcaReversiLike.c deleted file mode 100644 index 0951e7f..0000000 --- a/demos/orcaReversiLike.c +++ /dev/null @@ -1,136 +0,0 @@ -// 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; -} diff --git a/demos/orcaReversiLike.map b/demos/orcaReversiLike.map deleted file mode 100644 index 22d3a8a..0000000 --- a/demos/orcaReversiLike.map +++ /dev/null @@ -1,183 +0,0 @@ -# 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 diff --git a/demos/orcaReversiLike.o b/demos/orcaReversiLike.o deleted file mode 100644 index 23818237fd6602f55f2c39f3e19f40e44a302597..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1420 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 diff --git a/demos/orcaReversiLike.reloc b/demos/orcaReversiLike.reloc deleted file mode 100644 index 074de1e31b4a0a7badec23e898102a909653b67c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 868 zcmYk3F(`y#7{?#yI_DS^C5wScl#)7SxH5>`V9}*08I;X%MHZ9JV7T>euwCj(F-h`u zE%?a&tN0(`p`=;UGsAG)IVpZxd>%gad_gj6k}1M_o;i?ASu$0);hCCb>XNwC^0aT-EdxAr??CxuCek-|exRq3j^~1~uuL8SRLILldhYh&kz0v%tcc zn#Z*|KcISrIIL6zSSC(4(Dc?F!0(uMna-tAl^Ima0T-d72#t&A60F>o^=mt}*+QG* z9ozIDtY6&Omh~^*)t2>Z`+*K@i$)j80?-sQxQPUJ6$cs%wfa*e~!O~+FXu2*H)rR=*%l~ZE>Hloi>IWv#Y&-`+ zDzPjJOl-b|%|Z}$OiXO{0_)1yQR_uutYA3D)xXzu@xP66=dn!&`f#J2h0-m)isSLz zICzVP>km1ctL`1q5rm6u#B^u8A&3<+jo`@Wr8Su0-e?^z;q3^u=>1Pi5kPxOXnsNcJ;(Y7H*h7$>kKelEMu8XI&!KQpICD(XReQeluNr6TN>o*X$o= Y)lcqe*wt=ccG2Fz?`&$Ru;Zcp8%#4rVE_OC delta 715 zcmaKoO=uHQ5XWb;*=#mxLYmKQO5imfG{+v)(u4J)pmz~J4hj(x_M&(ZFUCB!q99Ft z2R+H^+?^Noy)szkTR%6lU#DKs6f(Rc#BX!d27Z zn(5kOK!Qu|J8i<%ELGPPu4Spll|`!5Hwy7Lak!3;s&_CrDPr?d_H+ffmfxJ@cE}cz zU1IZdLLjB;zsFs!8C=KAA?iBu54vfFKVZ7%k~#38>1oGI+N^jc4gBMNrjbJC8w`YaJPO zd~~IWJ9>^ys8W40W-b4$g13EOFriqP=#1$KXW_Fy=07nWXG3ekUHBE9Vdn#-`IAX8 zFw7qJn|*@%t3fhJ6mJJ&Sn$C}D`ABX}DBEQQ6W{+TO=yge?QLr`F{hAs|?Zr diff --git a/demos/qdProbe.c b/demos/qdProbe.c index 45660be..f8c47e7 100644 --- a/demos/qdProbe.c +++ b/demos/qdProbe.c @@ -45,19 +45,32 @@ int main(void) { *(volatile unsigned char *)0x80 = 0xA1; unsigned short userId = MMStartUp(); + // QD needs $200 bytes (own DP + cursor mgr at +$100), EM at +$200. + // masterSCB = $90 (640 mode, color burst OFF) avoids the NTSC chroma + // simulator turning the WM's dithered desktop pattern into red/green + // noise. See runtime/src/desktop.c for the full layout. void *dpH = NewHandle(0x400UL, userId, 0xC015, (void *)0); unsigned short dp = blockAddrLo(dpH); *(volatile unsigned char *)0x81 = 0xA2; - QDStartUp(dp, 0x80, 640, userId); + QDStartUp(dp, 0x90, 640, userId); *(volatile unsigned char *)0x82 = 0xA3; + // Match runtime/src/desktop.c's palette setup so the WM's dithered + // desktop fill renders as a clean B/W stipple instead of chroma. + 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; + } + } // 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); + EMStartUp((unsigned short)(dp + 0x200), 20, 0, 0, 639, 199, userId); *(volatile unsigned char *)0x83 = 0xA4; SchStartUp(); @@ -75,10 +88,9 @@ int main(void) { 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"); - } + // Spin to let the WM emit any deferred paint AND give snapshot + // tools time to capture the post-paint state. + for (volatile unsigned long s = 0; s < 300000UL; s++) { } *(volatile unsigned char *)0x86 = 0xA7; *(volatile unsigned char *)0x70 = 0x99; diff --git a/demos/qdProbe.map b/demos/qdProbe.map index e649d11..0978ede 100644 --- a/demos/qdProbe.map +++ b/demos/qdProbe.map @@ -1,11 +1,11 @@ # section layout -.text : 0x001000 .. 0x001d0c ( 3340 bytes) -.rodata : 0x001d0c .. 0x001d20 ( 20 bytes) +.text : 0x001000 .. 0x001ffe ( 4094 bytes) +.rodata : 0x001ffe .. 0x002012 ( 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 + 1259 /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 @@ -13,7 +13,7 @@ 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 + 1349 /home/scott/claude/llvm816/runtime/desktop.o 2540 /home/scott/claude/llvm816/runtime/libgcc.o # global symbols (sorted by address) @@ -33,58 +33,58 @@ 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 +0x0015a5 EMStartUp +0x0015c4 NewHandle +0x0015ea QDStartUp +0x001600 RefreshDesktop +0x001612 __jsl_indir +0x001615 __mulhi3 +0x001634 __umulhisi3 +0x00168b __ashlhi3 +0x00169a __lshrhi3 +0x0016aa __ashrhi3 +0x0016bd __udivhi3 +0x0016c9 __umodhi3 +0x0016d5 __divhi3 +0x0016ef __modhi3 +0x001709 __divmod_setup +0x00173c __udivmod_core +0x00175a __mulsi3 +0x001813 __ashlsi3 +0x001828 __lshrsi3 +0x00183d __ashrsi3 +0x001857 __udivmodsi_core +0x00188f __udivsi3 +0x0018a3 __umodsi3 +0x0018b7 __divsi3 +0x0018de __modsi3 +0x001905 __divmodsi_setup +0x001956 __divmoddi4_stash +0x001973 __retdi +0x001980 __ashldi3 +0x0019a3 __lshrdi3 +0x0019c6 __ashrdi3 +0x0019ec __muldi3 +0x001a47 __ucmpdi2 +0x001a70 __cmpdi2 +0x001aa7 __udivdi3 +0x001ab0 __umoddi3 +0x001ac9 __udivmoddi_core +0x001b16 __divdi3 +0x001b35 __moddi3 +0x001b62 __absdi_a +0x001b6a __absdi_b +0x001b72 __negdi_a +0x001b90 __negdi_b +0x001bae setjmp +0x001bd6 longjmp +0x001c00 __umulhisi3_qsq +0x001ffe __rodata_start +0x001ffe __text_end +0x001ffe gChainPath +0x002012 __init_array_end +0x002012 __init_array_start +0x002012 __rodata_end 0x00a000 __bss_lo16 0x00a000 __bss_seg0_lo16 0x00a000 __bss_start @@ -92,18 +92,18 @@ 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 +EMStartUp = 0x0015a5 +NewHandle = 0x0015c4 +QDStartUp = 0x0015ea +RefreshDesktop = 0x001600 +__absdi_a = 0x001b62 +__absdi_b = 0x001b6a +__ashldi3 = 0x001980 +__ashlhi3 = 0x00168b +__ashlsi3 = 0x001813 +__ashrdi3 = 0x0019c6 +__ashrhi3 = 0x0016aa +__ashrsi3 = 0x00183d __bss_bank = 0x000000 __bss_end = 0x00a002 __bss_lo16 = 0x00a000 @@ -121,49 +121,49 @@ __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 +__cmpdi2 = 0x001a70 +__divdi3 = 0x001b16 +__divhi3 = 0x0016d5 +__divmod_setup = 0x001709 +__divmoddi4_stash = 0x001956 +__divmodsi_setup = 0x001905 +__divsi3 = 0x0018b7 __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 +__init_array_end = 0x002012 +__init_array_start = 0x002012 +__jsl_indir = 0x001612 +__lshrdi3 = 0x0019a3 +__lshrhi3 = 0x00169a +__lshrsi3 = 0x001828 +__moddi3 = 0x001b35 +__modhi3 = 0x0016ef +__modsi3 = 0x0018de +__muldi3 = 0x0019ec +__mulhi3 = 0x001615 +__mulsi3 = 0x00175a +__negdi_a = 0x001b72 +__negdi_b = 0x001b90 +__retdi = 0x001973 +__rodata_end = 0x002012 +__rodata_start = 0x001ffe __start = 0x001000 -__text_end = 0x001d0c +__text_end = 0x001ffe __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 +__ucmpdi2 = 0x001a47 +__udivdi3 = 0x001aa7 +__udivhi3 = 0x0016bd +__udivmod_core = 0x00173c +__udivmoddi_core = 0x001ac9 +__udivmodsi_core = 0x001857 +__udivsi3 = 0x00188f +__umoddi3 = 0x001ab0 +__umodhi3 = 0x0016c9 +__umodsi3 = 0x0018a3 +__umulhisi3 = 0x001634 +__umulhisi3_qsq = 0x001c00 +gChainPath = 0x001ffe +longjmp = 0x001bd6 main = 0x0010ba -setjmp = 0x0018bc +setjmp = 0x001bae diff --git a/demos/qdProbe.o b/demos/qdProbe.o index 404b69cadc274867d0b66eec0e0b30d4872d9f8a..7110f4b969d3cc34cc60d4e5db0b83416047c74c 100644 GIT binary patch literal 2308 zcmb7FUuaup6hHaXwRPRPKdtRrXA>_WE2B3}vovXoW8kI%=WveV<4DrGHnd4&}+Td7n>pb;VH%Wx66cC~6G6};8E!3Rw z!u{$lEfd`j+^MYvoKTMlZIBc05n;y|6~+b()lVz)L~DW6ir4!D(dLx!REbiloz8Ea z=F|#NmHb$zIgkh~B2r~W+OKQEhYTx~*ExgZN$t#gcb3R$RROA|Pece_PUQ{usvaZJ zr*mK@q`6abLfttpiJ%h}Mvl1rAj&tm{C3ysZ)nxAhZq7~mR^8U+Hx9zJFn09c*73p z{sc&b+$zIP->B%@CcI_$y)XY~7RMhti;hq9cjw3}d`>^l(hszA+lw+Viyh>&>mi(* z!!X^g2p*=DW;wH1_^k4#n!%N$dhPSdf}A*cGcE)V-i+0URbaMnZ~+v zVx|+Mk;_C6Lv%5G9)fTuxeC2+(~1-_8zn^ zd2if;@Ol%~A#TUIpSGnb<;lpX^dltTD zx2eGq@R^W>x)<7T%ZtkLqN=>^9I6XC?%i}9BGMru9h@L8smkIQd-~pK2c-8vSpr0PpztOzx!|%MZ|K%q-0i53Fe+>HmjEwsZ*m+G8>rt@ZOO$|oQt4fg7TAY9 zm_7jenxslg@MZt^!S8~bz+b`i4J5CB2VPgY1NkS|cgT%>*5~?Mg?v%zQON6HpZd@F zS*`yH`G?ZCARj3GZ%8ld;=Lk}rqa3A@0I=|nc=9&%2t$jL~w)Kil z{7&;$!KN3i8zrkebFPzTnI&r`EyK)wI#(dGP_!-cnJeQ1 zWjmdnCX;95dU|34b2Ld;td~>i!o-Y4FHJmODrPJ*OJ>w4XjD{(kxrE_oi4YcHtIkt+`4RpPUVd{gVTAVot!jsb7`zc zt+PpnH$UbV-tlXJ>ZMXC6|7UR6-KW59%zLBO3&XTO&eh{xgtCxT*mf@xfLBfd;EX8 zqkAO|fCz~5Fv4MVEs4->8_h6I4hfTWp2*%bfxrdBx5yPe80B;k@h-@@hUQF`Yy;6O zABEFRfwX7qCGBl&Vk9-`@}XLZUC4H-ONk$FIF&1M!`rXzpnPjW1R*%P_E@{P&5 zeBhk;v%`;xcP!D(i|3`6&b%TrUNZlj_=Y7^IUx{Za ze~1dncUJs!#k0MtAuj|_w);V!{iUYkpd&${dw`FhVP6CV|EX`6gC~B?w|j&OVNVFV JzWp8a{{;sdq!s`G diff --git a/demos/qdProbe.omf b/demos/qdProbe.omf index c8b7403d904bcb9f35b4d6c13ce1777fb8a6542c..a3a511d7bdf74e220c130d9faa60d34d2a7542af 100644 GIT binary patch delta 1872 zcmaJ=U1%It6h1q%Gug?cO|t1`ce9B*lVKc}T52e1Vp2;$sww#3OH*19Y<)1>eX#A5 z__B4clR`kUGD!VHmQE&SBSK1rincE`Q1a9~gkpW^xTZ@88Wv4O3T{02-klWMCHwN- zZ@%x`d(PQ&Zq5ofXNAQVLb0gkN43T7DZd18&HormzxGGFomWDAo%M7gE5Q71?J7V; zyH!s+xzOREqmU~92E;0ZM$B>vh~b*H?^<@HybX9qMZ4nP)?BlPm@ATN^$^Q7Mu_43 z63XP4V(WPzrpV`>IXtsT`o%HgJR5G*%USun;%nyNu;Yg09dZ9_Hx zY+gZdFOa?`D!$bNB;{JPh$O8l0VK|8jM8o(U7U7Ox(`S@r+X-k0#P|tD8){-Fq$V4 z<$GZPpVH~w`ZReNJER94YC$3)VQHyIlt5`mvL{fwkaPx097!xtQb>}4(uagLKPWQ) z+^#LsfS5dO%T14vbWJSib^hO%o|&~1yUg0keODxzL>2@hx*0l8cVH_ol-mHt$G7%@ z+urZRoG*ltyj334pPu4{U2n!+zf)i=i5#q@NSZyPrpWQK#x;Oe+`jS^ks$+=PP_$ZJA%zmJGy~Uk+!?a#bdA%!Q zVQia~To~SVJ{3!G=(Q`JKm2>RBYb>&yQg)*s|^1Kz0Moq$$=wrZzE?{-LSo`;rWl8 zro{2Ey5VhR1gI&K7(r{vO*RzgVR)_&Z(PS4AFl1(xK3}x8OW77oV!xYxh37zPbTIz zy!D*zPgU^#HCMK)8h+cPuSiKeI^W6t5<6XAm6eb%k#rukoT6|cVo`V}GPrjlsV(;u zey(fm;LJtNoSsN})nl6(xMV-p&Ze|;DRg*`Yoc~BRX9qGUiB&QFWdLFunYg#Yu>+h zH86M9y=n&yd)wPYET*oXQ9k*|Su1wsqaBX~I1UU>02CjIa0;R_!g=@+P#8~NeFL-HYm)B9))BWWVCe27%spu8QKs|b6Ap(v>;pIa8Fh!yU$roR`Qho&FPmd zEO3#-SCNwu)D}7X5RnvQKXLYevkGT_Dic&2Z)I?S!#sy?TbEl=yT;k~oW)hnJ|2o>LJrDzm<%UZm_W_l%(j*{j_08n?W~E$?!8Pc5qOKY4MlqW}N^ delta 1095 zcmaKpK}Zx)7{|Yvx8uyTx~Z$XtFrXmh?Kerl_8`ZimXEvW?-iR1!XT@0tsTbokk-F zjXC5=7snAth>E46Fe8J)Qzn7cA*OBHL`oJ}LyX+MH_w7Pw3pxaf8YQ6fAii>kBige z;@vu-l7<}`z8mOwk^uLd8<2b-p?>3#5H2eYhk8VqoTXy`Y5Jr%Y(#|vjXtQcKZ2&( zKsDJ;f+m@=?wG2cwhMq6X?n|Ts*Gl}L6^?*>V5!1`! zUqU`6+5oMs`3f+%M^fd+HBVDawGY?+d#9=YCgaOsOvLBMYul591MZg<3Ywb0TxloK zN=$*2EYATbrc#${3H1n|$)?%^>;3PC2kjt zQK?44e_%Lj3=}1UzA8O!IR`&^N4whKKWF|VF0n+sXEa%AJX0!-JIbrtuF8pJ zYbmNb{b|h4m_>S);@Jw@;tybHjH(gItx_*kRS-J^#_Mez412x18QQ)3eVqZi7)(6h zq;6phdoP^p3|QHtEA72mv?DlJw{uu8DJo= zLs$?Ir-XHe2SSQrkLV+4sU9e^14o7gnfk)jCJDxv6g;lS_PB#H z98*%4guNM#7m~jS)f`vfxXN+$qo|Yh&dM%g91l1i$%``fo^mzI)h@+#HYmNyF>LNr j`V>T?;#!-PI8#Ts=OlVio#vJ^+!E!MiyW7g5e0q$_A7eJ diff --git a/demos/qdProbe.reloc b/demos/qdProbe.reloc index d89364ff737f3b7ef6c3a8ac4e89afbc7dbb78cf..5795d4ceda549e5adb850ab37d6e490c6115201e 100644 GIT binary patch literal 592 zcmYk2ze|Eq6oyZhmK7v6NK-=)2o1J4H3X69=Ax3|(h{`vW9mO}b+54?XfbGrT3y_l z1gD@e2!eL$x!im39bV4E!+FpB`1Z}LOl)A5VeFAi;u>5mMBfl@!M=YIe9mlV*@Or%26&}F{%h7)bPvCs=Q}Msz z|HR+2>-UGkcPnNc68_In_!Z9Pqkk9wDgI0R54-KOUtgW`mGGnR6Fes2-DmMH;!A7u tJ3H_x3H!Uu^TcJQ->JaY$yb^FJ%_M&k6`cCVDI)|@16-?zylKA{Rb4{ErI|5 literal 592 zcmYk$y-R{o6vy%7TPc`JL!&t~h%G|k))Ybxq4Wao34+VB1TJD*Ykz^et%9I~L4(lh z($*w61&%==eJ{^Bc;Gpl55MP}dv8@l%9Ol{Bx&bVQeDTVM{$1be2;Cu9rBb2pG4H0 z3hq;R-FL7acO{Kw^6m;W*QsPhkpdk>wb&NKW)g?ry!{^9bo u?Eai8j;JtyLGP<;bUWt~KWlzPxA)v&+ihXny~DQK!?ye6JisF=-1`rFsV)@& diff --git a/demos/reversi.bin b/demos/reversi.bin index 9d1209aaf47a0ebf7adca128d4d69391ebf6a437..61849953849be2c9e08c68c3e3c3b305fb5c65cb 100644 GIT binary patch literal 19505 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 Hmo57raRD>K literal 9225 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 diff --git a/demos/reversi.c b/demos/reversi.c index 3c37df6..d29bb66 100644 --- a/demos/reversi.c +++ b/demos/reversi.c @@ -1,47 +1,88 @@ -// reversi.c - port of ORCA-C's Reversi.cc sample. +// reversi.c - faithful 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. +// Mike Westerfield / Barbara Allred, Byte Works 1989. Original at +// tools/orca-c/C.Samples/Desktop.Samples/Reversi.cc. // -// 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 +// Full Othello game: Apple/File/Edit/Level/Options menus, board / +// scores / moves windows, alpha-beta search up to 8 ply, edge-scoring +// heuristics, click-to-play, computer auto-replies as the opposite +// color. Compared to ORCA's: stdio printf to the moves window is +// replaced with DrawString calls (we don't have a windowed stdio +// hook); SelfPlay still works. #include "iigs/toolbox.h" #include "iigs/desktop.h" -#define wInContent 19 +#include + + +#define squareWidth 52 +#define squareHeight 20 + +#define blank 0 +#define blackPiece 1 +#define whitePiece 2 +#define border 3 + +#define apple_AboutReversi 257 +#define file_NewGame 258 +#define file_Quit 259 + +#define edit_UndoLastMove 270 + +#define level_1Ply 262 +#define level_2Ply 263 +#define level_3Ply 264 +#define level_4Ply 265 +#define level_5Ply 266 +#define level_6Ply 267 +#define level_7Ply 268 +#define level_8Ply 269 + +#define options_SelfPlay 280 +#define options_ComputerPlaysWhite 281 +#define options_Pass 282 +#define options_ShowScoreWindow 283 +#define options_ShowMovesWindow 284 + + +#define wInMenuBar 3 +#define wInSpecial 25 #define wInGoAway 17 -#define keyDownEvt 3 +#define wInContent 19 +#define inUpdate 6 -#define fVis 0x0020 -#define fMove 0x0080 -#define fClose 0x4000 +#define norml 0 +#define stop 1 +#define note 2 +#define caution 3 -// Piece-color constants (mirrors Reversi.cc). -#define BLANK 0 -#define BLACK 1 -#define WHITE 2 -#define BORDER 3 +#define buttonItem 10 +#define statText 136 +#define itemDisable 0x8000 -// 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 +#define topMost ((void *)-1L) typedef struct { short v1, h1, v2, h2; } Rect; +typedef struct { short v, h; } Point; + + +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; + typedef struct { unsigned short paramLength; @@ -65,291 +106,729 @@ typedef struct { 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; + short itemID; + short itemRectV1, itemRectH1, itemRectV2, itemRectH2; + unsigned short itemType; + void *itemDescr; + short itemValue; + short itemFlag; + void *itemColor; +} ItemTemplate; + +typedef struct { + short atRectV1, atRectH1, atRectV2, atRectH2; + short atBtnHorz; + short atBeep0, atBeep1, atBeep2, atBeep3; + void *atSound; + void *atResv1; + void *atResv2; + void *atItemList[8]; +} AlertTemplate; -// 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. +typedef struct { + short num; + unsigned char moves[60]; +} MoveList; + + +static short gPly = 1; +static short gColor = whitePiece; +static short gCurrentColor; +static short gMovesMade; +static short gMoves[64]; + static unsigned char gBoard[100]; +static short gMovesLeft; +static short gSelfPlay; +static short gShowScoreWindow = 1; +static short gShowMovesWindow = 1; -// 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; +static const short gDisp[8] = { 9, 10, 11, -1, 1, -9, -10, -11 }; + + +// Compact piece-square table: just one phase, much smaller than the +// original's 300-entry / 3-phase bSc. Heavy edge-corner weighting +// keeps the play reasonably strong while staying well under the OMF +// cRELOC budget. +static const short gSqScore[100] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 500, -20, 100, 50, 50, 100, -20, 500, 0, + 0, -20,-250, -2, -2, -2, -2,-250, -20, 0, + 0, 100, -2, 30, 10, 10, 30, -2, 100, 0, + 0, 50, -2, 10, 2, 2, 10, -2, 50, 0, + 0, 50, -2, 10, 2, 2, 10, -2, 50, 0, + 0, 100, -2, 30, 10, 10, 30, -2, 100, 0, + 0, -20,-250, -2, -2, -2, -2,-250, -20, 0, + 0, 500, -20, 100, 50, 50, 100, -20, 500, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +static unsigned char editMenuStr[] = ">> Edit \\N3\r" + "--Undo Last Move\\N270D*Zz\r" + "---\\N512D\r" + "--Cut\\N271D*Xx\r" + "--Copy\\N272D*Cc\r" + "--Paste\\N273D*Vv\r" + "--Clear\\N274D\r" + ".\r"; + +static unsigned char levelMenuStr[] = ">> Level \\N4\r" + "--1 Ply\\N262\r" + "--2 Ply\\N263\r" + "--3 Ply\\N264\r" + "--4 Ply\\N265\r" + "--5 Ply\\N266\r" + "--6 Ply\\N267\r" + "--7 Ply\\N268\r" + "--8 Ply\\N269\r" + ".\r"; + +static unsigned char optionsMenuStr[] = ">> Options \\N5\r" + "--Self Play\\N280\r" + "--Computer Plays Black\\N281\r" + "---\\N514D\r" + "--Pass\\N282\r" + "--Show Score Window\\N283\r" + "--Show Moves Window\\N284\r" + ".\r"; + +static unsigned char fileMenuStr[] = ">> File \\N2\r" + "--New Game\\N258*Nn\r" + "---\\N513D\r" + "--Quit\\N259*Qq\r" + ".\r"; + +static unsigned char appleMenuStr[] = ">>@\\XN1\r" + "--About Reversi\\N257\r" + ".\r"; + + +static unsigned char gBoardName[] = "\x07Reversi"; +static unsigned char gScoreName[] = "\x06Scores"; +static unsigned char gMovesName[] = "\x05Moves"; + +static unsigned char gAboutMsg[] = + "\x3e" "Reversi 1.0\r" + "Copyright 1989\r" + "Byte Works, Inc.\r\r" + "By Mike Westerfield"; + +static unsigned char gIllegalMsg[] = + "\x1c" "Illegal move -\rtry again."; +static unsigned char gPassMsg[] = + "\x22" "I cannot move, so I\rmust pass.\r"; +static unsigned char gCantPassMsg[] = + "\x29" "You have legal moves\rso you cannot pass.\r"; +static unsigned char gDrawMsg[] = + "\x21" "The game is over. It\ris a draw."; +static unsigned char gWhiteWinsMsg[] = + "\x18" "White wins the game."; +static unsigned char gBlackWinsMsg[] = + "\x18" "Black wins the game."; + + +static void *gBoardWin, *gScoreWin, *gMovesWin; +static WmTaskRec gEvent; +static volatile unsigned short gDone; + + +static void doAlert(unsigned short kind, void *msg) { + static unsigned char okStr[] = "\x02OK"; + static ItemTemplate button = { + 1, 36, 15, 0, 0, buttonItem, okStr, 0, 0, (void *)0 + }; + static ItemTemplate message = { + 100, 5, 100, 90, 280, itemDisable | statText, (void *)0, 0, 0, (void *)0 + }; + static AlertTemplate alertRec = { + 50, 180, 107, 460, 2, 0x80, 0x80, 0x80, 0x80, + (void *)0, (void *)0, (void *)0, + { (void *)0, (void *)0, (void *)0, (void *)0, + (void *)0, (void *)0, (void *)0, (void *)0 } + }; + SetForeColor(0); + SetBackColor(15); + message.itemDescr = msg; + alertRec.atItemList[0] = (void *)&button; + alertRec.atItemList[1] = (void *)&message; + alertRec.atItemList[2] = (void *)0; + switch (kind) { + case norml: (void)Alert(&alertRec, (void *)0); break; + case stop: (void)StopAlert(&alertRec, (void *)0); break; + case note: (void)NoteAlert(&alertRec, (void *)0); break; + case caution: (void)CautionAlert(&alertRec, (void *)0); break; + default: break; } - return 0; } -static unsigned char gTitle[] = "\x07Reversi"; -static NewWindowParm gWp; -static WmTaskRec gEv; +// --- game logic ---------------------------------------------------- -// --- 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; +static void getMoves(const unsigned char *board, short color, MoveList *out) { + short enemy = color ^ 3; + out->num = 0; + for (short idx = 11; idx < 90; idx++) { + if (board[idx] != blank) continue; + for (short d = 0; d < 8; d++) { + short t = (short)(idx + gDisp[d]); + if (board[t] == enemy) { + while (board[t] == enemy) t = (short)(t + gDisp[d]); + if (board[t] == color) { + out->moves[out->num++] = (unsigned char)idx; + break; + } } } } - 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; - } + MoveList list; + getMoves(gBoard, color, &list); + for (short i = 0; i < list.num; i++) { + if (list.moves[i] == idx) 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; +static short score(const unsigned char *board) { + short s = 0; + for (short i = 11; i < 90; i++) { + if (board[i] == whitePiece) { + s = (short)(s - 4 - gSqScore[i]); + } else if (board[i] == blackPiece) { + s = (short)(s + 4 + gSqScore[i]); } } - *(volatile unsigned char *)0x74 = 0xB2; + return s; } -// 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; - } +static short endScore(const unsigned char *board) { + short s = 0; + for (short i = 11; i < 90; i++) { + if (board[i] == whitePiece) s--; + else if (board[i] == blackPiece) s++; } + if (s < 0) return (short)(-32000 + s); + if (s > 0) return (short)( 32000 + s); 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; +// Apply move `index` of color `col` to local board copy and return +// the resulting flips applied (board mutated). +static void applyMove(unsigned char *board, short idx, short col) { + short enemy = col ^ 3; + board[idx] = (unsigned char)col; + for (short d = 0; d < 8; d++) { + short t = (short)(idx + gDisp[d]); + if (board[t] != enemy) continue; + while (board[t] == enemy) t = (short)(t + gDisp[d]); + if (board[t] == col) { + t = (short)(idx + gDisp[d]); + while (board[t] != col) { + board[t] = (unsigned char)col; + t = (short)(t + gDisp[d]); } } } - return best; } -// --- Drawing ------------------------------------------------------------- +static short scoreMove(unsigned char *board, short idx, short col, short level) { + unsigned char lboard[100]; + for (short k = 0; k < 100; k++) lboard[k] = board[k]; + if (idx) applyMove(lboard, idx, col); -// 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)); + if (level >= gPly) return score(lboard); + + short enemy = col ^ 3; + MoveList list; + getMoves(lboard, enemy, &list); + short bscore; + if (enemy == whitePiece) bscore = 32000; + else bscore = -32000; + + if (!list.num) { + getMoves(lboard, col, &list); + if (!list.num) return endScore(lboard); + return scoreMove(lboard, 0, enemy, (short)(level + 1)); } - // 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); + + for (short i = 0; i < list.num; i++) { + short s = scoreMove(lboard, list.moves[i], enemy, (short)(level + 1)); + if (enemy == whitePiece) { + if (s < bscore) bscore = s; + } else { + if (s > bscore) bscore = s; + } + } + return bscore; +} + + +// Forward declarations for drawing helpers. +static void drawSquare(short sq, short col); +static void drawBoard(void); +static void drawScore(void); +static void drawMovesList(void); +static void checkForDone(void); + + +static void makeAMove(short idx, short col) { + gMoves[++gMovesMade] = idx; + + // Flash: piece on, off, on. + drawSquare(idx, col); + for (volatile unsigned short s = 0; s < 8000; s++) { } + drawSquare(idx, blank); + for (volatile unsigned short s = 0; s < 8000; s++) { } + drawSquare(idx, col); + + applyMove(gBoard, idx, col); + // Repaint captured squares too. + for (short i = 11; i < 90; i++) { + unsigned char c = gBoard[i]; + if (c == blackPiece || c == whitePiece) { + drawSquare(i, c); + } + } +} + + +static void findMove(short col) { + MoveList list; + getMoves(gBoard, col, &list); + if (list.num == 0) { + doAlert(note, gPassMsg); + return; + } + if (list.num == 1) { + makeAMove(list.moves[0], col); + } else { + short bscore = (col == whitePiece) ? 32000 : -32000; + short bmove = list.moves[0]; + for (short i = 0; i < list.num; i++) { + short s = scoreMove(gBoard, list.moves[i], col, 1); + if (col == whitePiece) { + if (s < bscore) { bscore = s; bmove = list.moves[i]; } } else { - SetSolidPenPat(15); - PaintOval(&pr); - SetSolidPenPat(0); - FrameOval(&pr); + if (s > bscore) { bscore = s; bmove = list.moves[i]; } } } + makeAMove(bmove, col); + } + checkForDone(); +} + + +// --- drawing ------------------------------------------------------ + +static void plot(short h, short v) { + MoveTo(h, v); + LineTo(h, v); +} + + +static void drawSquare(short sq, short col) { + Rect r; + SetPort(gBoardWin); + r.h2 = (short)((sq % 10) * squareWidth - 1); + r.v2 = (short)((sq / 10) * squareHeight - 1); + r.h1 = (short)(r.h2 - squareWidth + 1); + r.v1 = (short)(r.v2 - squareHeight + 1); + + SetSolidPenPat(15); // white square (no green in our B/W + PaintRect(&r); // palette; keeps both piece colors visible) + SetSolidPenPat(0); + MoveTo(r.h1, r.v2); + LineTo(r.h2, r.v2); + LineTo(r.h2, r.v1); + + switch (sq) { + case 22: case 26: case 62: case 66: + plot((short)(r.h2 - 1), (short)(r.v2 - 1)); break; + case 23: case 27: case 63: case 67: + plot(r.h1, (short)(r.v2 - 1)); break; + case 32: case 36: case 72: case 76: + plot((short)(r.h2 - 1), r.v1); break; + case 33: case 37: case 73: case 77: + plot(r.h1, r.v1); break; + default: break; + } + + if (col != blank) { + if (col == whitePiece) SetSolidPenPat(15); + else SetSolidPenPat(0); + PaintOval(&r); + if (col == whitePiece) { + SetSolidPenPat(0); + FrameOval(&r); + } } } -// --- Click handling ------------------------------------------------------ +static void drawBoard(void) { + for (short i = 11; i <= 88; i++) { + short c = (short)(i % 10); + if (c != 0 && c != 9) drawSquare(i, gBoard[i]); + } +} -// 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); + +// Tiny 5x7 digit glyphs in a 16-byte (8 row × 2 bytes) bitmap so we +// don't need to wire snprintf to a window port. Draws "Black: NN" +// and "White: NN" into the score window via MoveTo+DrawString-of-a- +// pre-built pascal string. +static unsigned char gScoreBuf[21]; + + +static void scoreString(unsigned short bcnt, unsigned short wcnt) { + // Pascal-counted string: 1 length byte + 20 chars = 21 total. + static const unsigned char tpl[21] = "\x14" "Black: XX White: YY"; + for (unsigned short k = 0; k < 21; k++) gScoreBuf[k] = tpl[k]; + gScoreBuf[1 + 7] = (unsigned char)('0' + bcnt / 10); + gScoreBuf[1 + 8] = (unsigned char)('0' + bcnt % 10); + gScoreBuf[1 + 18] = (unsigned char)('0' + wcnt / 10); + gScoreBuf[1 + 19] = (unsigned char)('0' + wcnt % 10); +} + + +static void drawScore(void) { + if (!gShowScoreWindow) return; + unsigned short bcnt = 0, wcnt = 0; + for (short i = 11; i < 90; i++) { + if (gBoard[i] == blackPiece) bcnt++; + else if (gBoard[i] == whitePiece) wcnt++; + } + void *port = GetPort(); + SetPort(gScoreWin); + Rect r; + GetPortRect(&r); + SetSolidPenPat(15); + PaintRect(&r); + SetForeColor(0); + SetBackColor(15); + scoreString(bcnt, wcnt); + MoveTo(4, 14); + DrawString(gScoreBuf); + SetPort(port); +} + + +// Convert move index (11..88) to "A1".."H8" pascal string. +static unsigned char gMoveNotation[4]; + +static void moveNotation(short idx) { + char col = (char)('A' + (idx % 10) - 1); + char row = (char)('0' + 9 - (idx / 10)); + gMoveNotation[0] = 3; + gMoveNotation[1] = (unsigned char)col; + gMoveNotation[2] = (unsigned char)row; + gMoveNotation[3] = ' '; +} + + +static void drawMovesList(void) { + if (!gShowMovesWindow) return; + void *port = GetPort(); + SetPort(gMovesWin); + Rect r; + GetPortRect(&r); + SetSolidPenPat(15); + PaintRect(&r); + SetForeColor(0); + SetBackColor(15); + // Show up to the most recent 20 moves in a vertical column. + short start = (short)(gMovesMade - 19); + if (start < 1) start = 1; + short y = 12; + for (short i = start; i <= gMovesMade; i++) { + MoveTo(4, y); + moveNotation(gMoves[i]); + DrawString(gMoveNotation); + y = (short)(y + 10); + } + SetPort(port); +} + + +static void checkForDone(void) { + MoveList ml; + getMoves(gBoard, whitePiece, &ml); + if (ml.num) return; + getMoves(gBoard, blackPiece, &ml); + if (ml.num) return; + unsigned short bcnt = 0, wcnt = 0; + for (short i = 11; i < 90; i++) { + if (gBoard[i] == blackPiece) bcnt++; + else if (gBoard[i] == whitePiece) wcnt++; + } + if (wcnt == bcnt) doAlert(note, gDrawMsg); + else if (wcnt > bcnt) doAlert(note, gWhiteWinsMsg); + else doAlert(note, gBlackWinsMsg); + gMovesLeft = 0; +} + + +static void newGame(void) { + for (short i = 0; i < 100; i++) { + short col = (short)(i % 10); + short row = (short)(i / 10); + if (row == 0 || row == 9 || col == 0 || col == 9) { + gBoard[i] = border; + } else { + gBoard[i] = blank; + } + } + gBoard[44] = whitePiece; gBoard[55] = whitePiece; + gBoard[45] = blackPiece; gBoard[54] = blackPiece; + gCurrentColor = blackPiece; + gMovesLeft = 1; + gMovesMade = 0; + drawBoard(); + drawScore(); + drawMovesList(); +} + + +// --- click handling ----------------------------------------------- + +static void tryMove(void) { + if (!gMovesLeft) return; + SetPort(gBoardWin); + Point p; + p.h = gEvent.wmWhereH; + p.v = gEvent.wmWhereV; + GlobalToLocal(&p); + short col = (short)(p.h / squareWidth + 1); + short row = (short)(p.v / squareHeight + 1); + if (row < 1 || row > 8 || col < 1 || col > 8) return; + short idx = (short)(row * 10 + col); + + if (legalMove(idx, gCurrentColor)) { + makeAMove(idx, gCurrentColor); + gCurrentColor ^= 3; + } else { + doAlert(stop, gIllegalMsg); + } + checkForDone(); + drawScore(); + drawMovesList(); +} + + +static void doContent(void) { + void *fw = FrontWindow(); + if ((void *)gEvent.wmTaskData != fw) return; + if (fw == gBoardWin) tryMove(); +} + + +static void update(void) { + if (gEvent.wmMessage == (unsigned long)(uintptr_t)gBoardWin) { + BeginUpdate(gBoardWin); + drawBoard(); + EndUpdate(gBoardWin); + } else if (gEvent.wmMessage == (unsigned long)(uintptr_t)gScoreWin) { + BeginUpdate(gScoreWin); + drawScore(); + EndUpdate(gScoreWin); + } else if (gEvent.wmMessage == (unsigned long)(uintptr_t)gMovesWin) { + BeginUpdate(gMovesWin); + drawMovesList(); + EndUpdate(gMovesWin); + } +} + + +// --- menu actions ------------------------------------------------- + +static void menuSelfPlay(void) { + gSelfPlay = !gSelfPlay; +} + + +static void menuColor(void) { + gColor = (gColor == whitePiece) ? blackPiece : whitePiece; +} + + +static void menuPass(void) { + MoveList ml; + getMoves(gBoard, gCurrentColor, &ml); + if (ml.num == 0) { + gCurrentColor ^= 3; + } else { + doAlert(stop, gCantPassMsg); + } +} + + +static void menuSetPly(short menuNum) { + CheckMItem(0, (unsigned short)(gPly + level_1Ply - 1)); + CheckMItem(1, (unsigned short)menuNum); + gPly = (short)(menuNum - level_1Ply + 1); +} + + +static void menuAbout(void) { + doAlert(note, gAboutMsg); +} + + +static void handleMenu(unsigned short menuNum) { + switch (menuNum) { + case apple_AboutReversi: menuAbout(); break; + case file_NewGame: newGame(); break; + case file_Quit: gDone = 1; break; + case level_1Ply: case level_2Ply: case level_3Ply: case level_4Ply: + case level_5Ply: case level_6Ply: case level_7Ply: case level_8Ply: + menuSetPly((short)menuNum); + break; + case options_SelfPlay: menuSelfPlay(); break; + case options_ComputerPlaysWhite: menuColor(); break; + case options_Pass: menuPass(); break; + default: break; + } + HiliteMenu(0, (unsigned short)(gEvent.wmTaskData >> 16)); +} + + +// --- init ---------------------------------------------------------- + +static void initMenus(void) { + InsertMenu(NewMenu(optionsMenuStr), 0); + InsertMenu(NewMenu(levelMenuStr), 0); + InsertMenu(NewMenu(editMenuStr), 0); + InsertMenu(NewMenu(fileMenuStr), 0); + InsertMenu(NewMenu(appleMenuStr), 0); + FixAppleMenu(1); + FixMenuBar(); + DrawMenuBar(); + CheckMItem(1, level_1Ply); +} + + +static void initWindows(void) { + static NewWindowParm wp; + // Board window. + unsigned char *p = (unsigned char *)℘ + for (unsigned short k = 0; k < sizeof wp; k++) p[k] = 0; + wp.paramLength = (unsigned short)sizeof wp; + wp.wFrameBits = 0x80E4; + wp.wTitle = gBoardName; + wp.wMaxHeight = squareHeight * 8; + wp.wMaxWidth = squareWidth * 8; + wp.wDataV = squareHeight * 8; + wp.wDataH = squareWidth * 8; + wp.wPosition.v1 = 32; + wp.wPosition.h1 = 32; + wp.wPosition.v2 = (short)(32 + squareHeight * 8); + wp.wPosition.h2 = (short)(32 + squareWidth * 8); + wp.wPlane = topMost; + gBoardWin = NewWindow(&wp); + + // Score window. + for (unsigned short k = 0; k < sizeof wp; k++) p[k] = 0; + wp.paramLength = (unsigned short)sizeof wp; + wp.wFrameBits = 0xC0C4; + wp.wTitle = gScoreName; + wp.wMaxHeight = 29; + wp.wMaxWidth = 200; + wp.wDataV = 29; + wp.wDataH = 200; + wp.wPosition.v1 = 32; + wp.wPosition.h1 = (short)(640 - 32 - 200); + wp.wPosition.v2 = 61; + wp.wPosition.h2 = (short)(640 - 32); + wp.wPlane = topMost; + gScoreWin = NewWindow(&wp); + + // Moves window. + for (unsigned short k = 0; k < sizeof wp; k++) p[k] = 0; + wp.paramLength = (unsigned short)sizeof wp; + wp.wFrameBits = 0xC0C4; + wp.wTitle = gMovesName; + wp.wMaxHeight = 112; + wp.wMaxWidth = 100; + wp.wDataV = 112; + wp.wDataH = 100; + wp.wPosition.v1 = 80; + wp.wPosition.h1 = (short)(640 - 32 - 100); + wp.wPosition.v2 = 192; + wp.wPosition.h2 = (short)(640 - 32); + wp.wPlane = topMost; + gMovesWin = NewWindow(&wp); + + SelectWindow(gBoardWin); } int main(void) { - *(volatile unsigned char *)0x71 = 0x01; unsigned short userId = startdesk(640); - *(volatile unsigned char *)0x71 = 0x02; (void)userId; + + paintDesktopBackdrop(); + initMenus(); + initWindows(); + newGame(); + gEvent.wmTaskMask = 0x13FFL; 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; + // Marker: init complete and we're entering the event loop. The + // headless test reads $00:0070 to confirm the demo got this far. + // Interactive runs continue to the TaskMaster loop below. + *(volatile unsigned char *)0x70 = 0x99; - *(volatile unsigned char *)0x71 = 0x05; - void *win = NewWindow(&gWp); - *(volatile unsigned char *)0x71 = 0x06; + gDone = 0; + unsigned short watchdog = 0; + do { + unsigned short event = TaskMaster(0x074E, &gEvent); + switch (event) { + case wInSpecial: + case wInMenuBar: + handleMenu((unsigned short)gEvent.wmTaskData); + watchdog = 0; + break; + case inUpdate: + update(); + watchdog = 0; + break; + case wInContent: + doContent(); + watchdog = 0; + break; + case wInGoAway: + gDone = 1; + break; + default: break; + } - initBoard(); - *(volatile unsigned char *)0x71 = 0x07; - (void)&hitSquare; - (void)&gEv; + if (gMovesLeft) { + if (gSelfPlay) { + findMove(gCurrentColor); + gCurrentColor ^= 3; + drawScore(); + drawMovesList(); + } else if (gColor == gCurrentColor) { + findMove(gColor); + gCurrentColor ^= 3; + drawScore(); + drawMovesList(); + } + } + watchdog++; + } while (!gDone && watchdog < 1000); - 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; } diff --git a/demos/reversi.map b/demos/reversi.map index 5d2263c..23b975f 100644 --- a/demos/reversi.map +++ b/demos/reversi.map @@ -1,19 +1,19 @@ # section layout -.text : 0x001000 .. 0x0033dc ( 9180 bytes) -.rodata : 0x0033dc .. 0x003409 ( 45 bytes) -.bss : 0x00a000 .. 0x00a0bc ( 188 bytes) +.text : 0x001000 .. 0x0057d5 ( 18389 bytes) +.rodata : 0x0057d5 .. 0x005c31 ( 1116 bytes) +.bss : 0x00a000 .. 0x00a197 ( 407 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 + 13790 /home/scott/claude/llvm816/demos/reversi.o + 43132 /home/scott/claude/llvm816/runtime/libc.o + 14895 /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 + 1349 /home/scott/claude/llvm816/runtime/desktop.o 2540 /home/scott/claude/llvm816/runtime/libgcc.o # global symbols (sorted by address) @@ -28,126 +28,193 @@ 0x000000 __bss_seg3_bank 0x000000 __bss_seg3_lo16 0x000000 __bss_seg3_size -0x0000bc __bss_seg0_size -0x0000bc __bss_size +0x000197 __bss_seg0_size +0x000197 __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 +0x002056 newGame +0x00221d findMove +0x00264d drawScore +0x0028ff drawMovesList +0x002b01 drawSquare +0x002f25 makeAMove +0x0032c9 checkForDone +0x003ec1 scoreMove +0x004698 memcpy +0x00471a memset +0x00477a CtlStartUp +0x00478a NoteAlert +0x0047a6 StopAlert +0x0047c2 EMStartUp +0x0047e1 FMStartUp +0x0047f1 LEStartUp +0x004801 LoadOneTool +0x004811 NewHandle +0x004837 MenuStartUp +0x004847 CheckMItem +0x004857 HiliteMenu +0x004867 InsertMenu +0x00487c NewMenu +0x004896 QDStartUp +0x0048ac DrawString +0x0048be FrameOval +0x0048d0 GetPort +0x0048e0 GetPortRect +0x0048f2 GlobalToLocal +0x004904 LineTo +0x004914 MoveTo +0x004924 PaintOval +0x004936 PaintRect +0x004948 SetPort +0x00495a BeginUpdate +0x00496c EndUpdate +0x00497e FrontWindow +0x00498e NewWindow +0x0049a8 SelectWindow +0x0049ba TaskMaster +0x0049d1 startdesk +0x004db7 paintDesktopBackdrop +0x004de9 __jsl_indir +0x004dec __mulhi3 +0x004e0b __umulhisi3 +0x004e62 __ashlhi3 +0x004e71 __lshrhi3 +0x004e81 __ashrhi3 +0x004e94 __udivhi3 +0x004ea0 __umodhi3 +0x004eac __divhi3 +0x004ec6 __modhi3 +0x004ee0 __divmod_setup +0x004f13 __udivmod_core +0x004f31 __mulsi3 +0x004fea __ashlsi3 +0x004fff __lshrsi3 +0x005014 __ashrsi3 +0x00502e __udivmodsi_core +0x005066 __udivsi3 +0x00507a __umodsi3 +0x00508e __divsi3 +0x0050b5 __modsi3 +0x0050dc __divmodsi_setup +0x00512d __divmoddi4_stash +0x00514a __retdi +0x005157 __ashldi3 +0x00517a __lshrdi3 +0x00519d __ashrdi3 +0x0051c3 __muldi3 +0x00521e __ucmpdi2 +0x005247 __cmpdi2 +0x00527e __udivdi3 +0x005287 __umoddi3 +0x0052a0 __udivmoddi_core +0x0052ed __divdi3 +0x00530c __moddi3 +0x005339 __absdi_a +0x005341 __absdi_b +0x005349 __negdi_a +0x005367 __negdi_b +0x005385 setjmp +0x0053ad longjmp +0x0053d7 __umulhisi3_qsq +0x0057d5 __rodata_start +0x0057d5 __text_end +0x0057d5 gChainPath +0x0057e9 gColor +0x0057eb optionsMenuStr +0x005874 levelMenuStr +0x0058ee editMenuStr +0x005961 fileMenuStr +0x0059a0 appleMenuStr +0x0059c0 gBoardName +0x0059c9 gScoreName +0x0059d1 gMovesName +0x0059d8 gAboutMsg +0x005a1a doAlert.okStr +0x005a1f doAlert.button +0x005a37 doAlert.message +0x005a4f doAlert.alertRec +0x005a8d gPly +0x005a8f gCantPassMsg +0x005aba gIllegalMsg +0x005ad5 gDrawMsg +0x005af7 gWhiteWinsMsg +0x005b0d gBlackWinsMsg +0x005b23 gPassMsg +0x005b44 gDisp +0x005b54 gSqScore +0x005c1c scoreString.tpl +0x005c31 __init_array_end +0x005c31 __init_array_start +0x005c31 __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 +0x00a000 gEvent +0x00a02c gDone +0x00a02e gMovesLeft +0x00a030 gSelfPlay +0x00a032 gCurrentColor +0x00a034 initWindows.wp +0x00a082 gBoardWin +0x00a086 gScoreWin +0x00a08a gMovesWin +0x00a08e gBoard +0x00a0f2 gMovesMade +0x00a0f4 gMoves +0x00a174 gScoreBuf +0x00a189 gMoveNotation +0x00a18d gUserId +0x00a18f gDpHandle +0x00a193 gDpBase +0x00a195 __indirTarget +0x00a197 __bss_end +0x00a197 __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 +BeginUpdate = 0x00495a +CheckMItem = 0x004847 +CtlStartUp = 0x00477a +DrawString = 0x0048ac +EMStartUp = 0x0047c2 +EndUpdate = 0x00496c +FMStartUp = 0x0047e1 +FrameOval = 0x0048be +FrontWindow = 0x00497e +GetPort = 0x0048d0 +GetPortRect = 0x0048e0 +GlobalToLocal = 0x0048f2 +HiliteMenu = 0x004857 +InsertMenu = 0x004867 +LEStartUp = 0x0047f1 +LineTo = 0x004904 +LoadOneTool = 0x004801 +MenuStartUp = 0x004837 +MoveTo = 0x004914 +NewHandle = 0x004811 +NewMenu = 0x00487c +NewWindow = 0x00498e +NoteAlert = 0x00478a +PaintOval = 0x004924 +PaintRect = 0x004936 +QDStartUp = 0x004896 +SelectWindow = 0x0049a8 +SetPort = 0x004948 +StopAlert = 0x0047a6 +TaskMaster = 0x0049ba +__absdi_a = 0x005339 +__absdi_b = 0x005341 +__ashldi3 = 0x005157 +__ashlhi3 = 0x004e62 +__ashlsi3 = 0x004fea +__ashrdi3 = 0x00519d +__ashrhi3 = 0x004e81 +__ashrsi3 = 0x005014 __bss_bank = 0x000000 -__bss_end = 0x00a0bc +__bss_end = 0x00a197 __bss_lo16 = 0x00a000 __bss_seg0_bank = 0x000000 __bss_seg0_lo16 = 0x00a000 -__bss_seg0_size = 0x0000bc +__bss_seg0_size = 0x000197 __bss_seg1_bank = 0x000000 __bss_seg1_lo16 = 0x000000 __bss_seg1_size = 0x000000 @@ -157,61 +224,104 @@ __bss_seg2_size = 0x000000 __bss_seg3_bank = 0x000000 __bss_seg3_lo16 = 0x000000 __bss_seg3_size = 0x000000 -__bss_size = 0x0000bc +__bss_size = 0x000197 __bss_start = 0x00a000 -__cmpdi2 = 0x002e4e -__divdi3 = 0x002ef4 -__divhi3 = 0x002ab3 -__divmod_setup = 0x002ae7 -__divmoddi4_stash = 0x002d34 -__divmodsi_setup = 0x002ce3 -__divsi3 = 0x002c95 +__cmpdi2 = 0x005247 +__divdi3 = 0x0052ed +__divhi3 = 0x004eac +__divmod_setup = 0x004ee0 +__divmoddi4_stash = 0x00512d +__divmodsi_setup = 0x0050dc +__divsi3 = 0x00508e __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 +__heap_start = 0x00a197 +__indirTarget = 0x00a195 +__init_array_end = 0x005c31 +__init_array_start = 0x005c31 +__jsl_indir = 0x004de9 +__lshrdi3 = 0x00517a +__lshrhi3 = 0x004e71 +__lshrsi3 = 0x004fff +__moddi3 = 0x00530c +__modhi3 = 0x004ec6 +__modsi3 = 0x0050b5 +__muldi3 = 0x0051c3 +__mulhi3 = 0x004dec +__mulsi3 = 0x004f31 +__negdi_a = 0x005349 +__negdi_b = 0x005367 +__retdi = 0x00514a +__rodata_end = 0x005c31 +__rodata_start = 0x0057d5 __start = 0x001000 -__text_end = 0x0033dc +__text_end = 0x0057d5 __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 +__ucmpdi2 = 0x00521e +__udivdi3 = 0x00527e +__udivhi3 = 0x004e94 +__udivmod_core = 0x004f13 +__udivmoddi_core = 0x0052a0 +__udivmodsi_core = 0x00502e +__udivsi3 = 0x005066 +__umoddi3 = 0x005287 +__umodhi3 = 0x004ea0 +__umodsi3 = 0x00507a +__umulhisi3 = 0x004e0b +__umulhisi3_qsq = 0x0053d7 +appleMenuStr = 0x0059a0 +checkForDone = 0x0032c9 +doAlert.alertRec = 0x005a4f +doAlert.button = 0x005a1f +doAlert.message = 0x005a37 +doAlert.okStr = 0x005a1a +drawMovesList = 0x0028ff +drawScore = 0x00264d +drawSquare = 0x002b01 +editMenuStr = 0x0058ee +fileMenuStr = 0x005961 +findMove = 0x00221d +gAboutMsg = 0x0059d8 +gBlackWinsMsg = 0x005b0d +gBoard = 0x00a08e +gBoardName = 0x0059c0 +gBoardWin = 0x00a082 +gCantPassMsg = 0x005a8f +gChainPath = 0x0057d5 +gColor = 0x0057e9 +gCurrentColor = 0x00a032 +gDisp = 0x005b44 +gDone = 0x00a02c +gDpBase = 0x00a193 +gDpHandle = 0x00a18f +gDrawMsg = 0x005ad5 +gEvent = 0x00a000 +gIllegalMsg = 0x005aba +gMoveNotation = 0x00a189 +gMoves = 0x00a0f4 +gMovesLeft = 0x00a02e +gMovesMade = 0x00a0f2 +gMovesName = 0x0059d1 +gMovesWin = 0x00a08a +gPassMsg = 0x005b23 +gPly = 0x005a8d +gScoreBuf = 0x00a174 +gScoreName = 0x0059c9 +gScoreWin = 0x00a086 +gSelfPlay = 0x00a030 +gSqScore = 0x005b54 +gUserId = 0x00a18d +gWhiteWinsMsg = 0x005af7 +initWindows.wp = 0x00a034 +levelMenuStr = 0x005874 +longjmp = 0x0053ad main = 0x0010ba -makeMove = 0x0022c4 -memset = 0x002474 -pickAiMove = 0x001af5 -setjmp = 0x002f8c -startdesk = 0x002639 +makeAMove = 0x002f25 +memcpy = 0x004698 +memset = 0x00471a +newGame = 0x002056 +optionsMenuStr = 0x0057eb +paintDesktopBackdrop = 0x004db7 +scoreMove = 0x003ec1 +scoreString.tpl = 0x005c1c +setjmp = 0x005385 +startdesk = 0x0049d1 diff --git a/demos/reversi.o b/demos/reversi.o index 09bacf00c2033d9cdb6618c5844fb10629b690be..ceca59910f63648686bcc7ca5d1a394414442f9c 100644 GIT binary patch literal 28976 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 G_4vO@hOn3b literal 9516 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 XUk3>5nuy9`ywCPx4h@1J__U2Ce=uDxN^ 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 TbuPz~xMHa@hrJ<#s|EfY$9$0< literal 2284 zcmYk-ZA^`E7{~FeIz5lAI#>riIL$CGY~*3K)*7i1v7$z6$(a#SvF`jfh!?KAT^-BiBCLM9vA0tBExcs1F(V!#emutu-fJ~_0Bm6o zg@<@fBplBk4JXivun(OHFQXlB9GwHl(s^(UT?o&hOW+8)9QLHEVe|epDmTI5{9UfW z6`b#Z%jf~PoF0Y?=>Xj9VmbmoOD}|5=vD9udNbTe7r{s9TDXqB0Pm+e;hppgIFJ4c zXVc^GRyr7ev~+qFoI%IH=jaspBE20xNteQ>=?1ulZiA1}U2rA+9xkDO!nw4?BC?0J z!47&Jyp4{BH`1HnOgbN4O;^F|=reFC?Szx*CvXb=3En{efwSmQIENmG3+R9FLE6(> zq?-1I>uEo@nGS^8=}7nry$Eilli=%gHhh&XhA-1i@JN91jI_bs!G@ixcdPzP^?ua{ zRUcM8$VcSIB;!mQ{El|QkLez`jD7{T&>!G>`n&4CRsXBHzps1V3Y+JIt3F5dXw_p? zU#a?f)w5LJp?aa}hg7do{gmo0s<*4&p?bIK&sFbJ{fp{Ds*kBIe(q<`0pH~PJOJm? zY5wlM1)jk7j}_mGG0yk~x}Sx+${+E4F`toy5Rp;4@qS*5Gj8xZ=78t(oP5~HUIpKx zTj4u&7i{kBh10pWPj#6hGRSv(5NyudmE&ML_pVSqP4x`b3t%tKm#UcxHPZ~g;m^IK zW;)c&BRGWT^s1THYGzRN0sOBsKmRY-{6A>7i424r_j9rGdDu49=JL?aI$dM|mg}6EVQ#NcKCD~~w_>^G z>r_9k`iSZtxHqx9KNegQXkT2-b0)&c>{eXO&l3ildm~|UZxn3qT?(6fmn$d1yRclJ F^FJNS089V? diff --git a/docs/USAGE.md b/docs/USAGE.md index 0318547..b41d219 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -469,15 +469,37 @@ clang --target=w65816 -O2 -mllvm -print-after=w65816-isel \ ## Cycle-count benchmarks -Eight microbenchmarks live under [`benchmarks/`](../benchmarks/). -Each runs N iterations of the bench function and reports a -per-call cycle count via MAME's `emu.time()`: +Eleven microbenchmarks live under [`benchmarks/`](../benchmarks/) — +eight integer/string benches plus three soft-double FP benches +(`dadd`, `dmul`, `ddiv`). Each runs N iterations of the bench +function and reports per-iter cycles via MAME's HBL counter: ```bash -bash scripts/benchCyclesPrecise.sh +bash scripts/benchCycles.sh ``` -Output: +Output (2026-05-20): + +``` +| Benchmark | Per-iteration cycles | +|-----------|---------------------:| +| bsearch | 127 cyc/iter (100 iters) | +| crc32 | <65 (under timer resolution) | +| dadd | 1157 cyc/iter (10 iters) | +| ddiv | 1261 cyc/iter (10 iters) | +| dmul | 1033 cyc/iter (10 iters) | +| dotProduct | 144 cyc/iter (100 iters) | +| fib | 97 cyc/iter (100 iters) | +| memcmp | 113 cyc/iter (100 iters) | +| popcount | 93 cyc/iter (100 iters) | +| strcpy | 91 cyc/iter (100 iters) | +| sumOfSquares | 126 cyc/iter (100 iters) | +``` + +The legacy `scripts/benchCyclesPrecise.sh` (per-call cycle count +via `emu.time()`) is still available but slower to run. + +Output (legacy `benchCyclesPrecise.sh`): ``` | Benchmark | Per-call cycles (clang) | diff --git a/runtime/build.sh b/runtime/build.sh index b87d62d..5464c33 100755 --- a/runtime/build.sh +++ b/runtime/build.sh @@ -55,11 +55,10 @@ cc "$SRC/libcxxabiSjlj.c" cc "$SRC/desktop.c" asm "$SRC/iigsGsos.s" asm "$SRC/iigsToolbox.s" -# softDouble.c builds at -O2. dpack stays noinline (basic regalloc -# overflows when dpack inlines into __adddf3/__muldf3). dclass MUST -# stay inline (its pointer-arg writes from a noinline boundary would -# lower to `sta (d,s),y` which uses DBR — silently corrupted under -# DBR != 0, caught by the dmul-after-bank-switch test). +# softDouble.c builds at -O2. dpack is noinline to dodge a backend +# stack-slot aliasing bug; dclass stays inline because pointer-arg +# stores from a noinline boundary use DBR-relative addressing (broken +# under DBR != 0). Both choices documented in the source. cc "$SRC/softDouble.c" echo "runtime built: $(ls -1 "$OUT"/*.o | wc -l) objects" diff --git a/runtime/src/libc.c b/runtime/src/libc.c index e2fce58..de80b47 100644 --- a/runtime/src/libc.c +++ b/runtime/src/libc.c @@ -798,7 +798,10 @@ typedef unsigned long clock_t; // DP scratch ($E0..$E7), then memcpy out. We can't use "=g" // constraints (W65816 backend rejects memory operands in inline // asm), so the data path runs through known DP addresses. -__attribute__((noinline)) +// +// "memory" clobber on the asm tells the scheduler we touch arbitrary +// memory, so it can't reorder the asm against the volatile DP reads +// below. That permits inlining without losing the read ordering. static void readTimeHex(unsigned char buf[8]) { __asm__ volatile ( "pea 0\n" @@ -1070,25 +1073,6 @@ extern int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap); int vfprintf(FILE *stream, const char *fmt, va_list ap); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); -// Opaque pos-update helper. The vfprintf body's `stream->pos += -// written` got DSE'd under p:32:16 + size_t=unsigned long when called -// after a format-spec vsnprintf call. Routing through an explicit -// noinline helper forces the compiler to emit the memory store. -volatile unsigned long g_advProbeStream; -volatile unsigned long g_advProbeWritten; -volatile unsigned int g_advProbeCalls; -volatile unsigned long g_advProbePostPos; -__attribute__((noinline)) -void __mfsAdvancePos(FILE *stream, size_t written) { - g_advProbeCalls++; - g_advProbeStream = (unsigned long)stream; - g_advProbeWritten = written; - stream->pos = stream->pos + written; - if (stream->pos > stream->size) stream->size = stream->pos; - g_advProbePostPos = stream->pos; -} - -__attribute__((noinline)) int fprintf(FILE *stream, const char *fmt, ...) { va_list ap; __builtin_va_start(ap, fmt); @@ -1097,7 +1081,6 @@ int fprintf(FILE *stream, const char *fmt, ...) { return r; } -__attribute__((noinline)) int vfprintf(FILE *stream, const char *fmt, va_list ap) { if (!stream) return -1; if (stream->kind == FILE_KIND_STDOUT || stream->kind == FILE_KIND_STDERR) @@ -1124,19 +1107,11 @@ int vfprintf(FILE *stream, const char *fmt, va_list ap) { size_t remain = (stream->cap > stream->pos) ? stream->cap - stream->pos : 0; if (remain == 0) { stream->err = 1; return -1; } - // Stash the FILE* low+high halves in volatile stack locals so - // the compiler is forced to reload after vsnprintf. Without - // this, the compiler keeps stream's hi half in IMG0 ($D0) for - // the entire function; vsnprintf uses $D0 as scratch, so when - // we read stream->* after vsnprintf returns the hi is garbage - // and writes go to the wrong bank. Caught by hex dumper test. - volatile unsigned int streamLo = (unsigned int)(unsigned long)stream; - volatile unsigned int streamHi = (unsigned int)((unsigned long)stream >> 16); int n = vsnprintf(stream->buf + stream->pos, remain, fmt, ap); - FILE *vs = (FILE *)((unsigned long)streamLo | ((unsigned long)streamHi << 16)); - if (n < 0) { vs->err = 1; return -1; } + if (n < 0) { stream->err = 1; return -1; } size_t written = ((size_t)n < remain) ? (size_t)n : remain - 1; - __mfsAdvancePos(vs, written); + stream->pos += written; + if (stream->pos > stream->size) stream->size = stream->pos; return n; } return -1; @@ -1219,7 +1194,6 @@ int system(const char *cmd) { (void)cmd; return 0; } // Returns NULL if no registration matches `path` (or the requested // mode isn't compatible with the registration's writable flag). -__attribute__((noinline)) static void initFileMem(FILE *f, const MfsEntry *reg, int wantWrite) { f->kind = FILE_KIND_MEM; f->writable = (u8)(wantWrite ? 1 : 0); @@ -1230,15 +1204,7 @@ static void initFileMem(FILE *f, const MfsEntry *reg, int wantWrite) { f->cap = reg->cap; f->pos = 0; f->unget = -1; - // Workaround: write path via byte-by-byte memcpy to dodge a ptr32 - // SDAG combiner bug where the i32 ptr-store of `f->path = reg->path` - // (struct offset 22) ends up writing to the previously-computed - // `f->pos` address (offset 16), corrupting pos. - { - const unsigned char *src = (const unsigned char *)®->path; - unsigned char *dst = (unsigned char *)&f->path; - dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; - } + f->path = reg->path; } // Scratch GSString for fopen's gsosOpen call. Single static buffer is diff --git a/runtime/src/libgcc.s b/runtime/src/libgcc.s index 3bdbe6f..31230a0 100644 --- a/runtime/src/libgcc.s +++ b/runtime/src/libgcc.s @@ -979,7 +979,18 @@ __muldi3: stz 0xf4 stz 0xf6 stz 0xf8 - ; Loop 64 times on a's bits. + ; Short-circuit when a's high half ($E4/$E6) is zero: bits 32..63 + ; of a are 0, so the 32 high iterations would add nothing. Saves + ; ~50% of __muldi3 cost in mulhi64Aligned (softDouble.c), which + ; passes only u32-wide operands. b's high half is irrelevant for + ; this short-circuit — even if b is full-width, iters 32..63 only + ; shift b and add zero. + lda 0xe4 + ora 0xe6 + bne .Lmuldi_long + ldy #0x20 + bra .Lmuldi_loop +.Lmuldi_long: ldy #0x40 .Lmuldi_loop: ; Right-shift the 64-bit `a` by 1. $E0=lo..$E6=hi (matches the diff --git a/runtime/src/math.c b/runtime/src/math.c index 0134ecb..c4f9815 100644 --- a/runtime/src/math.c +++ b/runtime/src/math.c @@ -708,12 +708,6 @@ float expm1f(float x) { return (float)expm1((double)x); } // to avoid overflow — for |x|, |y| < ~1e150 the naive form is fine, // past that you'd want the standard scale-by-max trick. -// hypot — naive sqrt(x*x + y*y). NO `volatile` on the temps — -// clang's codegen for volatile-double locals on this target generates -// stack-relative loads/stores that crash under the GS/OS Loader (the -// chain executes correctly under runInMame but not via Finder). The -// volatile-free version works in both contexts. -__attribute__((noinline)) double hypot(double x, double y) { double xx = x * x; double yy = y * y; @@ -734,8 +728,6 @@ float hypotf(float x, float y) { // Implemented WITHOUT calling pow because clang treats pow as a // known builtin and either inlines it (with bad fold of pow(x,1/3)) // or DCEs the call entirely (cbrt body collapses to "return 0"). -// This implementation has no pow dependency and is immune. -__attribute__((noinline)) double cbrt(double x) { if (x == 0.0) return x; int neg = (int)(dToBits(x) >> 63) & 1; diff --git a/runtime/src/qsort.c b/runtime/src/qsort.c index 8e4e8e2..95b06ac 100644 --- a/runtime/src/qsort.c +++ b/runtime/src/qsort.c @@ -57,7 +57,6 @@ void *bsearch(const void *key, const void *base, size_t nmemb, // the split, qsort's i32-pointer pressure under ptr32 produces // ADCEfi tied-def chains the inline-spiller can't allocate ("ran // out of registers" failure). -__attribute__((noinline)) static void qsortInner(unsigned char *base, unsigned char *cur, size_t size, CmpFnT cmp) { while (cur > base) { diff --git a/runtime/src/snprintf.c b/runtime/src/snprintf.c index 35b7109..158c0ae 100644 --- a/runtime/src/snprintf.c +++ b/runtime/src/snprintf.c @@ -18,25 +18,9 @@ // the buffer been unbounded (C99 vsnprintf semantics), not just the // number actually written. This lets callers detect truncation. // -// **Sink state lives in file-static globals** instead of an explicit -// struct passed by pointer. This was originally a workaround for two -// W65816 backend bugs (since fixed): -// (1) The address of a stack-resident struct used to be computed -// wrong (&s came out as SP+5 = address of s.end instead of SP+3). -// (2) Functions taking fmt as arg1 (stack) didn't initialize the -// fmt local before the loop body — first char came from the -// arg slot but the loop's fmt++ ran on uninitialized memory. -// The struct-sink form now compiles correctly, but switching back to it -// would shift every TU's branch distances; left as-is for stability. -// Single-threaded use only, but that matches the rest of this runtime. -// -// Reverse-emit pattern (used by emitUDec / emitULong / emitHex): the -// natural countdown forms (`while (i > 0) emit(buf[--i])`, -// `while (i > 0) { i--; emit(buf[i]); }`, -// `for (j = i - 1; j >= 0; j--) emit(buf[j])`) all lower to a -// do-while whose `dec a; bpl` exit condition runs the loop one -// extra time on this backend, leaking a `buf[-1]` read. Use the -// forward count + index-arithmetic form instead. +// Sink state lives in file-static globals (gCur/gEnd/gTotal) rather +// than a per-call context. Single-threaded use only, but that matches +// the rest of this runtime. typedef unsigned long size_t; typedef __builtin_va_list va_list; @@ -50,7 +34,6 @@ static char *gEnd; static size_t gTotal; -__attribute__((noinline)) static void emit(char c) { if (gCur < gEnd) { *gCur++ = c; @@ -59,7 +42,6 @@ static void emit(char c) { } -__attribute__((noinline)) static void emitStr(const char *p) { if (!p) { p = "(null)"; @@ -70,7 +52,6 @@ static void emitStr(const char *p) { } -__attribute__((noinline)) static void emitUDec(unsigned int n) { char buf[6]; int i = 0; @@ -82,15 +63,10 @@ static void emitUDec(unsigned int n) { buf[i++] = '0' + (n % 10); n /= 10; } - // Reverse-emit; see file header for the forward-index rationale. - int top = i; - for (int j = 0; j < top; j++) { - emit(buf[top - 1 - j]); - } + while (i > 0) emit(buf[--i]); } -__attribute__((noinline)) static void emitDec(int n) { // -n on INT_MIN is signed-overflow UB; negate as unsigned. if (n < 0) { @@ -102,7 +78,6 @@ static void emitDec(int n) { } -__attribute__((noinline)) static void emitULong(unsigned long n) { char buf[11]; int i = 0; @@ -114,15 +89,10 @@ static void emitULong(unsigned long n) { buf[i++] = '0' + (n % 10); n /= 10; } - // Reverse-emit; see file header for the forward-index rationale. - int top = i; - for (int j = 0; j < top; j++) { - emit(buf[top - 1 - j]); - } + while (i > 0) emit(buf[--i]); } -__attribute__((noinline)) static void emitSignedLong(long n) { // See emitDec: avoid the signed-overflow UB on LONG_MIN. if (n < 0) { @@ -134,7 +104,6 @@ static void emitSignedLong(long n) { } -__attribute__((noinline)) static void emitHex(unsigned int n, int width) { static const char digits[] = "0123456789abcdef"; // unsigned int is 16-bit on this target -> at most 4 hex digits. @@ -153,15 +122,10 @@ static void emitHex(unsigned int n, int width) { while (i < width) { buf[i++] = '0'; } - // Reverse-emit; see file header for the forward-index rationale. - int top = i; - for (int j = 0; j < top; j++) { - emit(buf[top - 1 - j]); - } + while (i > 0) emit(buf[--i]); } -__attribute__((noinline)) static void emitDouble(double v, int prec, char spec) { // For %g / %G, "precision" is total significant digits. Real glibc // would compute exponent and choose between %e and %f styles, but diff --git a/runtime/src/softDouble.c b/runtime/src/softDouble.c index b02ee1e..beb6bb8 100644 --- a/runtime/src/softDouble.c +++ b/runtime/src/softDouble.c @@ -24,45 +24,20 @@ typedef unsigned char u8; // Pack sign / unbiased-exp / mantissa-with-leading-bit into IEEE-754 // double. Returns sign for zero or underflow; sign|inf for overflow. -// -// Body uses per-word writes through a `union { u64; u16[4]; }` and -// stores each word through a volatile-qualified accessor to defeat -// the backend's stack-slot coalescing. Without the volatile wrap, -// inlining dpack into __adddf3 hit a stack-slot-aliasing miscompile -// where result word 2 got OR'd with result word 3 (dadd(1.5, 2.5) → -// 0x4010_4010_0000_0000 instead of 0x4010_0000_0000_0000). Real fix -// needs backend stack-slot lifetime analysis at the coalescer stage. static u64 dpack(u64 sign, s16 exp, u64 mant) { if (mant == 0) return sign; s16 eS = exp + DEXP_BIAS; if (eS <= 0) return sign; if (eS >= 2047) return sign | DEXP_MASK; - union { u64 u; u16 w[4]; } mantU, signU; - mantU.u = mant; - signU.u = sign; - // Volatile output array forces distinct stack slots per word — - // the compiler can't fold these into shared slots. - volatile u16 outW[4]; - outW[0] = (u16)(mantU.w[0] | signU.w[0]); - outW[1] = (u16)(mantU.w[1] | signU.w[1]); - outW[2] = (u16)(mantU.w[2] | signU.w[2]); - outW[3] = (u16)((mantU.w[3] & 0x000F) | signU.w[3] | ((u16)eS << 4)); - union { u64 u; u16 w[4]; } r; - r.w[0] = outW[0]; - r.w[1] = outW[1]; - r.w[2] = outW[2]; - r.w[3] = outW[3]; - return r.u; + return sign | (mant & DMANT_MASK) | ((u64)(u16)eS << DEXP_SHIFT); } // Decompose `x` into sign / unbiased-exp / mantissa-with-leading-bit. // Returns the class: 0=zero, 1=normal, 2=infinity, 3=NaN. -// noinline reduces register pressure in __muldf3/__divdf3/__adddf3 -// — without it, greedy regalloc runs out of registers in __muldf3 -// at -O2. Now safe because pointer-arg writes lower to STBptr/STAptr -// which use [$E0],Y indirect-long with the bank byte forced to 0 -// (DBR-independent). See `feedback_dbr_ptr_deref_spill.md`. -// noinline removed — pointer-arg stores now lower to STBptr/STAptr (indirect-long, DBR-independent) +// +// Kept inline: passing pointer args from a noinline boundary lowers to +// `sta (d,s),y` (DBR-relative) — broken under DBR != 0. Inlining keeps +// the stores within the caller's frame. See feedback_dbr_ptr_deref_spill.md. static u16 dclass(u64 x, u64 *out_sign, s16 *out_exp, u64 *out_mant) { *out_sign = x & DSIGN_BIT; s16 e = (s16)((x >> DEXP_SHIFT) & 0x7FF); @@ -142,10 +117,9 @@ u64 __adddf3(u64 a, u64 b) { // left-shift if subtraction left the lead below 55. Reverse order // would shift an over-wide value out of u64 range entirely. // Use if + do-while because pure `while (cond) body` triggers a - // ptr32 backend bug: PHP/PLP wrap pass mis-identifies the loop's - // pre-test LDA reload as flag corruption and wraps the wrong - // range, so the BEQ tests stale flags and the loop body never - // fires. `do { } while (cond)` is unaffected (test-after-body). + // backend bug in the left-shift renormalize path: subtraction + // cases (different signs) lose their result (7+(-8) → -0 instead + // of -1). do-while is unaffected (test-after-body). if (mr & ~((1ULL << 56) - 1)) { do { u64 sticky_bit = mr & 1; @@ -282,26 +256,14 @@ u64 __divdf3(u64 a, u64 b) { // Handle the leading quotient bit explicitly. u64 q = DMANT_LEAD; u64 r = ma - mb; - // `volatile vmb`: forces mb to be re-read from memory inside the - // loop. Without this, the W65816 codegen miscompiles `r >= mb` and - // `r -= mb` when called as the 3rd+ chained `__divdf3` after prior - // softDouble libcalls (sqrt3 Newton iter — 3rd iter returned 0.0 - // instead of 1.41421). Adding `volatile` to either `r` or `mb` - // alone fixes it, suggesting the compiler is keeping one of them - // in registers across loop iterations and a JSL inside the loop - // (__ashlsi3 for `r <<= 1`) clobbers the held value. The real - // fix lives in the W65816 backend's u64-shift lowering; volatile - // here is the conservative workaround. - volatile u64 vmb = mb; // Compute 52 more fractional bits via standard shift-test-subtract. for (int i = 51; i >= 0; i--) { r <<= 1; - if (r >= vmb) { - r -= vmb; + if (r >= mb) { + r -= mb; q |= (1ULL << i); } } - mb = vmb; // resync in case below reads mb // Round to nearest, ties to even. Generate one extra bit (the // "guard"), examine the remainder for any non-zero "sticky" tail, // and round q up when guard=1 and (sticky || (q & 1)). Without diff --git a/runtime/src/softFloat.c b/runtime/src/softFloat.c index bf055bc..0cd2d3e 100644 --- a/runtime/src/softFloat.c +++ b/runtime/src/softFloat.c @@ -38,7 +38,6 @@ typedef int s16; #define MANT_MASK 0x007FFFFFUL #define MANT_LEAD 0x00800000UL // implicit leading 1 -__attribute__((noinline)) static u16 fpClass(u32 x, u32 *out_sign, s16 *out_exp, u32 *out_mant) { *out_sign = x & SIGN_BIT; s16 e = (s16)((x >> EXP_SHIFT) & 0xFF); @@ -61,7 +60,6 @@ static u16 fpClass(u32 x, u32 *out_sign, s16 *out_exp, u32 *out_mant) { return 1; // normal } -__attribute__((noinline)) static u32 fpPack(u32 sign, s16 exp, u32 mant) { if (mant == 0) return sign; // zero // Normalize: shift mantissa until bit 23 is the leading 1. diff --git a/runtime/src/strtok.c b/runtime/src/strtok.c index 03e6567..ca29e3f 100644 --- a/runtime/src/strtok.c +++ b/runtime/src/strtok.c @@ -9,7 +9,6 @@ static char *gStrtokSave; // strtok_r, growing the .o by ~70%. The runtime's bank-0 budget // is tight enough that the duplicated code pushes rodata past // 0xC000 (IIgs IO window), corrupting string literals at runtime. -__attribute__((noinline)) char *strtok_r(char *str, const char *delim, char **saveptr) { unsigned char *s; if (str != (char *)0) { diff --git a/runtime/src/timeExt.c b/runtime/src/timeExt.c index 7124c8d..dc74e8a 100644 --- a/runtime/src/timeExt.c +++ b/runtime/src/timeExt.c @@ -164,7 +164,6 @@ static const char *const __monLong[12] = { // (__udivhi3 + __umodhi3) is slower than one __udivhi3 + multiply but // is the only spelling that avoids the negation bug at this width. // Calendar values stay under 65535 so u16 suffices. -__attribute__((noinline)) static char *fmtN(char *p, unsigned long v, int n) { unsigned int v16 = (unsigned int)v; p += n; @@ -220,7 +219,6 @@ char *ctime(const time_t *t) { // %Y %m %d %H %M %S %j %w %a %A %b %h %B %p %% // Composite specs (expanded by main loop via strftimeComposite): // %D %F %R %T %r %x %X %c -__attribute__((noinline)) static int strftimeOne(char dst[8], char spec, const struct tm *tm, const char **strOut) { *strOut = 0; diff --git a/screenshots/frame.png b/screenshots/frame.png index 052783d..31dc20e 100644 --- a/screenshots/frame.png +++ b/screenshots/frame.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:051573cbf726c8f39f6ad9ce3cf8fb49f5282be228845bb50b13887d0c0a5fc8 -size 2713 +oid sha256:0d383d40d649de9e2985f6aa22381cb4bff184bd28d026673237798508c7c160 +size 1373 diff --git a/screenshots/minicad.png b/screenshots/minicad.png index 60c19f3..00e2e43 100644 --- a/screenshots/minicad.png +++ b/screenshots/minicad.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:81a59ee363dbe66546fe56bd7570757886ab0526a99be4839387c73c009849ce -size 3803 +oid sha256:1a5cb11d44ad3254569cf3200a50ed925e6863634048b54fef7c9a1185e01ef8 +size 1693 diff --git a/screenshots/orcaFrameLike.png b/screenshots/orcaFrameLike.png deleted file mode 100644 index 757cdeb..0000000 --- a/screenshots/orcaFrameLike.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08243cbf6f9d31d3a29dc50b3e9f98e278777b13ab361e30fdd8687247cac256 -size 1203 diff --git a/screenshots/orcaMiniCadLike.png b/screenshots/orcaMiniCadLike.png deleted file mode 100644 index 9898b4c..0000000 --- a/screenshots/orcaMiniCadLike.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8a3378f00c133c0754db525b4b8d1215ba1ddcb515ff5b52a0ec5a561d1ba307 -size 2891 diff --git a/screenshots/orcaReversiLike.png b/screenshots/orcaReversiLike.png deleted file mode 100644 index 757cdeb..0000000 --- a/screenshots/orcaReversiLike.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08243cbf6f9d31d3a29dc50b3e9f98e278777b13ab361e30fdd8687247cac256 -size 1203 diff --git a/screenshots/qdProbe.png b/screenshots/qdProbe.png index d560a07..84f7fb9 100644 --- a/screenshots/qdProbe.png +++ b/screenshots/qdProbe.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9f01c81966a4b6508f086ed8a9d3e54b3694e60643cec97ed33a516b5065823 -size 14278 +oid sha256:e53252d3a0ea077043d598b06081dfc6ff4a1901a7cf18b371abf9bb08143e15 +size 1199 diff --git a/screenshots/reversi.png b/screenshots/reversi.png index d6048b4..ed782b6 100644 --- a/screenshots/reversi.png +++ b/screenshots/reversi.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f09749b0d2605f9f6bfac1e9f8629f84753ad0c3c65805bb228a415171973ba8 -size 3936 +oid sha256:66d15097eb8ad88a92b27cef8c631f8803e9ae1960674aaea38eb773dda75a51 +size 4427 diff --git a/scripts/benchCycles.sh b/scripts/benchCycles.sh index ead9809..e16162d 100755 --- a/scripts/benchCycles.sh +++ b/scripts/benchCycles.sh @@ -24,6 +24,8 @@ oCrt0=$(mktemp --suffix=.o) oLibgcc=$(mktemp --suffix=.o) "$LLVM_MC" -arch=w65816 -filetype=obj "$PROJECT_ROOT/runtime/src/crt0.s" -o "$oCrt0" "$LLVM_MC" -arch=w65816 -filetype=obj "$PROJECT_ROOT/runtime/src/libgcc.s" -o "$oLibgcc" +# softDouble.o is needed for FP benches (dmul/dadd/ddiv → __muldf3/etc.) +oSoftDouble="$PROJECT_ROOT/runtime/softDouble.o" # Per-benchmark wrapper template. The C wrapper calls each benchmark # with appropriate inputs, then writes the iteration count and cycle @@ -39,6 +41,9 @@ benchInputs() { dotProduct) echo 'dotProduct(va, vb, 4)';; popcount) echo 'popcount(0x12345678UL)';; crc32) echo 'crc32((const unsigned char *)"hello", 5)';; + dmul) echo 'dmul(da, db)';; + dadd) echo 'dadd(da, db)';; + ddiv) echo 'ddiv(da, db)';; *) echo "/* unknown */";; esac } @@ -53,6 +58,9 @@ benchExtern() { dotProduct) echo 'extern long dotProduct(const short *a, const short *b, unsigned int n); static const short va[] = {1,2,3,4}; static const short vb[] = {5,6,7,8};';; popcount) echo 'extern int popcount(unsigned long x);';; crc32) echo 'extern unsigned long crc32(const unsigned char *p, unsigned int n);';; + dmul) echo 'extern double dmul(double a, double b); static volatile double da = 3.14, db = 2.71;';; + dadd) echo 'extern double dadd(double a, double b); static volatile double da = 3.14, db = 2.71;';; + ddiv) echo 'extern double ddiv(double a, double b); static volatile double da = 3.14, db = 2.71;';; *) echo '';; esac } @@ -68,6 +76,14 @@ runOneBench() { echo "(no input config)" return fi + # FP benches assign result to sinkD (double); rest assign to sink as ulong + # FP benches also use fewer iters (each call is ~1000+ cycles, so 100 + # iters wraps the 8-bit HBL counter many times). + local sink_lhs sink_cast iters + case "$name" in + dmul|dadd|ddiv) sink_lhs='sinkD'; sink_cast=''; iters=10 ;; + *) sink_lhs='sink'; sink_cast='(unsigned long)'; iters=100 ;; + esac local cwrap=$(mktemp --suffix=.c) local owrap=$(mktemp --suffix=.o) @@ -90,7 +106,8 @@ __attribute__((noinline)) static unsigned char readVbl(void) { return r; } volatile unsigned long sink; -#define ITERS 100 +volatile double sinkD; +#define ITERS $iters int main(void) { // Re-enable IRQs so the IIgs ROM's VBL handler runs and the // VBL counter at \$E1006B actually ticks. crt0 disables IRQs @@ -98,7 +115,7 @@ int main(void) { __asm__ volatile ("cli\n" ::: "memory"); unsigned char t0 = readVbl(); for (int i = 0; i < ITERS; i++) { - sink = (unsigned long)($call_expr); + $sink_lhs = $sink_cast($call_expr); } unsigned char t1 = readVbl(); __asm__ volatile ("sei\n" ::: "memory"); @@ -114,7 +131,7 @@ EOF || { echo "compile-fail"; rm -f "$cwrap" "$owrap"; return; } "$CLANG" --target=w65816 -O2 -ffunction-sections -c "$BENCH_DIR/$name.c" -o "$obench" 2>/dev/null \ || { echo "compile-fail"; rm -f "$cwrap" "$owrap" "$obench"; return; } - "$LINK" -o "$bin" --text-base 0x1000 "$oCrt0" "$oLibgcc" "$owrap" "$obench" 2>/dev/null \ + "$LINK" -o "$bin" --text-base 0x1000 "$oCrt0" "$oLibgcc" "$oSoftDouble" "$owrap" "$obench" 2>/dev/null \ || { echo "link-fail"; rm -f "$cwrap" "$owrap" "$obench" "$bin"; return; } # Read VBL delta at $025000. @@ -135,8 +152,8 @@ EOF if [ "$ticks" -eq 0 ]; then echo "<65 cyc/iter (under timer resolution)" else - local cycles=$((ticks * 65 / 100)) - printf "%d hbl-ticks (~%d cyc/iter)" "$ticks" "$cycles" + local cycles=$((ticks * 65 / iters)) + printf "%d hbl-ticks (~%d cyc/iter, %d iters)" "$ticks" "$cycles" "$iters" fi fi } diff --git a/scripts/runInMame.sh b/scripts/runInMame.sh index 79dd36c..e5dd0e4 100755 --- a/scripts/runInMame.sh +++ b/scripts/runInMame.sh @@ -21,7 +21,15 @@ source "$(dirname "$0")/common.sh" BIN="$1" shift -SECS=3 +# Frame budget: load at frame 30, check at CHECK_FRAME (default 300 = 4.5 +# simulated seconds after load). Override via env for heavy-compute tests. +# Earlier default was 60 frames (0.5 sec), which falsely flagged slow but +# correct math (e.g. 6-iter sqrt with chained soft-double libcalls) as +# runtime hangs — see feedback_sqrt_runtime_broken.md. +CHECK_FRAME=${MAME_CHECK_FRAME:-300} +# seconds_to_run is simulated time; MAME terminates at this point. Sized +# to comfortably exceed CHECK_FRAME (300 frames = 5 sec at 60Hz). +SECS=${MAME_SECS:-6} # Build address list as Lua table entries. LUA_CHECKS="" @@ -84,7 +92,7 @@ emu.register_frame_done(function() cpu.state["S"].value = 0x01FF print("MAME-LOADED bytes=" .. #data) end - if frame == 60 then + if frame == $CHECK_FRAME then local cpu = manager.machine.devices[":maincpu"] local mem = cpu.spaces["program"] $LUA_CHECKS diff --git a/scripts/runInMameWithGsosStub.sh b/scripts/runInMameWithGsosStub.sh index 39e077b..ef1303c 100755 --- a/scripts/runInMameWithGsosStub.sh +++ b/scripts/runInMameWithGsosStub.sh @@ -22,7 +22,8 @@ source "$(dirname "$0")/common.sh" BIN="$1" shift -SECS=3 +CHECK_FRAME=${MAME_CHECK_FRAME:-300} +SECS=${MAME_SECS:-6} # 23-byte stub bytes (see runtime/src/iigsGsosStub.s for source). # Hand-assembled to avoid relying on llvm-mc tracking M-flag state. @@ -96,7 +97,7 @@ $STUB_LUA cpu.state["S"].value = 0x01FF print("MAME-LOADED bytes=" .. #data .. " stub=$((${#STUB_BYTES}/2))") end - if frame == 60 then + if frame == $CHECK_FRAME then local cpu = manager.machine.devices[":maincpu"] local mem = cpu.spaces["program"] $LUA_CHECKS diff --git a/scripts/runMultiSeg.sh b/scripts/runMultiSeg.sh index 9f8d803..65b51b6 100755 --- a/scripts/runMultiSeg.sh +++ b/scripts/runMultiSeg.sh @@ -11,7 +11,8 @@ source "$(dirname "$0")/common.sh" MANIFEST="$1" shift -SECS=3 +CHECK_FRAME=${MAME_CHECK_FRAME:-300} +SECS=${MAME_SECS:-6} # Build address list as Lua table entries, mirroring runInMame.sh. LUA_CHECKS="" @@ -97,7 +98,7 @@ $LOAD_LUA cpu.state["S"].value = 0x01FF print('MAME-READY pc=0x' .. string.format('%06x', $ENTRY_BASE + $ENTRY_OFF)) end - if frame == 60 then + if frame == $CHECK_FRAME then local cpu = manager.machine.devices[":maincpu"] local mem = cpu.spaces["program"] $LUA_CHECKS diff --git a/src/link816/link816.cpp b/src/link816/link816.cpp index be6b8d4..d25517f 100644 --- a/src/link816/link816.cpp +++ b/src/link816/link816.cpp @@ -833,6 +833,15 @@ struct Linker { L.bssBase = 0xD000; } } + // Also bump past the IO window if BSS would SPAN it + // (starts below 0xC000, extends into or past 0xC000). + // BSS writes to 0xC000-0xCFFF hit soft switches — caught + // by smoke #128 hex dumper, where ~954-byte BSS pushed + // past 0xC000 and BSS-clear writes crashed MAME. + if (L.bssBase < 0xC000 && + L.bssBase + L.bssSize > 0xC000) { + L.bssBase = 0xD000; + } if (L.bssBase + L.bssSize > 0x10000u) { char msg[256]; std::snprintf(msg, sizeof(msg), diff --git a/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp b/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp index ad3ff9d..5780640 100644 --- a/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp +++ b/src/llvm/lib/Target/W65816/W65816ISelLowering.cpp @@ -114,6 +114,17 @@ W65816TargetLowering::W65816TargetLowering(const TargetMachine &TM, for (MVT VT : MVT::integer_valuetypes()) setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i8, Expand); + // GlobalOpt sometimes narrows a `short` global to `i1` when it sees + // every assignment is 0 or 1. Custom-lower so LowerLoad rewrites + // `zext/sext/anyext from i1` into a plain byte load + appropriate + // mask. Both i16 and i8 result widths can appear, depending on + // whether the consumer wants the value as `short` or `bool`. + for (MVT ResVT : {MVT::i8, MVT::i16}) { + setLoadExtAction(ISD::ZEXTLOAD, ResVT, MVT::i1, Custom); + setLoadExtAction(ISD::SEXTLOAD, ResVT, MVT::i1, Custom); + setLoadExtAction(ISD::EXTLOAD, ResVT, MVT::i1, Custom); + } + // Only register i32 ext-load / trunc-store and Custom actions when // i32 is actually a legal type (ptr32 mode active). Otherwise the // Custom-action calls intercept i16/i8 ops, and LowerTruncate's @@ -191,6 +202,20 @@ W65816TargetLowering::W65816TargetLowering(const TargetMachine &TM, setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand); setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand); setOperationAction(ISD::MUL, MVT::i16, LibCall); + + // i8 multiply / mulh / div / rem: SDAG narrows e.g. `x / 10` to + // `mulhu i8 x, -51` + shift when it proves operands fit in i8. + // The 65816 has no native 8-bit multiplier; route everything + // through the 16-bit libcalls by Promoting i8 ops to i16. + setOperationAction(ISD::MUL, MVT::i8, Promote); + setOperationAction(ISD::MULHU, MVT::i8, Promote); + setOperationAction(ISD::MULHS, MVT::i8, Promote); + setOperationAction(ISD::SDIV, MVT::i8, Promote); + setOperationAction(ISD::UDIV, MVT::i8, Promote); + setOperationAction(ISD::SREM, MVT::i8, Promote); + setOperationAction(ISD::UREM, MVT::i8, Promote); + setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand); // CTPOP/CTLZ/CTTZ/ROTL/ROTR — no hardware support. Expand lets the // type legalizer rewrite into a sequence of basic ops. Without // this, e.g. `x && !(x & (x-1))` (LLVM canonicalises to popcount==1) @@ -904,6 +929,28 @@ SDValue W65816TargetLowering::LowerLoad(SDValue Op, Ld->getAlign(), Ld->getMemOperand()->getFlags()); } + // i1 memory type comes from GlobalOpt narrowing `short` globals + // whose only assignments are 0/1. Treat as i8 load + appropriate + // mask — the underlying memory is still byte-sized. + if (MemVT == MVT::i1) { + SDValue ByteLd = DAG.getExtLoad(ISD::ZEXTLOAD, DL, MVT::i16, Chain, + FoldedLo, MVT::i8, + Ld->getMemOperand()); + SDValue Val = ByteLd; + if (ExtType == ISD::ZEXTLOAD || ExtType == ISD::EXTLOAD) { + Val = DAG.getNode(ISD::AND, DL, MVT::i16, ByteLd, + DAG.getConstant(1, DL, MVT::i16)); + } else if (ExtType == ISD::SEXTLOAD) { + // i1 sign-extend: bit 0 -> all bits. AND #1 then NEG. + SDValue Bit = DAG.getNode(ISD::AND, DL, MVT::i16, ByteLd, + DAG.getConstant(1, DL, MVT::i16)); + Val = DAG.getNode(ISD::SUB, DL, MVT::i16, + DAG.getConstant(0, DL, MVT::i16), Bit); + } + if (Op.getValueType() == MVT::i8) + Val = DAG.getNode(ISD::TRUNCATE, DL, MVT::i8, Val); + return DAG.getMergeValues({Val, ByteLd.getValue(1)}, DL); + } return DAG.getExtLoad(ExtType, DL, Op.getValueType(), Chain, FoldedLo, MemVT, Ld->getMemOperand()); } @@ -913,6 +960,9 @@ SDValue W65816TargetLowering::LowerLoad(SDValue Op, return SDValue(); EVT MemVT = Ld->getMemoryVT(); + // Widen i1 memVT to i8 (single-byte storage). getMemIntrinsicNode + // asserts memvt must be supported; i1 isn't. + if (MemVT == MVT::i1) MemVT = MVT::i8; SDVTList VTs = DAG.getVTList(MVT::i16, MVT::Other); SDValue Ops[] = { Chain, Ptr }; // memVT for the LD_PTR memintrinsic must match MMO's size (i8 vs @@ -925,10 +975,14 @@ SDValue W65816TargetLowering::LowerLoad(SDValue Op, MemVT, Ld->getMemOperand()); SDValue Val = LdNode; // Byte memory access: mask the high byte for zextload, leave anyext. + // i1 memVT was widened to i8 above; the mask path is the same. if (MemVT == MVT::i8) { - if (Ld->getExtensionType() == ISD::ZEXTLOAD) - Val = DAG.getNode(ISD::AND, DL, MVT::i16, Val, - DAG.getConstant(0xFF, DL, MVT::i16)); + EVT OrigMemVT = Ld->getMemoryVT(); + SDValue MaskC = DAG.getConstant(OrigMemVT == MVT::i1 ? 1 : 0xFF, + DL, MVT::i16); + if (Ld->getExtensionType() == ISD::ZEXTLOAD || + (OrigMemVT == MVT::i1 && Ld->getExtensionType() == ISD::EXTLOAD)) + Val = DAG.getNode(ISD::AND, DL, MVT::i16, Val, MaskC); else if (Ld->getExtensionType() == ISD::SEXTLOAD) Val = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i16, Val, DAG.getValueType(MVT::i8)); diff --git a/src/llvm/lib/Target/W65816/W65816ImgCalleeSave.cpp b/src/llvm/lib/Target/W65816/W65816ImgCalleeSave.cpp index 7af5379..cf05eea 100644 --- a/src/llvm/lib/Target/W65816/W65816ImgCalleeSave.cpp +++ b/src/llvm/lib/Target/W65816/W65816ImgCalleeSave.cpp @@ -110,21 +110,32 @@ static int classifyImgReg(unsigned Reg) { return -1; } +// Classification of a DP-addressed instruction's relation to a DP slot. +enum class DpAccess { + None, // not a DP-imm instruction we care about + Read, // only reads the DP slot (e.g., LDA $C0) + Write, // only writes the DP slot (e.g., STA $C0) + ReadWrite, // both (e.g., INC $C0) +}; + // Map a DP-addressed instruction's first immediate operand to an IMG -// slot index if it falls in $C0..$CE. Returns -1 otherwise. -static int classifyDpImmAsImg(const MachineInstr &MI) { - // Most DP-addressed opcodes take the dp address as immediate op 0. - // (Some, like ADC_DP-form-with-explicit-A, may put the imm at op 1.) - // For our scan, check the first IMM operand we find. +// slot index and access mode. Returns (-1, None) if it doesn't access +// an IMG slot. +static std::pair classifyDpImmAsImg(const MachineInstr &MI) { unsigned Opc = MI.getOpcode(); + DpAccess Mode; switch (Opc) { - case W65816::LDA_DP: + // Pure stores: write only. case W65816::STA_DP: case W65816::STZ_DP: - case W65816::LDX_DP: case W65816::STX_DP: - case W65816::LDY_DP: case W65816::STY_DP: + Mode = DpAccess::Write; + break; + // Pure loads / compares / bit-tests: read only (writes to A/X/Y/P, not DP). + case W65816::LDA_DP: + case W65816::LDX_DP: + case W65816::LDY_DP: case W65816::ADC_DP: case W65816::SBC_DP: case W65816::AND_DP: @@ -134,53 +145,68 @@ static int classifyDpImmAsImg(const MachineInstr &MI) { case W65816::CPX_DP: case W65816::CPY_DP: case W65816::BIT_DP: + Mode = DpAccess::Read; + break; + // Read-modify-write. case W65816::INC_DP: case W65816::DEC_DP: case W65816::ASL_DP: case W65816::LSR_DP: case W65816::ROL_DP: case W65816::ROR_DP: + Mode = DpAccess::ReadWrite; break; default: - return -1; + return {-1, DpAccess::None}; } for (const auto &MO : MI.operands()) { if (!MO.isImm()) continue; int64_t V = MO.getImm(); for (int i = 0; i < 8; ++i) if ((int64_t)IMG_DP[i] == V) - return i; - return -1; // First imm is the dp addr; not in IMG range. + return {i, Mode}; + return {-1, DpAccess::None}; // First imm is the dp addr; not in IMG range. } - return -1; + return {-1, DpAccess::None}; } bool W65816ImgCalleeSave::runOnMachineFunction(MachineFunction &MF) { - // Step 1: scan for IMG8..IMG15 usage. copyPhysReg already lowered - // some COPY $imgN = $a forms to STA_DP imm:0xC0 (etc.), so we have - // to check both the physreg form AND the DP-immediate form. - bool UsedSlot[8] = {false}; - bool AnyUsed = false; + // Step 1: scan for IMG8..IMG15 WRITES. Reads alone don't need saving + // — if we never write IMGn, the caller's value survives untouched + // (other functions we call also preserve IMG8..IMG15 by the same + // convention, so no chain breaks the invariant). Saving on read-only + // use costs ~6 bytes per slot of needlessly-saved prologue/epilogue + // (caught by evalAt at 1.96× Calypsi — 5 IMG slots saved when fewer + // were actually written). + // + // copyPhysReg lowers `COPY $imgN = $a` to `STA_DP imm:0xCx`, so we + // check both the physreg-DEF form AND the DP-imm-store form. + bool WrittenSlot[8] = {false}; + bool AnyWritten = false; for (auto &MBB : MF) { for (auto &MI : MBB) { - // physreg form: $imgN = ... or ... = $imgN + // physreg-DEF form: $imgN appearing as a Def operand. for (const auto &MO : MI.operands()) { - if (!MO.isReg() || MO.getReg() == 0) continue; + if (!MO.isReg() || MO.getReg() == 0 || !MO.isDef()) continue; int idx = classifyImgReg(MO.getReg()); if (idx >= 0) { - UsedSlot[idx] = true; - AnyUsed = true; + WrittenSlot[idx] = true; + AnyWritten = true; } } - // DP-imm form: lda dp imm:0xC0 etc. - int idx = classifyDpImmAsImg(MI); - if (idx >= 0) { - UsedSlot[idx] = true; - AnyUsed = true; + // DP-imm form: STA_DP / INC_DP / etc. write the slot at $Cx. + auto [idx, mode] = classifyDpImmAsImg(MI); + if (idx >= 0 && + (mode == DpAccess::Write || mode == DpAccess::ReadWrite)) { + WrittenSlot[idx] = true; + AnyWritten = true; } } } - if (!AnyUsed) return false; + if (!AnyWritten) return false; + // Rename for downstream Step 2/3/4 readability — they use UsedSlot. + bool (&UsedSlot)[8] = WrittenSlot; + (void)AnyWritten; // Step 2: allocate one frame slot per used IMG. Size = 2 bytes (each // Img16 holds a 16-bit value). Mark as a spill slot so PEI accounts diff --git a/src/llvm/lib/Target/W65816/W65816InstrInfo.td b/src/llvm/lib/Target/W65816/W65816InstrInfo.td index 4416a1b..b702161 100644 --- a/src/llvm/lib/Target/W65816/W65816InstrInfo.td +++ b/src/llvm/lib/Target/W65816/W65816InstrInfo.td @@ -942,6 +942,17 @@ def : Pat<(i16 (zextloadi8 (W65816Wrapper tglobaladdr:$g))), def : Pat<(i16 (zextloadi8 (W65816Wrapper texternalsym:$s))), (ANDi16imm (LDAabs texternalsym:$s), 0xFF)>; +// i1-result loads from globals: GlobalOpt narrows `static short` to +// i1 when it sees every assignment is 0 or 1. zextloadi1 and +// extloadi1 land on us as i16-result loads with `s8`/i1 memory type; +// emit them as a normal byte load + mask (zext) or bare load (ext). +def : Pat<(i16 (zextloadi1 (W65816Wrapper tglobaladdr:$g))), + (ANDi16imm (LDAabs tglobaladdr:$g), 0xFF)>; +def : Pat<(i16 (extloadi1 (W65816Wrapper tglobaladdr:$g))), + (LDAabs tglobaladdr:$g)>; +def : Pat<(i16 (sextloadi1 (W65816Wrapper tglobaladdr:$g))), + (ANDi16imm (LDAabs tglobaladdr:$g), 1)>; + // CMP / branches. CMP sets the flags via the W65816cmp SDNode (glue // out); the W65816brcc node consumes the glue and dispatches to the // right Bxx instruction by condition code. diff --git a/src/llvm/lib/Target/W65816/W65816LowerWide32.cpp b/src/llvm/lib/Target/W65816/W65816LowerWide32.cpp index afcb125..ef1752e 100644 --- a/src/llvm/lib/Target/W65816/W65816LowerWide32.cpp +++ b/src/llvm/lib/Target/W65816/W65816LowerWide32.cpp @@ -117,17 +117,33 @@ bool W65816LowerWide32::runOnMachineFunction(MachineFunction &MF) { MachineInstr *DefMI = MRI.getUniqueVRegDef(W); if (DefMI && DefMI->getOpcode() == TargetOpcode::REG_SEQUENCE) { Register Lo, Hi; + bool Bail = false; for (unsigned op = 1; op + 1 < DefMI->getNumOperands(); op += 2) { if (!DefMI->getOperand(op).isReg() || !DefMI->getOperand(op + 1).isImm()) continue; unsigned idx = DefMI->getOperand(op + 1).getImm(); Register Src = DefMI->getOperand(op).getReg(); + unsigned SrcSub = DefMI->getOperand(op).getSubReg(); + // If the source has a sub-register specifier (e.g. + // `%W.sub_lo:wide32` is a slice of a wide32 vreg), the + // effective "half" is the corresponding half of that source. + // Resolve via wideMap when the parent is already mapped; + // otherwise defer until a later iteration picks it up. + if (SrcSub != 0) { + if (!Src.isVirtual() || !wideMap.count(Src)) { + Bail = true; + break; + } + auto [SrcLo, SrcHi] = wideMap[Src]; + Src = (SrcSub == llvm::sub_lo) ? SrcLo : SrcHi; + } if (idx == llvm::sub_lo) Lo = Src; else if (idx == llvm::sub_hi) Hi = Src; } + if (Bail) continue; if (Lo && Hi) { wideMap[W] = {Lo, Hi}; toErase.push_back(DefMI); @@ -156,25 +172,38 @@ bool W65816LowerWide32::runOnMachineFunction(MachineFunction &MF) { MachineInstr *LoDefMI = nullptr; MachineInstr *HiDefMI = nullptr; bool ok = true; + bool Bail = false; for (MachineInstr &MI : MRI.def_instructions(W)) { if (!MI.isCopy()) { ok = false; break; } const MachineOperand &Dst = MI.getOperand(0); const MachineOperand &Src = MI.getOperand(1); if (!Dst.isReg() || Dst.getReg() != W) { ok = false; break; } unsigned SubIdx = Dst.getSubReg(); + Register S = Src.getReg(); + unsigned SrcSub = Src.getSubReg(); + // If the source has a sub-register specifier, resolve through + // wideMap[parent]. Symmetric with the REG_SEQUENCE handler + // above — without this, `%W.sub_lo = COPY %V.sub_lo:wide32` + // records the wide32 parent %V instead of %V's i16 sub_lo. + if (SrcSub != 0) { + if (!S.isVirtual() || !wideMap.count(S)) { Bail = true; break; } + auto [SL, SH] = wideMap[S]; + S = (SrcSub == llvm::sub_lo) ? SL : SH; + } if (SubIdx == llvm::sub_lo) { if (LoDefMI) { ok = false; break; } LoDefMI = &MI; - LoSrc = Src.getReg(); + LoSrc = S; } else if (SubIdx == llvm::sub_hi) { if (HiDefMI) { ok = false; break; } HiDefMI = &MI; - HiSrc = Src.getReg(); + HiSrc = S; } else { ok = false; break; } } + if (Bail) continue; if (ok && LoSrc && HiSrc) { wideMap[W] = {LoSrc, HiSrc}; if (LoDefMI) toErase.push_back(LoDefMI); diff --git a/src/llvm/lib/Target/W65816/W65816PromoteFiToImg.cpp b/src/llvm/lib/Target/W65816/W65816PromoteFiToImg.cpp index 8810bc2..3e3f52c 100644 --- a/src/llvm/lib/Target/W65816/W65816PromoteFiToImg.cpp +++ b/src/llvm/lib/Target/W65816/W65816PromoteFiToImg.cpp @@ -281,7 +281,11 @@ bool W65816PromoteFiToImg::runOnMachineFunction(MachineFunction &MF) { Name == "__modsi3" || Name == "__ashlhi3" || Name == "__lshrhi3" || Name == "__ashrhi3" || Name == "__ashlsi3" || Name == "__lshrsi3" || - Name == "__ashrsi3") + Name == "__ashrsi3" || + // 64-bit helpers: use $E0..$EE only, no IMG0..7 touch. + Name == "__ashldi3" || Name == "__lshrdi3" || + Name == "__ashrdi3" || Name == "__cmpdi2" || + Name == "__ucmpdi2") return true; return false; } diff --git a/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp b/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp index e3a1633..5b44b9f 100644 --- a/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp +++ b/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp @@ -54,6 +54,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" +#include using namespace llvm; @@ -131,6 +132,501 @@ static bool isImgSafeCall(const MachineInstr &MI) { } +// Phase 12 peephole — A-dead PHA/PLA bracket elision. Two shapes: +// +// (a) PEI single-store IMG-source-STAfi bracket. When the next op +// after PLA redefines A, the bracket is dead weight: +// +// PHA ; (LDA_DP $cx | TXA | TYA) ; STA_StackRel (off+2) ; PLA +// [next redefines A] +// → +// (LDA_DP $cx | TXA | TYA) ; STA_StackRel off +// +// (b) ImgCalleeSave multi-store bracket at function entry. When the +// post-PLA pattern is "STX_DP ... ; STA_StackRel destOff ; [redefines +// A]", the post-PLA STA is storing entry-A to its final slot — we +// reorder by hoisting that STA to BEFORE the bracket, then dropping +// PHA/PLA and reverting inner offsets: +// +// PHA ; (LDA_DP $cx ; STA_StackRel off+2)×N ; PLA +// STX_DP $cM ; STA_StackRel destOff +// [next redefines A] +// → +// STA_StackRel destOff ; hoisted, entry-A → slot first +// (LDA_DP $cx ; STA_StackRel off)×N +// STX_DP $cM ; STX stays after saves +// [next op] +// +// Restricted to the entry MBB starting at MBB.begin() to ensure the +// match is an ImgCalleeSave-emitted prologue bracket (and not a mid- +// function bracket where the post-PLA STA is consuming a *different* +// A value than what was preserved). +static bool elidePhaBracket(MachineFunction &MF, + const W65816InstrInfo *TII) { + bool Changed = false; + auto opNoTouchA = [](unsigned Op) { + switch (Op) { + case W65816::STX_DP: case W65816::STX_Abs: + case W65816::STY_DP: case W65816::STY_Abs: + return true; + default: + return false; + } + }; + auto opRedefinesA = [](unsigned Op) { + switch (Op) { + case W65816::LDA_DP: case W65816::LDA_StackRel: + case W65816::LDA_Abs: case W65816::LDA_Imm16: + case W65816::LDAabs: case W65816::LDAi16imm: + case W65816::TXA: case W65816::TYA: + case W65816::PLA: + return true; + default: + return false; + } + }; + + // --- Case (a): single-store brackets anywhere in any MBB. --- + for (MachineBasicBlock &MBB : MF) { + SmallVector ToErase; + for (auto It = MBB.begin(); It != MBB.end(); ++It) { + if (It->getOpcode() != W65816::PHA) continue; + auto Lda = std::next(It); + if (Lda == MBB.end()) continue; + unsigned LdaOp = Lda->getOpcode(); + bool LdaIsLoadDp = (LdaOp == W65816::LDA_DP); + bool LdaIsXfer = (LdaOp == W65816::TXA || LdaOp == W65816::TYA); + if (!LdaIsLoadDp && !LdaIsXfer) continue; + auto Sta = std::next(Lda); + if (Sta == MBB.end()) continue; + if (Sta->getOpcode() != W65816::STA_StackRel) continue; + auto Pla = std::next(Sta); + if (Pla == MBB.end()) continue; + if (Pla->getOpcode() != W65816::PLA) continue; + auto AfterPla = std::next(Pla); + if (AfterPla == MBB.end()) continue; + unsigned AfterPlaOp = AfterPla->getOpcode(); + bool AfterDeadA = opRedefinesA(AfterPlaOp); + // Forward-walk liveness: if AfterPla is a branch and ALL its + // successors' first ops redefine A (recursing through + // unconditional-branch trampolines), A is dead. + if (!AfterDeadA && AfterPla->isBranch()) { + bool AllDead = true; + std::function firstRedef = + [&](MachineBasicBlock *B, int Depth) -> bool { + if (Depth > 3 || !B || B->empty()) return false; + MachineInstr &MI = B->front(); + unsigned MOp = MI.getOpcode(); + if (opRedefinesA(MOp)) return true; + if (MOp == W65816::BRA || MOp == W65816::BRL || + MOp == W65816::JMP_Abs) { + for (auto &MO : MI.operands()) { + if (MO.isMBB()) { + return firstRedef(MO.getMBB(), Depth + 1); + } + } + } + return false; + }; + for (MachineBasicBlock *Succ : MBB.successors()) { + if (!firstRedef(Succ, 0)) { AllDead = false; break; } + } + if (AllDead && !MBB.succ_empty()) AfterDeadA = true; + } + if (!AfterDeadA) continue; + MachineOperand &OffMO = Sta->getOperand(0); + if (!OffMO.isImm()) continue; + int64_t Off = OffMO.getImm(); + if (Off < 2) continue; + OffMO.setImm(Off - 2); + ToErase.push_back(&*It); + ToErase.push_back(&*Pla); + } + for (MachineInstr *MI : ToErase) { + MI->eraseFromParent(); + Changed = true; + } + } + + // --- Case (c): multi-pair STA_DP-only bracket anywhere. --- + // IMG-to-IMG copies bracketed for A-preservation. No StackRel + // offsets to adjust (DP is absolute, immune to PHA shifts), so just + // drop PHA/PLA when A is dead at PLA's exit. + std::function firstRedef = + [&](MachineBasicBlock *B, int Depth) -> bool { + if (Depth > 3 || !B || B->empty()) return false; + MachineInstr &MI = B->front(); + unsigned MOp = MI.getOpcode(); + if (opRedefinesA(MOp)) return true; + if (MOp == W65816::BRA || MOp == W65816::BRL || + MOp == W65816::JMP_Abs) { + for (auto &MO : MI.operands()) { + if (MO.isMBB()) return firstRedef(MO.getMBB(), Depth + 1); + } + } + return false; + }; + for (MachineBasicBlock &MBB : MF) { + SmallVector ToErase; + for (auto It = MBB.begin(); It != MBB.end(); ++It) { + if (It->getOpcode() != W65816::PHA) continue; + // Walk inner LDA_DP + STA_DP pairs. + auto Inner = std::next(It); + int InnerPairs = 0; + bool BailInner = false; + while (Inner != MBB.end()) { + if (Inner->getOpcode() == W65816::PLA) break; + if (Inner->getOpcode() != W65816::LDA_DP) { BailInner = true; break; } + auto St = std::next(Inner); + if (St == MBB.end() || St->getOpcode() != W65816::STA_DP) { + BailInner = true; break; + } + ++InnerPairs; + Inner = std::next(St); + } + if (BailInner || Inner == MBB.end() || InnerPairs < 1) continue; + // Inner == PLA. Check liveness after PLA. + auto Post = std::next(Inner); + if (Post == MBB.end()) continue; + unsigned PostOp = Post->getOpcode(); + bool ADead = opRedefinesA(PostOp); + if (!ADead && Post->isBranch()) { + bool AllDead = true; + for (MachineBasicBlock *Succ : MBB.successors()) { + if (!firstRedef(Succ, 0)) { AllDead = false; break; } + } + if (AllDead && !MBB.succ_empty()) ADead = true; + } + if (!ADead) continue; + // Eligible: drop PHA + PLA (no offset adjustment for DP). + ToErase.push_back(&*It); + ToErase.push_back(&*Inner); + } + for (MachineInstr *MI : ToErase) { + MI->eraseFromParent(); + Changed = true; + } + } + + // --- Case (b): ImgCalleeSave prologue bracket in entry MBB. --- + // PHA must be the FIRST instruction (or first after PEI prologue ops + // like REP/TAY/TSC/SEC/SBC/TCS/TYA) in the entry MBB. This ensures + // we're looking at the prologue's IMG save block. + MachineBasicBlock &EntryMBB = MF.front(); + auto BB = EntryMBB.begin(); + // Skip PEI prologue ops to reach the first ImgCalleeSave PHA. + while (BB != EntryMBB.end()) { + unsigned Op = BB->getOpcode(); + if (Op == W65816::PHA) break; + // PEI prologue ops we expect to see before ImgCalleeSave's PHA. + if (Op == W65816::REP || Op == W65816::TAY || + Op == W65816::TSC || Op == W65816::SEC || + Op == W65816::SBC_Imm16 || Op == W65816::TCS || + Op == W65816::TYA) { + ++BB; + continue; + } + BB = EntryMBB.end(); // not a recognized prologue shape — bail + break; + } + if (BB != EntryMBB.end() && BB->getOpcode() == W65816::PHA) { + SmallVector InnerStas; + auto Inner = std::next(BB); + bool BailInner = false; + while (Inner != EntryMBB.end()) { + unsigned IOp = Inner->getOpcode(); + if (IOp == W65816::PLA) break; + // Inner must be alternating LDA_DP + STA_StackRel pairs. + if (IOp != W65816::LDA_DP) { BailInner = true; break; } + auto St = std::next(Inner); + if (St == EntryMBB.end() || St->getOpcode() != W65816::STA_StackRel) { + BailInner = true; break; + } + MachineOperand &OffMO = St->getOperand(0); + if (!OffMO.isImm() || OffMO.getImm() < 2) { + BailInner = true; break; + } + InnerStas.push_back(&*St); + Inner = std::next(St); + } + if (!BailInner && Inner != EntryMBB.end() && !InnerStas.empty()) { + // Inner == PLA. Walk forward through STX_DP / STY_DP (A- + // transparent) ops looking for STA_StackRel that consumes + // entry-A, then verify next op redefines A. + auto Post = std::next(Inner); + while (Post != EntryMBB.end() && opNoTouchA(Post->getOpcode())) { + ++Post; + } + if (Post != EntryMBB.end() && + Post->getOpcode() == W65816::STA_StackRel) { + auto AfterSta = std::next(Post); + if (AfterSta != EntryMBB.end() && + opRedefinesA(AfterSta->getOpcode())) { + // Eligible. Move STA destOff to right BEFORE PHA, drop + // PHA + PLA, shift inner STA offsets by -2. + MachineInstr *StaToMove = &*Post; + MachineInstr *PhaMI = &*BB; + MachineInstr *PlaMI = &*Inner; + // splice: move StaToMove to position just before PhaMI. + EntryMBB.splice(PhaMI->getIterator(), &EntryMBB, + StaToMove->getIterator()); + for (MachineInstr *Sta : InnerStas) { + Sta->getOperand(0).setImm(Sta->getOperand(0).getImm() - 2); + } + PhaMI->eraseFromParent(); + PlaMI->eraseFromParent(); + Changed = true; + } + } + } + } + return Changed; +} + + +// Always-on: elide the STA $E0 / LDA $E0 round-trip in +// ADJCALLSTACKUP's Y-live i64-return path when the next instruction +// after the LDA is `STA_StackRel off,s` storing A to a slot. The +// emitted PEI sequence (see W65816FrameLowering ADJCALLSTACKUP): +// +// STA_DP $E0 ; save A across TSC +// TSC ; A = S +// CLC ; ADC_Imm16 #N ; TCS ; pop N bytes +// LDA_DP $E0 ; restore A +// STA_StackRel off, s ; store A to slot +// +// If the destination's pre-adjust offset (off + N) fits in a 1-byte +// stack-rel encoding, we can move the STA up to BEFORE the SP-adjust +// (using the pre-adjust offset) and drop both the save and reload. +// +// Saves 6 bytes + 8 cyc per match. evalAt has 4 of these. +static bool elideCallResultSaveSPReload(MachineFunction &MF, + const W65816InstrInfo *TII) { + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + SmallVector ToErase; + for (auto It = MBB.begin(); It != MBB.end(); ++It) { + if (It->getOpcode() != W65816::STA_DP) continue; + MachineOperand &SaveImm = It->getOperand(0); + if (!SaveImm.isImm() || SaveImm.getImm() != 0xE0) continue; + auto I1 = std::next(It); + if (I1 == MBB.end() || I1->getOpcode() != W65816::TSC) continue; + auto I2 = std::next(I1); + if (I2 == MBB.end() || I2->getOpcode() != W65816::CLC) continue; + auto I3 = std::next(I2); + if (I3 == MBB.end() || I3->getOpcode() != W65816::ADC_Imm16) continue; + MachineOperand &AdcImm = I3->getOperand(0); + if (!AdcImm.isImm()) continue; + int64_t N = AdcImm.getImm(); + auto I4 = std::next(I3); + if (I4 == MBB.end() || I4->getOpcode() != W65816::TCS) continue; + auto I5 = std::next(I4); + if (I5 == MBB.end() || I5->getOpcode() != W65816::LDA_DP) continue; + MachineOperand &LoadImm = I5->getOperand(0); + if (!LoadImm.isImm() || LoadImm.getImm() != 0xE0) continue; + auto I6 = std::next(I5); + if (I6 == MBB.end() || I6->getOpcode() != W65816::STA_StackRel) continue; + MachineOperand &StaImm = I6->getOperand(0); + if (!StaImm.isImm()) continue; + int64_t Off = StaImm.getImm(); + int64_t NewOff = Off + N; + if (NewOff < 0 || NewOff > 255) continue; + // Insert a new STA_StackRel at NewOff before the STA_DP $E0. + BuildMI(MBB, It, It->getDebugLoc(), TII->get(W65816::STA_StackRel)) + .addImm(NewOff); + ToErase.push_back(&*It); // STA_DP $E0 + ToErase.push_back(&*I5); // LDA_DP $E0 + ToErase.push_back(&*I6); // original STA_StackRel + } + for (MachineInstr *MI : ToErase) { + MI->eraseFromParent(); + Changed = true; + } + } + return Changed; +} + + +// Returns true if the opcode is "transparent" to a STA→LDA forward — +// does not write A, does not change S, does not write to any stack +// memory. Used to widen the elideStoreForwarding peephole's window. +static bool isStaLdaTransparent(unsigned Opc) { + switch (Opc) { + // X/Y register ops (don't touch A or S) + case W65816::LDX_Imm16: case W65816::LDX_DP: case W65816::LDX_Abs: + case W65816::LDXi16imm: + case W65816::LDY_Imm16: case W65816::LDY_DP: case W65816::LDY_Abs: + case W65816::TAX: case W65816::TAY: + case W65816::INX: case W65816::INY: + case W65816::DEX: case W65816::DEY: + case W65816::STX_DP: case W65816::STX_Abs: + case W65816::STY_DP: case W65816::STY_Abs: + // Flag ops + case W65816::CLC: case W65816::SEC: + case W65816::CLD: case W65816::SED: + case W65816::CLI: case W65816::SEI: + case W65816::CLV: + case W65816::NOP: + return true; + default: + return false; + } +} + + +// Always-on: drop a redundant LDA following STA to the same slot when +// any intermediate ops are "transparent" (don't write A or change S +// or stack memory). STA doesn't modify A, so A still holds the value. +// +// STA off, s +// LDX #imm ; transparent +// LDA off, s ; redundant — A unchanged since STA +// +// Saves 1 instruction (3 bytes / 4 cyc) per match. +static bool elideStoreForwarding(MachineFunction &MF) { + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + SmallVector ToErase; + for (auto It = MBB.begin(); It != MBB.end(); ++It) { + if (It->getOpcode() != W65816::STA_StackRel) continue; + MachineOperand &S = It->getOperand(0); + if (!S.isImm()) continue; + int64_t StaOff = S.getImm(); + // Walk forward up to 3 ops looking for matching LDA. + MachineBasicBlock::iterator Walk = std::next(It); + int Steps = 0; + while (Walk != MBB.end() && Steps < 3) { + unsigned WOp = Walk->getOpcode(); + if (WOp == W65816::LDA_StackRel) { + MachineOperand &L = Walk->getOperand(0); + if (L.isImm() && L.getImm() == StaOff) { + ToErase.push_back(&*Walk); + } + break; + } + if (!isStaLdaTransparent(WOp)) break; + ++Walk; + ++Steps; + } + } + for (MachineInstr *MI : ToErase) { + MI->eraseFromParent(); + Changed = true; + } + } + return Changed; +} + + +// Always-on: drop a consecutive PLA/PHA pair. PLA restores A from +// the stack; PHA immediately pushes the same A back. Net is a no-op +// in both A and stack memory. Emerges when multiple adjacent IMG +// copies are each bracketed with PHA/PLA for A-preservation: +// +// PHA ; LDA dp ; STA dp ; PLA ; PHA ; LDA dp ; STA dp ; PLA +// ^^^^^^^^^^ +// collapsed away +// +// Saves 2 instructions (2 bytes / 7 cyc) per match. +static bool elidePlaPhaPair(MachineFunction &MF) { + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + SmallVector ToErase; + for (auto It = MBB.begin(); It != MBB.end(); ++It) { + if (It->getOpcode() != W65816::PLA) continue; + auto I1 = std::next(It); + if (I1 == MBB.end() || I1->getOpcode() != W65816::PHA) continue; + ToErase.push_back(&*It); + ToErase.push_back(&*I1); + ++It; // advance past PHA (already-to-erase) + } + for (MachineInstr *MI : ToErase) { + MI->eraseFromParent(); + Changed = true; + } + } + return Changed; +} + + +// Always-on: drop a redundant LDA when the prior LDA loaded the same +// source and the only intervening instruction was PHA (which reads A +// but doesn't modify it). Emerges from i64 arg-push sequences: +// +// LDA off, s +// PHA +// LDA off, s ; A still has this value — redundant +// PHA +// +// Saves 1 instruction (3 bytes / 4 cyc) per match. +static bool elideRedundantLdaAfterPha(MachineFunction &MF) { + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + SmallVector ToErase; + for (auto It = MBB.begin(); It != MBB.end(); ++It) { + unsigned Op = It->getOpcode(); + bool IsLdaSr = (Op == W65816::LDA_StackRel); + bool IsLdaDp = (Op == W65816::LDA_DP); + if (!IsLdaSr && !IsLdaDp) continue; + auto I1 = std::next(It); + if (I1 == MBB.end() || I1->getOpcode() != W65816::PHA) continue; + auto I2 = std::next(I1); + if (I2 == MBB.end() || I2->getOpcode() != Op) continue; + MachineOperand &S1 = It->getOperand(0); + MachineOperand &S2 = I2->getOperand(0); + if (!S1.isImm() || !S2.isImm()) continue; + if (S1.getImm() != S2.getImm()) continue; + ToErase.push_back(&*I2); + } + for (MachineInstr *MI : ToErase) { + MI->eraseFromParent(); + Changed = true; + } + } + return Changed; +} + + +// Always-on: drop a dead STA in the i32-carry-propagation pattern: +// +// STA_StackRel off, s +// ADC_Imm16 #N ; doesn't touch slot +// STA_StackRel off, s ; overwrites first STA +// +// The first STA's value is shadowed by the second. Drop it. +// Saves 1 instruction (3 bytes / 5 cyc) per match. +static bool elideDeadStaCarry(MachineFunction &MF) { + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + SmallVector ToErase; + for (auto It = MBB.begin(); It != MBB.end(); ++It) { + if (It->getOpcode() != W65816::STA_StackRel) continue; + auto I1 = std::next(It); + if (I1 == MBB.end()) continue; + unsigned MidOp = I1->getOpcode(); + bool IsAddImm = (MidOp == W65816::ADC_Imm16 || + MidOp == W65816::ADCi16imm || + MidOp == W65816::ADCEi16imm || + MidOp == W65816::SBCi16imm || + MidOp == W65816::SBCEi16imm); + if (!IsAddImm) continue; + auto I2 = std::next(I1); + if (I2 == MBB.end() || I2->getOpcode() != W65816::STA_StackRel) continue; + MachineOperand &Off1 = It->getOperand(0); + MachineOperand &Off2 = I2->getOperand(0); + if (!Off1.isImm() || !Off2.isImm()) continue; + if (Off1.getImm() != Off2.getImm()) continue; + ToErase.push_back(&*It); + } + for (MachineInstr *MI : ToErase) { + MI->eraseFromParent(); + Changed = true; + } + } + return Changed; +} + + bool W65816StackRelToImg::runOnMachineFunction(MachineFunction &MF) { if (skipFunction(MF.getFunction())) return false; if (MF.getFunction().hasOptNone()) return false; @@ -139,26 +635,48 @@ bool W65816StackRelToImg::runOnMachineFunction(MachineFunction &MF) { // be from FP not SP and the PHP-wrap +1 adjustment differs. if (MF.getFrameInfo().hasVarSizedObjects()) return false; + // Always-on peepholes that run even when the main IMG promotion bails. + const W65816Subtarget &STIp = MF.getSubtarget(); + // Run PLA;PHA collapse FIRST so adjacent brackets merge into a + // single multi-pair bracket — lets elidePhaBracket case (c) match + // the merged shape. + bool ChangedEarly = elidePlaPhaPair(MF); + ChangedEarly |= elidePhaBracket(MF, STIp.getInstrInfo()); + ChangedEarly |= elideCallResultSaveSPReload(MF, STIp.getInstrInfo()); + ChangedEarly |= elideDeadStaCarry(MF); + ChangedEarly |= elideRedundantLdaAfterPha(MF); + // elideStoreForwarding only when main IMG promotion would bail — + // running it early in non-bailing functions cascades into IMG-slot + // reallocation that regresses strcpy 1.63×. Gated below. + // 2. Bail if the function has any non-IMG-safe call (would clobber // our IMG0..7 promotions) or is recursive (same). Tried allowing - // IMG8..15 + ImgCalleeSave fallback for these cases (gained 12 - // inst on evalAt), but broke sprintf and fib due to subtle - // interactions with ImgCalleeSave's slot allocation. Reverted. + // IMG8..15 + own-pass save/restore for these cases (today, after + // landing W65816LowerWide32 + ImgCalleeSave-writes-only fixes), and + // saw: evalAt 498→500 (NET LOSS due to save/restore overhead) AND + // qsort #70 regression. The IMG8..15 path is not currently a win + // for our benchmarks; reverted. StringRef SelfName = MF.getName(); for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { if (!MI.isCall()) continue; - if (!isImgSafeCall(MI)) return false; + if (!isImgSafeCall(MI)) { + ChangedEarly |= elideStoreForwarding(MF); + return ChangedEarly; + } for (const MachineOperand &MO : MI.operands()) { StringRef Name; if (MO.isGlobal()) Name = MO.getGlobal()->getName(); else if (MO.isSymbol()) Name = MO.getSymbolName(); else continue; - if (Name == SelfName) return false; + if (Name == SelfName) { + ChangedEarly |= elideStoreForwarding(MF); + return ChangedEarly; + } } } } - uint8_t imgBase = 0xD0; + uint8_t imgBase = 0xD0u; // 3. Count stack-rel accesses per offset. CRITICAL: the stack // pointer shifts during the function due to PHP/PLP (+1 byte) and @@ -614,23 +1132,65 @@ bool W65816StackRelToImg::runOnMachineFunction(MachineFunction &MF) { auto Tya = std::next(Tcs); while (Tya != EntryMBB.end() && Tya->isDebugInstr()) ++Tya; if (Tya != EntryMBB.end() && Tya->getOpcode() == W65816::TYA) { + // Walk past A-transparent ops (STX_DP, STY_DP) — these + // don't touch A, so TAY/TYA can still be removed. auto Sta = std::next(Tya); - while (Sta != EntryMBB.end() && Sta->isDebugInstr()) ++Sta; + while (Sta != EntryMBB.end() && + (Sta->isDebugInstr() || + Sta->getOpcode() == W65816::STX_DP || + Sta->getOpcode() == W65816::STY_DP)) { + ++Sta; + } if (Sta != EntryMBB.end() && - Sta->getOpcode() == W65816::STA_DP && Sta->getNumOperands() >= 1 && Sta->getOperand(0).isImm()) { - int64_t StaAddr = Sta->getOperand(0).getImm(); - // Build new STA_DP between REP and TSC. - DebugLoc DL = Sta->getDebugLoc(); - BuildMI(EntryMBB, Tsc, DL, TII->get(W65816::STA_DP)) - .addImm(StaAddr) - .addReg(W65816::A, RegState::Implicit); - // Erase: TAY, TYA, old STA_DP. - Tay->eraseFromParent(); - Tya->eraseFromParent(); - Sta->eraseFromParent(); - Changed = true; + unsigned StaOp = Sta->getOpcode(); + bool IsStaDp = (StaOp == W65816::STA_DP); + bool IsStaSr = (StaOp == W65816::STA_StackRel); + if (IsStaDp || IsStaSr) { + // For STA_StackRel: pre-TCS offset = post-TCS_off - N + // where N = SBC immediate. Only valid if off >= N. + int64_t StaAddr = Sta->getOperand(0).getImm(); + int64_t SbcImm = Sbc->getOperand(0).isImm() + ? Sbc->getOperand(0).getImm() : -1; + // Drop ADCi16imm pseudo-tied operands: imm is at op 0 for + // SBC_Imm16 but op 2 for SBCi16imm — handle uniformly. + if (!Sbc->getOperand(0).isImm() && + Sbc->getNumOperands() >= 3 && + Sbc->getOperand(2).isImm()) { + SbcImm = Sbc->getOperand(2).getImm(); + } + int64_t NewAddr = IsStaDp ? StaAddr : (StaAddr - SbcImm); + bool OffOk = IsStaDp || (NewAddr >= 1 && SbcImm > 0); + // Safety: the op after the spill-STA must REDEFINE A + // (not read it). Otherwise A would be lost (TCS + // clobbered it). + auto Next = std::next(Sta); + while (Next != EntryMBB.end() && Next->isDebugInstr()) + ++Next; + bool NextRedef = false; + if (Next != EntryMBB.end()) { + unsigned NOp = Next->getOpcode(); + NextRedef = + NOp == W65816::LDA_DP || NOp == W65816::LDA_StackRel || + NOp == W65816::LDA_Abs || NOp == W65816::LDA_Imm16 || + NOp == W65816::LDAabs || NOp == W65816::LDAi16imm || + NOp == W65816::TXA || NOp == W65816::TYA || + NOp == W65816::PLA; + } + if (OffOk && NextRedef) { + // Build new STA_ between REP and TSC. + DebugLoc DL = Sta->getDebugLoc(); + BuildMI(EntryMBB, Tsc, DL, TII->get(StaOp)) + .addImm(NewAddr) + .addReg(W65816::A, RegState::Implicit); + // Erase: TAY, TYA, old STA. + Tay->eraseFromParent(); + Tya->eraseFromParent(); + Sta->eraseFromParent(); + Changed = true; + } + } } } } @@ -1459,5 +2019,17 @@ bool W65816StackRelToImg::runOnMachineFunction(MachineFunction &MF) { } } + // Run elideStoreForwarding at the very end, AFTER IMG promotion has + // committed slot assignments. Running this peephole earlier (with + // the other early peepholes) cascades into different IMG-promotion + // choices and was observed to regress strcpy 1.63×. At this point + // promotion is done, so dropping a redundant LDA can no longer + // disturb slot allocation. + // End-of-pass: also try elideStoreForwarding for non-bailing + // functions. After main IMG promotion finalizes slot assignments, + // dropping a redundant LDA can no longer disturb them. + Changed |= elideStoreForwarding(MF); + + Changed |= ChangedEarly; return Changed; }