diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cb2dce8..501f553 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -169,6 +169,8 @@ /core/saga-registers/sprite-collision.md @WDrijver /core/saga-registers/system.md @WDrijver /core/saga-video-isabelle/index.md @WDrijver +/examples/saga-pip-overlay-and-chroma-key.md @WDrijver +/examples/saga-pointer-sprite.md @WDrijver /hardware/index.md @WDrijver /os/apolloos-and-amigaos-on-v4.md @WDrijver /os/apolloos-specific-on-v4.md @WDrijver @@ -187,7 +189,15 @@ /toolchain/project-makefile.md @WDrijver /toolchain/target-os-headers.md @WDrijver /toolchain/vasm-assembler.md @WDrijver +/toolchain/apollolib/debug.md @WDrijver +/toolchain/apollolib/index.md @WDrijver +/toolchain/apollolib/input.md @WDrijver +/toolchain/apollolib/memory-and-blit.md @WDrijver +/toolchain/apollolib/picture.md @WDrijver +/toolchain/apollolib/sound.md @WDrijver +/toolchain/apollolib/system-and-timing.md @WDrijver /toolchain/best-practices/gcc-code-generation-for-68080.md @TuKo1982 +/toolchain/pitfalls/apollolib-known-bugs.md @WDrijver /toolchain/pitfalls/calling-assembler-from-gcc.md @TuKo1982 /toolchain/pitfalls/float-settings-mismatch.md @TuKo1982 /toolchain/pitfalls/gcc-bbb-autoinc.md @TuKo1982 diff --git a/.github/workflows/kb-checks.yml b/.github/workflows/kb-checks.yml index 7bdc267..9b2d5dd 100644 --- a/.github/workflows/kb-checks.yml +++ b/.github/workflows/kb-checks.yml @@ -44,6 +44,7 @@ jobs: env: ACD_DIR: /home/runner/ApolloCrossDev PREFIX: /home/runner/ApolloCrossDev/Compilers/GCC-6.50-Dev + APOLLOLIB: /home/runner/acd-src/Projects/ApolloLib steps: - uses: actions/checkout@v4 @@ -52,6 +53,16 @@ jobs: - name: Find ApolloCrossDev commit id: acd run: echo "sha=$(git ls-remote https://github.com/WDrijver/ApolloCrossDev refs/heads/main | cut -f1)" >> "$GITHUB_OUTPUT" + # Snippets may include ApolloLib's headers: fetch only Projects/ApolloLib + # of the same commit (a few hundred KB), also when the toolchain is cached. + - name: Fetch ApolloLib + run: | + git init -q /home/runner/acd-src + cd /home/runner/acd-src + git sparse-checkout set --no-cone Projects/ApolloLib + git fetch -q --depth 1 --filter=blob:none https://github.com/WDrijver/ApolloCrossDev ${{ steps.acd.outputs.sha }} + git checkout -q FETCH_HEAD + test -f "$APOLLOLIB/ApolloCrossDev_Lib.h" - name: Restore ApolloCrossDev id: cache uses: actions/cache/restore@v4 diff --git a/core/best-practices/prefer-library-calls-for-saga-chips.md b/core/best-practices/prefer-library-calls-for-saga-chips.md index b351dea..070a5d1 100644 --- a/core/best-practices/prefer-library-calls-for-saga-chips.md +++ b/core/best-practices/prefer-library-calls-for-saga-chips.md @@ -13,6 +13,7 @@ tags: [saga, arne, isabelle, maggie, library, apollolib, maggie-library, registe related: - core/saga-registers/index.md - os/libraries/maggie-library.md + - toolchain/apollolib/index.md - core/saga-audio-arne/index.md - core/saga-video-isabelle/index.md - core/saga-3d-maggie/index.md @@ -41,7 +42,10 @@ For the SAGA chips, prefer the library calls to direct register access - An official library for Arne and Isabelle is in development. Until it is released, ApolloLib is the best choice for library calls to Arne and - Isabelle. + Isabelle. It is described in + [toolchain/apollolib/](../../toolchain/apollolib/index.md); check its + [fixed bugs and remaining limits](../../toolchain/pitfalls/apollolib-known-bugs.md) + first. - maggie.library is described in [os/libraries/maggie-library.md](../../os/libraries/maggie-library.md). When you need more than that file covers, the author's repository is the diff --git a/core/saga-registers/arne-channels.md b/core/saga-registers/arne-channels.md index 1e07fb7..79b3ca5 100644 --- a/core/saga-registers/arne-channels.md +++ b/core/saga-registers/arne-channels.md @@ -17,7 +17,7 @@ related: - core/best-practices/prefer-library-calls-for-saga-chips.md sources: - "SAGA register documentation, sources/official/saga-registers/ (HTML)" - - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)" - "WDrijver (maintainer), answers on the SAGA register documentation, 2026-11-04" - "Gunnar (core developer, BigGun), Apollo chat, 2026-11-04 (relayed by WDrijver)" generated_from: sources/official/saga-registers/index.htm diff --git a/core/saga-registers/chunky-plane.md b/core/saga-registers/chunky-plane.md index 3818d96..104ef6c 100644 --- a/core/saga-registers/chunky-plane.md +++ b/core/saga-registers/chunky-plane.md @@ -15,7 +15,7 @@ related: - core/best-practices/prefer-library-calls-for-saga-chips.md sources: - "SAGA register documentation, sources/official/saga-registers/ (HTML)" - - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)" - "maggie.library samples, see os/libraries/maggie-library.md" generated_from: sources/official/saga-registers/index.htm --- diff --git a/core/saga-registers/colour-ports.md b/core/saga-registers/colour-ports.md index 9faf194..941b970 100644 --- a/core/saga-registers/colour-ports.md +++ b/core/saga-registers/colour-ports.md @@ -15,7 +15,7 @@ related: - core/best-practices/prefer-library-calls-for-saga-chips.md sources: - "SAGA register documentation, sources/official/saga-registers/ (HTML)" - - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)" - "Gunnar (core developer, BigGun), Apollo chat, 2026-11-04 (relayed by WDrijver)" generated_from: sources/official/saga-registers/index.htm --- diff --git a/core/saga-registers/index.md b/core/saga-registers/index.md index b8c1067..52605fb 100644 --- a/core/saga-registers/index.md +++ b/core/saga-registers/index.md @@ -14,7 +14,7 @@ related: - core/best-practices/prefer-library-calls-for-saga-chips.md sources: - "SAGA register documentation, sources/official/saga-registers/ (HTML)" - - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)" - "WDrijver (maintainer), answers on the SAGA register documentation, 2026-11-04" - "Gunnar (core developer, BigGun), Apollo chat, 2026-11-04 (relayed by WDrijver)" generated_from: sources/official/saga-registers/index.htm diff --git a/core/saga-registers/input.md b/core/saga-registers/input.md index 9e15f92..fc4aa2f 100644 --- a/core/saga-registers/input.md +++ b/core/saga-registers/input.md @@ -15,7 +15,7 @@ related: - core/best-practices/prefer-library-calls-for-saga-chips.md sources: - "SAGA register documentation, sources/official/saga-registers/ (HTML)" - - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)" generated_from: sources/official/saga-registers/index.htm --- diff --git a/core/saga-registers/pip.md b/core/saga-registers/pip.md index 925ab33..dc17d63 100644 --- a/core/saga-registers/pip.md +++ b/core/saga-registers/pip.md @@ -17,8 +17,8 @@ related: - core/best-practices/prefer-library-calls-for-saga-chips.md sources: - "SAGA register documentation, sources/official/saga-registers/ (HTML)" - - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)" - - "Example SAGAPiP.c, github.com/WDrijver/ApolloCrossDev Projects/SAGAPiP, commit 2dfaa5c (2026-09-02)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)" + - "Example ApolloPiP.c (formerly SAGAPiP), github.com/WDrijver/ApolloCrossDev Projects/ApolloPiP, commit ad7f0b4 (2026-11-04)" - "WDrijver (maintainer), answers on the SAGA register documentation, 2026-11-04" generated_from: sources/official/saga-registers/index.htm --- @@ -45,7 +45,7 @@ SAGA overlays up to two picture-in-picture windows (PIP) on the main screen, eac | `$DFF3E0` | PipColorKey | W | ColorKey 1000,RRRR,GGGG,BBBB | | `$DFF3E2` | PipDMARowLen | W | PipDMARowLen | -The original links these rows to a page that doesn't exist; the facts below come from ApolloLib and the SAGAPiP example (SRC). +The original links these rows to a page that doesn't exist; the facts below come from ApolloLib and the ApolloPiP example (SRC). ### PIP 2 registers (SRC, not in the original) @@ -63,7 +63,7 @@ PIP 2 has the same layout as PIP 1, `$20` lower (ApolloLib): | `$DFF3C0` | PIP2 colour key | `$DFF3E0` | | `$DFF3C2` | PIP2 DMA row length | `$DFF3E2` | -Its colour port is `$DFF37C` (see [colour-ports.md](colour-ports.md)). The SAGAPiP example says two PIPs exist from Core 11900 (SRC). +Its colour port is `$DFF37C` (see [colour-ports.md](colour-ports.md)). The ApolloPiP example says two PIPs exist from Core 11900 (SRC). ### Register meanings (SRC) @@ -90,7 +90,7 @@ Its colour port is `$DFF37C` (see [colour-ports.md](colour-ports.md)). The SAGAP Formats and transparent colours: WDrijver, 2026-11-04. The transparent colour is fixed per format. ApolloLib still marks YUV as not supported on PIP; that is an error in ApolloLib, not in the hardware. -### Two modes (SAGAPiP example, SRC) +### Two modes (ApolloPiP example, SRC) - **Overlay:** colour key 0. The PIP is in front of the main screen; with format bit 8 set, pixels in the transparent colour of the format are transparent. - **Chroma key:** colour key with bit 15 set, for example `$8F0F` (purple). The PIP is behind the main screen and shows only where the main screen has the key colour. diff --git a/core/saga-registers/pointer.md b/core/saga-registers/pointer.md index d9332e0..ca9d10b 100644 --- a/core/saga-registers/pointer.md +++ b/core/saga-registers/pointer.md @@ -15,9 +15,9 @@ related: - core/best-practices/prefer-library-calls-for-saga-chips.md sources: - "SAGA register documentation, sources/official/saga-registers/ (HTML)" - - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)" - "ApolloLib, older copy in ApolloClaude docs/toolchain/_ApolloLib (ApolloCrossDev_Defines.h), 2026-11-04" - - "Example ApolloPointer.c, github.com/WDrijver/ApolloCrossDev Projects/ApolloPointer, commit 2dfaa5c (2026-09-02)" + - "Example ApolloPointer.c, github.com/WDrijver/ApolloCrossDev Projects/ApolloPointer, commit ad7f0b4 (2026-11-04)" - "WDrijver (maintainer), answers on the SAGA register documentation, 2026-11-04" generated_from: sources/official/saga-registers/index.htm --- diff --git a/examples/saga-pip-overlay-and-chroma-key.md b/examples/saga-pip-overlay-and-chroma-key.md new file mode 100644 index 0000000..ad287c0 --- /dev/null +++ b/examples/saga-pip-overlay-and-chroma-key.md @@ -0,0 +1,136 @@ +--- +title: SAGA PIP in overlay and chroma-key mode (from the ApolloPiP example) +type: example +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [saga-video-isabelle, toolchain] +applies_to: + core: "Core 12000+" + os: [any] +tags: [saga, isabelle, pip, overlay, chroma-key, apollolib, example] +related: + - core/saga-registers/pip.md + - core/saga-registers/colour-ports.md + - toolchain/apollolib/picture.md + - core/best-practices/prefer-library-calls-for-saga-chips.md +sources: + - "Example ApolloPiP.c (formerly SAGAPiP), github.com/WDrijver/ApolloCrossDev Projects/ApolloPiP, commit ad7f0b4 (2026-11-04)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib, commit ad7f0b4 (2026-11-04)" +--- + +## Purpose + +Show a picture-in-picture (PIP) window on top of the screen (overlay mode) +and behind it (chroma-key mode), with ApolloLib. The code below is the PIP +part of ApolloCrossDev's ApolloPiP example, in three functions: + +- `ShowPiP1Overlay`: an 8-bit PIP in front of the screen; palette index + `$FF` is transparent. +- `ShowPiP1Behind`: a 16-bit PIP behind the screen, visible where the + screen is purple (the chroma key). +- `HidePiP1`: PIP 1 off. + +The full ApolloPiP program does more: it plays a soundtrack, shows a +1280x720 background, opens a Workbench window, lays PIP 1 and PIP 2 over +it and follows the window when it moves (see "The full example" below). + +## Build + +The functions compile as a library unit. In a project that uses ApolloLib +(see [toolchain/apollolib/index.md](../toolchain/apollolib/index.md)): + +```sh +m68k-amigaos-gcc -noixemul -O2 -m68080 -m68881 -ffast-math -fomit-frame-pointer -Wall \ + -I$APOLLOLIB -c pip.c -o pip.o +``` + +The full example builds in ApolloCrossDev with `make` in +`Projects/ApolloPiP` (which also uploads it to the Apollo V4), or +`make cleanbefore build` to only build. + +## Code + +```c +// kb:compile +/* SAGA PIP with ApolloLib: overlay and chroma-key mode, after the ApolloPiP + example in ApolloCrossDev Projects/ApolloPiP. Needs ApolloLib a9a994f+: + from there ApolloShowPiP1 also loads the palette of an 8-bit picture. */ +#include "ApolloCrossDev_Lib.h" + +#define PIP1_REG(a) (*(volatile UWORD *)(a)) + +/* Overlay mode: PIP 1 lies in front of the screen at (left, top). With the + transparency bit, palette index $FF is transparent. */ +void ShowPiP1Overlay(struct ApolloPicture *pic, WORD left, WORD top) +{ + *(volatile ULONG *)APOLLO_SAGA_PIP1_POINTER = (ULONG)(pic->buffer + pic->position); + PIP1_REG(APOLLO_SAGA_PIP1_X_START) = left + 16; /* +16 and -1: as in ApolloPiP */ + PIP1_REG(APOLLO_SAGA_PIP1_X_STOP) = left + pic->width + 16; + PIP1_REG(APOLLO_SAGA_PIP1_Y_START) = top - 1; + PIP1_REG(APOLLO_SAGA_PIP1_Y_STOP) = top + pic->height - 1; + PIP1_REG(APOLLO_SAGA_PIP1_GFXMODE) = APOLLO_SAGA_PIP_TRANSON | APOLLO_SAGA_8_INDEX; + PIP1_REG(APOLLO_SAGA_PIP1_MODULO) = 0; + PIP1_REG(APOLLO_SAGA_PIP1_CLRKEY) = 0x0000; /* 0 = overlay mode */ + ApolloShowPiP1(pic); /* palette, then DMA row length: PIP on */ +} + +/* Chroma-key mode: PIP 1 lies behind the screen and shows only where the + screen has the key colour, here purple ($F0F in RGB444). */ +void ShowPiP1Behind(struct ApolloPicture *pic16, WORD width, WORD height) +{ + *(volatile ULONG *)APOLLO_SAGA_PIP1_POINTER = (ULONG)(pic16->buffer + pic16->position); + PIP1_REG(APOLLO_SAGA_PIP1_X_START) = 16; + PIP1_REG(APOLLO_SAGA_PIP1_X_STOP) = width + 16; + PIP1_REG(APOLLO_SAGA_PIP1_Y_START) = 0; + PIP1_REG(APOLLO_SAGA_PIP1_Y_STOP) = height; + PIP1_REG(APOLLO_SAGA_PIP1_GFXMODE) = APOLLO_SAGA_16_R5G6B5; + PIP1_REG(APOLLO_SAGA_PIP1_MODULO) = 0; + PIP1_REG(APOLLO_SAGA_PIP1_CLRKEY) = 0x8F0F; /* bit 15 = on, R=$F G=$0 B=$F */ + ApolloShowPiP1(pic16); +} + +/* Switch PIP 1 off: DMA row length 0. */ +void HidePiP1(void) +{ + ApolloHidePiP1(); +} +``` + +Load the pictures with `ApolloLoadPicture` first: an 8-bit BMP for the +overlay, a 16-bit DDS (R5G6B5) for the background. + +## Expected result + +- **Overlay:** after `ShowPiP1Overlay(&pic, left, top)` the 8-bit picture + appears over the screen, its top-left corner at (`left`, `top`) in + screen pixels. Pixels with palette index `$FF` show the screen behind. +- **Chroma key:** after `ShowPiP1Behind(&bg, 1280, 720)` the screen looks + unchanged, except where it is purple (`$F0F`): there the PIP shows + through. ApolloPiP fills a Workbench window with purple to look through it. +- **Off:** after `HidePiP1()` the PIP is gone. + +## The full example + +`Projects/ApolloPiP/ApolloPiP.c` (ApolloCrossDev commit ad7f0b4; called SAGAPiP before 2026-11-04) does more than +the code above: soundtrack, background picture, a Workbench window with +PIP 1 and PIP 2 on it that follow the window, and a click that punches a +transparent square into the overlay. + +ApolloCrossDev pull request #19 (2026-11-04) fixed these problems of the +earlier version. Keep them out of your own code: + +| Earlier problem | Effect | Now | +|---|---|---| +| No PIP palette loaded | 8-bit overlays in the wrong colours, since ApolloLib 789cbcc (2026-06-16) dropped the palette preload in `ApolloLoadPicture` | `ApolloShowPiP1/2` load it | +| Positional initializers for `struct ApolloPicture` | Since `palette` is an array, the last value went into `palette[2]`, not `target` | Fields set by name | +| Workbench restored as GFXMODE `$0A04` | Worked only on a 1280x720, 24-bit Workbench | Mode, pointer and modulo saved from `$DFE1F4`/`$DFE1EC`/`$DFE1E6` and restored | +| `if (!&pipwindow)` | A failed `OpenWindowTags` went unnoticed | `if (!pipwindow)` | +| `BMF_DISPLAYABLE \| BMB_CLEAR \| BMB_HIJACKED \| …` | `BMB_` are bit numbers: the flags became `$F` | `BMF_DISPLAYABLE \| BMF_CLEAR \| BMF_INTERLEAVED` | +| Five exit labels, uninitialized structures | Freed buffers that were never loaded; read uninitialized fields | Everything starts cleared; one exit path frees only what was acquired | +| cybergraphics.library never closed | Leak | Closed | +| `ApolloCPUDelay` under Workbench | Busy waits | `Delay()` | + +The +16 (X) and −1 (Y) corrections place the PIP exactly over a Workbench +window in ApolloPiP; they are not documented elsewhere. diff --git a/examples/saga-pointer-sprite.md b/examples/saga-pointer-sprite.md new file mode 100644 index 0000000..c84a232 --- /dev/null +++ b/examples/saga-pointer-sprite.md @@ -0,0 +1,116 @@ +--- +title: SAGA hardware pointer from a 32x32 BMP (from the ApolloPointer example) +type: example +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [saga-video-isabelle, toolchain] +applies_to: + core: "Core 12500+" + os: [any] +tags: [saga, isabelle, pointer, sprite, bmp, apollolib, example] +related: + - core/saga-registers/pointer.md + - toolchain/apollolib/picture.md + - toolchain/apollolib/input.md + - core/best-practices/prefer-library-calls-for-saga-chips.md +sources: + - "Example ApolloPointer.c, github.com/WDrijver/ApolloCrossDev Projects/ApolloPointer, commit ad7f0b4 (2026-11-04)" + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloLoadPointer, ApolloShowPointer), commit ad7f0b4 (2026-11-04)" +--- + +## Purpose + +Replace the SAGA hardware pointer (the 32x32 sprite of Core 12500 and +later) with an image from a BMP file, and move it, with ApolloLib. +ApolloCrossDev's ApolloPointer example does the first part as a command: +`ApolloPointer sprite.bmp`. + +## Build + +The functions compile as a library unit. In a project that uses ApolloLib +(see [toolchain/apollolib/index.md](../toolchain/apollolib/index.md)): + +```sh +m68k-amigaos-gcc -noixemul -O2 -m68080 -m68881 -ffast-math -fomit-frame-pointer -Wall \ + -I$APOLLOLIB -c pointer.c -o pointer.o +``` + +The full example builds in ApolloCrossDev with `make` in +`Projects/ApolloPointer` (which also uploads it to the Apollo V4), or +`make cleanbefore build` to only build. Its folder has seven 32x32 8-bit +pointer images (`ApolloPointer_*_32x32x8.bmp`). + +## Code + +```c +// kb:compile +/* Replace the SAGA hardware pointer with a 32x32 BMP, after the ApolloPointer + example in ApolloCrossDev Projects/ApolloPointer. Core 12500+ (32x32 + sprite), ApolloLib b9891d9+ (ApolloLoadPointer returns a result code). */ +#include "ApolloCrossDev_Lib.h" + +static struct ApolloPointer pointer; /* over 5 KB: keep it off the stack */ + +/* Load a 32x32 BMP (8-bit with palette, 24-bit, or 32-bit ARGB) and show it + as the pointer. Returns APOLLO_PICTURE_OK or the error code. */ +uint8_t SetPointerFromBMP(const char *filename) +{ + struct ApolloPicture bmp = {0}; + uint8_t result; + + strncpy(bmp.filename, filename, sizeof(bmp.filename) - 1); + bmp.format = APOLLO_BMP_FORMAT; + bmp.target = APOLLO_PIC_TARGET_SPRITE; + + result = ApolloLoadPointer(&pointer, &bmp); /* loads, converts and frees the BMP */ + if (result == APOLLO_PICTURE_OK) + ApolloShowPointer(&pointer); /* palette to $DFF3A8/$DFF3AA, image to $DFD000 */ + return result; +} + +/* Move the pointer to screen position (x, y), with the offsets ApolloMouse uses. */ +void MovePointer(WORD x, WORD y) +{ + *(volatile UWORD *)APOLLO_POINTER_SET_X = x + 16; + *(volatile UWORD *)APOLLO_POINTER_SET_Y = y + 8; +} +``` + +## Expected result + +- `SetPointerFromBMP("ApolloPointer_Gold_32x32x8.bmp")` returns + `APOLLO_PICTURE_OK`, and the pointer on screen changes to the image at + once, at its current position. +- Pixels with colour index 0 are transparent. In an 8-bit or 24-bit BMP + every other pixel is opaque. In a 32-bit ARGB BMP, alpha 0 is + transparent, alpha `$FF` opaque, and any other alpha 50 % + semi-transparent (see [pointer.md](../core/saga-registers/pointer.md)). +- A BMP that isn't 32x32 returns `APOLLO_PICTURE_W_ERROR` or `H_ERROR`, + another depth `D_ERROR`, a missing file the load error; the pointer + stays as it was. +- `MovePointer(x, y)` places it; `ApolloMouse` (see + [input.md](../toolchain/apollolib/input.md)) does the same from the + mouse every frame. + +## The full example + +`Projects/ApolloPointer/ApolloPointer.c` (ApolloCrossDev commit ad7f0b4) +calls `ApolloLoadPointer` and `ApolloShowPointer` on the file named on the +command line, prints an error and returns 10 if the file can't be used, +and exits; the new pointer stays. + +ApolloCrossDev pull request #21 (2026-11-04) fixed `ApolloLoadPointer`. +With an older ApolloLib, keep these in mind: + +| Before b9891d9 | Effect | +|---|---| +| `ApolloLoadPointer` returned `void` and never set `bLoaded` | A caller couldn't see whether loading worked; `ApolloShowPointer` showed whatever was in the struct | +| 24-bit BMPs were accepted but not converted | An empty (transparent) pointer | +| The loaded BMP was not freed | About 1–4 KB stayed allocated | +| 32-bit alpha read correctly only with `endian = true` | Wrong transparency otherwise | +| The example's text said colour 1 was semi-transparent | Not true: only the transparency byte decides (WDrijver, 2026-11-04) | + +`hotspotX`/`hotspotY` in `struct ApolloPointer` are still not used by +ApolloLib. diff --git a/toolchain/apollolib/debug.md b/toolchain/apollolib/debug.md new file mode 100644 index 0000000..cf9c963 --- /dev/null +++ b/toolchain/apollolib/debug.md @@ -0,0 +1,92 @@ +--- +title: ApolloLib serial debug output +type: reference +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain] +applies_to: + core: "any" + os: [any] +tags: [apollolib, debug, serial, rawdofmt, logging] +related: + - toolchain/apollolib/index.md + - toolchain/project-makefile.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_Debug.h, _Debug.c, _Defines.h), commit 639e195 (2026-11-04)" +--- + +## Summary + +ApolloLib writes debug text straight to the serial port at 115200 baud, +without OS calls, so it also works without a console and with the OS +taken over. Two macro sets use it: `AD()`/`ADX()` around `sprintf`, and +the levelled `Debug_Info()` … `Debug_Flag()` macros. + +## Details + +### Functions (ApolloCrossDev_Debug.c) + +| Function | What it does | +|---|---| +| `ApolloDebugInit()` | Sets DTR and RTS on CIA-B and SERPER to 115200 baud (PAL clock) | +| `ApolloDebugPutChar(c)` | Waits for TBE, writes one character to SERDAT; `\n` becomes `\r\n` | +| `ApolloDebugMayGetChar()` | Returns a received character, or −1 | +| `ApolloDebugPutStr(s)` | Writes a string | +| `ApolloDebugPutDec(label, v)`, `ApolloDebugPutHex(label, v)`, `ApolloDebugPutHexVal(v)` | Write `label: value` in decimal or hex | +| `WriteRegisterWord(reg, v)`, `ReadRegisterWord(reg)` | Write and read a 16-bit hardware register | + +`char ApolloDebugMessage[256]` is the shared buffer for `sprintf`. + +### Macros, set 1: AD and ADX (ApolloCrossDev_Defines.h) + +| Macro | Active with | +|---|---| +| `AD(x)` | `-DAPOLLO_DEBUG` | +| `ADX(x)` | `-DAPOLLO_DEBUG -DAPOLLO_DEBUGEXTRA` | +| `ADXX(x)` | Never (always empty) | + +```c +AD(sprintf(ApolloDebugMessage, "loaded %s\n", name);) +AD(ApolloDebugPutStr(ApolloDebugMessage);) +``` + +ApolloLib's own code uses this set. The example Makefiles build with +`-DAPOLLO_DEBUG -DAPOLLO_DEBUGEXTRA`. + +### Macros, set 2: levels (ApolloCrossDev_Debug.h) + +Set `DEBUG` to a sum of levels, for example `-DDEBUG=7`: + +| Level | Value | Macro | +|---|---|---| +| `DBG_INFO` | 1 | `Debug_Info(fmt, ...)` | +| `DBG_WARN` | 2 | `Debug_Warn(...)` (yellow) | +| `DBG_ERROR` | 4 | `Debug_Error(...)` (red) | +| `DBG_FLAG` | 8 | `Debug_Flag(...)` (blinking magenta) | +| `DBG_TRACE` | 16 | `Debug_Trace(...)` (grey) | +| `DBG_CMD` | 32 | `traceCommand(req)`: device drivers only, not in ApolloLib | +| `DBG_MEM` | 64 | `AllocMem`/`FreeMem` wrappers: device drivers only, not in ApolloLib | + +The macros print `[project][file][function][line] [LEVEL]` and the +message through exec `RawDoFmt` inside `Forbid()`/`Permit()`. They need +`PROJECT_NAME` and `BASE_FILE_NAME` defined, for example by the Makefile. +`RawDoFmt` formats: use `%ld` for 32-bit values. + +`BUG_RED`, `BUG_BOLD` … are ANSI colour codes for your own messages. + +## Differences from AmigaOS / AROS / 68060 + +- `kprintf`/debug.lib need the OS and go through exec; ApolloLib writes + SERDAT directly and works in takeover code and interrupts. +- The serial port is shared: don't use the debug output while serial.device + owns the port. + +## Do / Don't + +- DO call `ApolloDebugInit()` once before the first output. +- DO use `%ld` in `Debug_…` formats (`RawDoFmt`) and the C types in `AD()` + (`sprintf`). +- DON'T set `DBG_CMD` or `DBG_MEM` in an ApolloLib program: their code is + not in ApolloLib. diff --git a/toolchain/apollolib/index.md b/toolchain/apollolib/index.md new file mode 100644 index 0000000..9361cd8 --- /dev/null +++ b/toolchain/apollolib/index.md @@ -0,0 +1,122 @@ +--- +title: ApolloLib, the ApolloCrossDev library for SAGA and the 68080 +type: reference +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain, saga-audio-arne, saga-video-isabelle] +applies_to: + core: "any" + os: [any] +tags: [apollolib, library, saga, arne, isabelle, pip, pointer, debug] +related: + - core/best-practices/prefer-library-calls-for-saga-chips.md + - core/saga-registers/index.md + - toolchain/project-makefile.md + - toolchain/pitfalls/apollolib-known-bugs.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib, commit 639e195 (2026-11-04)" + - "WDrijver (maintainer), library calls for the SAGA chips, 2026-11-04" +--- + +## Summary + +ApolloLib is the C and assembly library that ships with ApolloCrossDev in +`Projects/ApolloLib`. It loads and plays sounds on Arne, loads and shows +pictures on the SAGA chunky plane, PIP and pointer sprite, reads mouse, +USB joypad and keyboard, and has fast copy, fill and blit routines and a +serial debug output. Until the official libraries for Arne and Isabelle +are released, ApolloLib is the preferred way to use them (see +[prefer-library-calls-for-saga-chips.md](../../core/best-practices/prefer-library-calls-for-saga-chips.md)). + +## Details + +### Using it in a project + +ApolloLib is not a link library: a project compiles its sources. The +example Makefiles (ApolloPointer, ApolloPiP) set +`APOLLOLIB = $(PWD)/../../Projects/ApolloLib`, add `-I$(APOLLOLIB)`, +and compile every `.c` and `.s` file there into the program (see +[project-makefile.md](../project-makefile.md)). + +```c +#include "ApolloCrossDev_Lib.h" /* includes _Defines.h and _Debug.h */ +``` + +| File | Content | +|---|---| +| `ApolloCrossDev_Lib.h` | Structures and prototypes | +| `ApolloCrossDev_Defines.h` | SAGA addresses, modes, formats, return codes, debug switches, Amiga includes | +| `ApolloCrossDev_LibC.c` | Files, sound, picture, PIP, pointer, input | +| `ApolloCrossDev_LibASM.s` | Copy, fill, blit, endian swap, timing, takeover (vasm, 68080 and AMMX) | +| `ApolloCrossDev_Debug.h`, `_Debug.c` | Serial debug output | + +The assembly functions take their arguments in registers, declared with +the macros `_A0(...)` … `_D7(...)` from `_Defines.h`. + +### Areas + +| Area | Functions | File | +|---|---|---| +| Sound on Arne | `ApolloLoadSound`, `ApolloPlaySound`, `ApolloStopSound`, `ApolloVolume…`, fades; the channel API `ApolloPlay`, `ApolloPlayFile`, `ApolloStartChannel`, `ApolloStopChannel` | [sound.md](sound.md) | +| Pictures, PIP, pointer | `ApolloLoadPicture`, `ApolloShowPicture`, `ApolloShowPiP1/2`, `ApolloHidePiP1/2`, `ApolloLoadPointer`, `ApolloShowPointer`, `ApolloShowFile` | [picture.md](picture.md) | +| Input | `ApolloMouse`, `ApolloJoypad`, `ApolloKeyboard`, `ApolloKeyboardToUnicode`, `ApolloGetMouseDelta` | [input.md](input.md) | +| Memory and blit | `ApolloCopyBlock`, `ApolloFillLongs`, `ApolloSwapLong`, `ApolloBlit…Loop` and others | [memory-and-blit.md](memory-and-blit.md) | +| System and timing | `ApolloWaitVBL`, `ApolloCPUTick`, `ApolloCPUDelay`, `ApolloTimer`/`ApolloTimerStop`, `ApolloTakeOver`/`ApolloRelease`, `ApolloForbid`/`ApolloPermit`, `ApolloDisable`/`ApolloEnable` | [system-and-timing.md](system-and-timing.md) | +| Debug | `ApolloDebugInit`, `ApolloDebugPutStr`, `AD()`, `Debug_Info()` … | [debug.md](debug.md) | +| Files | `ApolloLoadFile`, `ApolloCacheFile` | this file | + +### Files + +`ApolloLoadFile(struct ApolloFile *file)` reads `file->filename` from byte +`file->offset` to the end into `file->buffer`, which the caller allocates, +and sets `file->size`. `ApolloCacheFile(filename, &cache, &length, offset)` +does the same with plain arguments. Both use libnix `fopen`/`fread`. + +### Return codes + +| Value | Sound (`APOLLO_SOUND_…`) | Picture (`APOLLO_PICTURE_…`) | +|---|---|---| +| `$00` | OK | OK | +| `$01` | NOCHANNEL | W_ERROR (width has no SAGA mode) | +| `$02` | – | H_ERROR (height has no SAGA mode) | +| `$03` | ENDOFFILE | D_ERROR (depth not supported) | +| `$04` | LOADERROR | LOADERR | +| `$05` | NOHEADER | NOHEADER | +| `$06` | – | PLANEERR | +| `$07` | – | COMPRERR | +| `$09` | MEMERROR | MEMERROR | +| `$0A` | OPENERR | OPENERR | +| `$0B` | CLOSEERR | CLOSEERR | +| `$0C` | COMPRERR | – | + +`ApolloLoadFile` returns the sound codes. + +### Versions + +Many bugs were fixed on 2026-11-04 (commit 639e195): use that version or +later. An older copy has the bugs listed in +[apollolib-known-bugs.md](../pitfalls/apollolib-known-bugs.md), among them +broken 320-pixel modes and no way to undo `ApolloTakeOver` or +`ApolloTimer`. From commit a9a994f, `ApolloShowPiP1/2` also load the +palette of an 8-bit picture. + +## Differences from AmigaOS / AROS / 68060 + +- ApolloLib programs the SAGA registers directly, without graphics.library, + audio.device or input.device. Most functions are OS-takeover style: + under a running OS, `ApolloMouse` and `ApolloShowPicture` compete with + Intuition for the pointer and the screen. +- The assembly uses 68080 and AMMX instructions (`load`, `store`, `vperm`, + `dbra.l`, `move16`): it doesn't run on a 68060. + +## Do / Don't + +- DO use ApolloLib for Arne and Isabelle instead of programming the + registers yourself (a best practice, not a forced rule). +- DO build against ApolloLib 639e195 or later. +- DO check the limits that remain before you rely on a function: + [apollolib-known-bugs.md](../pitfalls/apollolib-known-bugs.md). +- DON'T copy an old ApolloLib into a project: compile the one in + `Projects/ApolloLib`. diff --git a/toolchain/apollolib/input.md b/toolchain/apollolib/input.md new file mode 100644 index 0000000..5dcc430 --- /dev/null +++ b/toolchain/apollolib/input.md @@ -0,0 +1,99 @@ +--- +title: ApolloLib input functions (mouse, USB joypad, keyboard) +type: reference +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain, general] +applies_to: + core: "any" + os: [any] + mode: [os-takeover] +tags: [apollolib, input, mouse, joypad, keyboard, pointer] +related: + - toolchain/apollolib/index.md + - core/saga-registers/input.md + - core/saga-registers/pointer.md + - toolchain/pitfalls/apollolib-known-bugs.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_LibC.c, _LibASM.s, _Defines.h), commit 639e195 (2026-11-04)" +--- + +## Summary + +ApolloLib polls the mouse, the first USB joypad and the keyboard directly +from the hardware, and moves the SAGA pointer with the mouse. Call the +functions once per frame. They bypass input.device, so they belong in +OS-takeover code. + +## Details + +### Mouse: ApolloMouse(ApolloMouseState *m) + +| Source | Register | +|---|---| +| X, Y counters | `$DFF00B`, `$DFF00A` (JOY0DAT) | +| Left button | CIA-A `$BFE001` bit 6 (0 = pressed) | +| Right button | POTINP `$DFF016` bit 10 (0 = pressed) | +| Middle button | POTINP `$DFF016` bit 8 (0 = pressed) | + +Each call: + +1. computes the X/Y delta since the last call (with wrap-around of the + 8-bit counters); +2. moves `MouseX_Pointer`/`MouseY_Pointer`, clamped to 1 … + `MouseX_Pointer_Max`/`MouseY_Pointer_Max` (set these first); +3. writes the pointer position + 16 (X) and + 8 (Y) to `$DFF1D0`/`$DFF1D2`; +4. sets `Button_State` from the `APOLLOMOUSE_…` flags. + +| Flag | Value | Set when | +|---|---|---| +| `APOLLOMOUSE_LEFTCLICK` / `RIGHTCLICK` / `MIDDLECLICK` | `$0001` / `$0002` / `$0004` | Button released | +| `APOLLOMOUSE_LEFTDOUBLECLICK` / `RIGHTDOUBLECLICK` / `MIDDLEDOUBLECLICK` | `$0008` / `$0010` / `$0020` | Released again within 15 calls (`APOLLOMOUSE_DOUBLECLICKCOUNTER`) | +| `APOLLOMOUSE_LEFTDOWN` / `RIGHTDOWN` / `MIDDLEDOWN` | `$0040` / `$0080` / `$0100` | Button held | + +`ApolloGetMouseDelta(UWORD *old)` (assembly) is a smaller variant: it +returns the X and Y delta since the value in `*old`, and updates `*old`. + +### USB joypad: ApolloJoypad(ApolloJoypadState *j) + +Reads joypad 0 (`$DFF220`) into `Joypad_Value` and decodes it: + +| Field | Bits | +|---|---| +| `Joypad_LeftX_Delta` | 15 → +1 (right), 14 → −1 (left) | +| `Joypad_LeftY_Delta` | 13 → +1 (down), 12 → −1 (up) | +| `Joypad_RightX_Delta` | 2 → +1, 3 → −1 | +| `Joypad_RightY_Delta` | 1 → +1, 4 → −1 | +| `Joypad_Start`, `Joypad_Back` | 10, 9 | +| `Joypad_TR`, `TL`, `BR`, `BL` | 8, 7, 6, 5 | +| `Joypad_Y`, `X`, `B`, `A` | 4, 3, 2, 1 | +| `Joypad_Connect` | 0 | + +The right stick shares bits 1–4 with A, B, X and Y. Joypads 1–3 +(`$DFF222`–`$DFF226`) need your own read. + +### Keyboard: ApolloKeyboard(ApolloKeyBoardState *k) + +Reads the raw key code from CIA-A `$BFEC01` (`not` and `ror #1`). A new +key below 127 goes to `Current_Key` (and `Previous_Key`); otherwise +`Current_Key` is 127. `ApolloKeyboardToUnicode(code)` maps a raw Amiga key +code to a character. + +## Differences from AmigaOS / AROS / 68060 + +- input.device, Intuition and lowlevel.library are not used. Under a + running OS, Intuition also moves the pointer and reads the keyboard: the + two fight. +- The keyboard read doesn't handshake with the keyboard controller, as the + OS keyboard interrupt does. + +## Do / Don't + +- DO set `MouseX_Pointer_Max` and `MouseY_Pointer_Max` before the first + `ApolloMouse` call. +- DO call these functions once per frame, for example after `ApolloWaitVBL`. +- DON'T use them while Intuition owns the input. +- DON'T rely on the middle-button flags with an ApolloLib older than + 639e195: there they followed the wheel counter. diff --git a/toolchain/apollolib/memory-and-blit.md b/toolchain/apollolib/memory-and-blit.md new file mode 100644 index 0000000..cd45aee --- /dev/null +++ b/toolchain/apollolib/memory-and-blit.md @@ -0,0 +1,89 @@ +--- +title: ApolloLib memory, endian and blit routines +type: reference +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain, cpu-68080] +applies_to: + core: "any" + os: [any] +tags: [apollolib, memcpy, fill, endian, blit, alpha, ammx, move16] +related: + - toolchain/apollolib/index.md + - core/cpu-68080/measured-instruction-costs.md + - core/best-practices/align-copy-destination.md + - toolchain/pitfalls/apollolib-known-bugs.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_LibASM.s, _Lib.h), commit 639e195 (2026-11-04)" +--- + +## Summary + +ApolloLib's assembly file has copy, fill and endian-swap routines for +memory, and copy, fill and alpha-blit routines for pixel rectangles. They +use 68080 instructions (`dbra.l`, `move16`, AMMX `load`/`store`/`vperm`). +Most ignore a remainder: give sizes that are a multiple of the chunk size. + +## Details + +All take their arguments in registers; the prototypes in +`ApolloCrossDev_Lib.h` declare them with `_A0(...)` … `_D7(...)`. + +### Memory + +| Routine | Arguments | Chunk | Remainder | +|---|---|---|---| +| `ApolloCopyBlock(s, d, size)` | a0, a1, d3 = bytes | 16 bytes with `move16`, then bytes | Copied | +| `ApolloCopyBlock32(s, d, size)` | a0, a1, d3 = bytes | 32 bytes (2 × `move16`) | **Ignored** | +| `ApolloCopyLongs(s, d, size)` | a0, a1, d3 = bytes | 4 bytes | **Ignored** | +| `ApolloFillLongs(d, value, size)` | a1, d4, d3 = bytes | 4 bytes | **Ignored** | +| `ApolloFillBlock(d, count, value)` | a0, d3 = bytes, d4 | 32 bytes (4 × AMMX `store`), 32-byte aligned | **Ignored** | + +`move16` needs no alignment on the 68080, but is never faster than +aligned AMMX or quad moves (see +[measured-instruction-costs.md](../../core/cpu-68080/measured-instruction-costs.md)). + +### Endian swap + +| Routine | What it does | +|---|---| +| `ApolloSwapWord(w)`, `ApolloSwapLong(l)`, `ApolloSwapOcta(q)` | Return the value with its bytes reversed (d0) | +| `ApolloEndianSwapWordBuffer(s, length)` | Byte-swaps 16-bit words in place, 8 bytes per AMMX step; buffer ≥ 8 bytes, 2-byte aligned | +| `ApolloEndianSwapLongBuffer(s, length)` | Byte-swaps 32-bit longs in place, 8 bytes per AMMX step; buffer ≥ 8 bytes, 4-byte aligned. Before 639e195 it swapped words. | +| `ApolloEndianSwap2Loop`, `ApolloEndianSwap8Loop` | Older swap loops, used by `ApolloShowFile` | + +### Pixel rectangles + +| Routine | What it does | +|---|---| +| `ApolloFillBitMap(dst, w, h, depth, dstmod, value)` | Fills a rectangle with a 32-bit value; modulo in pixels | +| `ApolloFillColor(dst, w, h, depth, dstmod, value)` | As above, value given byte-reversed | +| `ApolloCopyPicture(s, d, w, h, smod, dmod)` | Copies a rectangle; sizes and modulos in bytes | +| `ApolloCopyPicture32(...)` | As above, 32-byte aligned | +| `ApolloCopyLoop`, `ApolloCopy32Loop`, `ApolloBlitLoop` | Copy, aligned copy and copy with transparency; pitches in words | +| `ApolloFillLoop(d, w, h, dpitch, colour)` | Fills with an R5G6B5 colour | +| `ApolloBlitAlphaConstLoop(s, d, w, h, sp, dp, alpha)` | Blends with a constant alpha 0–255 (0 = transparent) | +| `ApolloBlitAlphaKeyTransLoop(..., alpha, key)` | Blends with alpha and skips the R5G6B5 key colour | +| `ApolloBlitAlphaHorizontalLineLoop(s, d, w, colour, alpha)` | Blends one line with an R8G8B8 colour | +| `ApolloBlitRed/Green/BlueAlphaBGLoop`, `ApolloBlitBlueAlphaUILoop` | Blend through a separate alpha map, one colour channel at a time | +| `ApolloUncompressLoop`, `ApolloUncompressVectorLoop` | Unpack sprites, with endian and colour swap (`$07C0` green becomes the key `$F81F`) | + +The blit routines work on R5G6B5 pixels (16-bit modes). + +## Differences from AmigaOS / AROS / 68060 + +- `CopyMem`/`CopyMemQuick` and the classic blitter are not used; these are + CPU loops for the 68080. +- AMMX (`load`, `store`, `vperm`) doesn't exist on the 68060: these + routines need a 68080. + +## Do / Don't + +- DO give sizes in multiples of 32 (`ApolloCopyBlock32`, `ApolloFillBlock`) + or 4 (`ApolloCopyLongs`, `ApolloFillLongs`). +- DO align the destination of large copies (see + [align-copy-destination.md](../../core/best-practices/align-copy-destination.md)). +- DON'T use `ApolloEndianSwapLongBuffer` from an ApolloLib older than + 639e195: it swapped words, not bytes. diff --git a/toolchain/apollolib/picture.md b/toolchain/apollolib/picture.md new file mode 100644 index 0000000..9512e71 --- /dev/null +++ b/toolchain/apollolib/picture.md @@ -0,0 +1,131 @@ +--- +title: ApolloLib picture, PIP and pointer functions (Isabelle) +type: reference +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain, saga-video-isabelle] +applies_to: + core: "any" + os: [any] +tags: [apollolib, isabelle, picture, bmp, dds, pip, pointer, sprite] +related: + - toolchain/apollolib/index.md + - core/saga-registers/chunky-plane.md + - core/saga-registers/pip.md + - core/saga-registers/pointer.md + - toolchain/pitfalls/apollolib-known-bugs.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_LibC.c, _Lib.h, _Defines.h), commit 639e195 (2026-11-04)" + - "Example ApolloPiP.c (formerly SAGAPiP), github.com/WDrijver/ApolloCrossDev Projects/ApolloPiP, commit ad7f0b4" + - "Example ApolloPointer.c, github.com/WDrijver/ApolloCrossDev Projects/ApolloPointer, commit 639e195" +--- + +## Summary + +ApolloLib loads BMP and DDS files into a 32-byte aligned buffer +(`ApolloLoadPicture`) and shows them on the SAGA chunky plane by picking +the GFXMODE that matches width, height and depth (`ApolloShowPicture`). +It switches PIP 1 and 2 on and off and loads the 32x32 pointer sprite of +Core 12500 and later. + +## Details + +### struct ApolloPicture + +| Field | Set by | Meaning | +|---|---|---| +| `filename[256]`, `format` | Caller | `APOLLO_BMP_FORMAT` (3), `APOLLO_DDS_FORMAT` (2), or raw (0: the whole file) | +| `endian` | Caller | `true`: swap the byte order of each 16-, 24- or 32-bit pixel after loading | +| `buffer`, `position`, `size` | `ApolloLoadPicture` | Allocated buffer; pixels at `buffer + position` (32-byte aligned) | +| `width`, `height`, `depth` | `ApolloLoadPicture` | From the header | +| `palette[256]`, `palettesize` | `ApolloLoadPicture` | For depth ≤ 8 | +| `modulo` | Caller | Bytes skipped after each row (BPLHMOD) | +| `fullscreen`, `target` | Caller | `target`: 0 SAGA screen, 1 PIP 1, 2 PIP 2, 3 pointer sprite | + +### Functions + +| Function | What it does | +|---|---| +| `ApolloLoadPicture(pic)` | BMP: uncompressed (or BI_BITFIELDS), 1 plane; bottom-up rows are flipped. DDS: the data after the header as it is, without a compression check, so only uncompressed DDS works; depth = pitch / width × 8. Returns an `APOLLO_PICTURE_…` code. | +| `ApolloAllocPicture(pic)` | Allocates an aligned buffer of `width × height × depth / 8` bytes (or `size`) | +| `ApolloFreePicture(pic)` | `FreeVec` of the buffer | +| `ApolloShowPicture(pic)` | Picks the GFXMODE from width × height (see below) and depth 8, 15, 16, 24 or 32, loads the chunky palette for depth ≤ 8, writes GFXMODE (`$DFF1F4`), modulo (`$DFF1E6`) and pointer (`$DFF1EC`) | +| `ApolloShowPiP1(pic)` / `ApolloShowPiP2(pic)` | Writes the PIP's DMA row length (`width × depth / 8`), which switches it on. Set position, pointer, format and modulo first (see [pip.md](../../core/saga-registers/pip.md)). For an 8-bit picture it first loads `pic->palette` into the PIP colour port (from ApolloLib a9a994f). See [the example](../../examples/saga-pip-overlay-and-chroma-key.md). | +| `ApolloHidePiP1()` / `ApolloHidePiP2()` | Writes 0 to the DMA row length: the PIP goes off | +| `uint8_t ApolloLoadPointer(ptr, pic)` | Loads a 32x32 BMP (8-bit with palette, 24-bit or 32-bit ARGB) and converts it into pointer sprite data: colour index + transparency byte per pixel and a 256-entry palette. Frees the BMP again. Returns `APOLLO_PICTURE_OK`, a load error, `W_ERROR`/`H_ERROR` (not 32x32) or `D_ERROR`; sets `ptr->bLoaded`. | +| `ApolloShowPointer(ptr)` | If `ptr->bLoaded`: writes the palette (`$DFF3A8` index, `$DFF3AA` colour) and copies the 2048-byte image to `$DFD000` | +| `ApolloShowFile(filename, &draw, &live, length, offset, gfx_mode, modulo, endianswap)` | Reads a raw frame into `draw`, swaps `draw` and `live`, and shows `live`: double buffering for streamed frames | +| `ApolloShowPattern(buffer, w, h, depth)` | Fills a buffer with a test pattern | + +### Screen modes of ApolloShowPicture + +| Width | Heights | +|---|---| +| 304 | 224 | +| 320 | 200, 240, 256 | +| 480 | 270 | +| 640 | 200, 360, 400, 480, 512 | +| 720 | 405, 576 | +| 800, 848, 960, 1024 | 600, 480, 540, 768 (height not checked) | +| 1280 | 720, 800, 1024 | +| 1440, 1920 | 900, 1080 (height not checked) | + +Another width returns `APOLLO_PICTURE_W_ERROR`, another height of a +checked width `APOLLO_PICTURE_H_ERROR`. Before ApolloLib 639e195 the +320-pixel modes were broken (see +[apollolib-known-bugs.md](../pitfalls/apollolib-known-bugs.md)). + +### Pointer + +`ApolloLoadPointer` accepts a 32x32 BMP (from ApolloLib b9891d9; before, +it returned nothing, ignored 24-bit BMPs and kept the BMP allocated): + +- 8-bit: the BMP palette becomes the sprite palette; every pixel is + opaque. Colour index 0 is transparent (see + [pointer.md](../../core/saga-registers/pointer.md)). +- 24-bit: every pixel opaque; colours are gathered into a palette. +- 32-bit ARGB: alpha 0 becomes index 0 (transparent), alpha `$FF` opaque, + any other alpha semi-transparent (50 %). Colours are gathered into a + palette of up to 255 entries; further colours use entry 255. + +It loads the BMP with `endian` off and reads the bytes in BMP order, so the +caller doesn't set `endian`. + +`ApolloMouse` (see [input.md](input.md)) moves the pointer. A complete, +checked use of both functions is in +[the pointer example](../../examples/saga-pointer-sprite.md). + +### Example + +```c +struct ApolloPicture pic = {0}; +strcpy(pic.filename, "title.dds"); +pic.format = APOLLO_DDS_FORMAT; /* 1280x720, 16-bit */ +if (ApolloLoadPicture(&pic) == APOLLO_PICTURE_OK) { + pic.modulo = 0; + ApolloShowPicture(&pic); + /* ... */ + ApolloFreePicture(&pic); /* after switching the mode back */ +} +``` + +## Differences from AmigaOS / AROS / 68060 + +- No graphics.library or cybergraphics: `ApolloShowPicture` writes + GFXMODE and the chunky pointer directly, behind Intuition's back. Save + the old mode and pointer at `$DFE1F4`/`$DFE1EC` and restore them on exit. +- BMP pixels are little-endian. Use `endian` or the swap routines when the + SAGA format needs big-endian pixels. + +## Do / Don't + +- DO set the PIP registers before `ApolloShowPiP1/2`: they only write the + DMA row length. +- DO load an 8-bit PIP's palette yourself (`$DFF38C` for PIP 1, `$DFF37C` + for PIP 2) with an ApolloLib older than a9a994f. +- DO restore GFXMODE and the chunky pointer before the program exits. +- DON'T free a picture that is still shown. +- DON'T use `ApolloShowPicture` for 320-pixel-wide or 8-bit pictures with + an ApolloLib older than 639e195. diff --git a/toolchain/apollolib/sound.md b/toolchain/apollolib/sound.md new file mode 100644 index 0000000..07564ce --- /dev/null +++ b/toolchain/apollolib/sound.md @@ -0,0 +1,116 @@ +--- +title: ApolloLib sound functions (Arne) +type: reference +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain, saga-audio-arne] +applies_to: + core: "any" + os: [any] +tags: [apollolib, arne, audio, wav, aiff, sound] +related: + - toolchain/apollolib/index.md + - core/saga-registers/arne-channels.md + - core/saga-registers/arne-dma-and-interrupts.md + - toolchain/pitfalls/apollolib-known-bugs.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_LibC.c, _Lib.h), commit 639e195 (2026-11-04)" +--- + +## Summary + +ApolloLib loads WAV and AIFF files into a 32-byte aligned buffer and plays +them on an Arne channel: `ApolloLoadSound`, then `ApolloPlaySound`, which +programs 16-bit stereo, 16-bit mono or 8-bit mono to match the file. A +second, older API (`ApolloPlay`, `ApolloPlayFile`) takes a channel number +and a buffer instead of a `struct ApolloSound`, and always plays 16-bit +stereo at 44.1 kHz. + +## Details + +### struct ApolloSound + +| Field | Set by | Meaning | +|---|---|---| +| `filename[256]`, `format` | Caller | File and format: `APOLLO_WAV_FORMAT` (4), `APOLLO_AIFF_FORMAT` (1), or raw (`APOLLO_RAW_FORMAT`, 0: the whole file) | +| `buffer`, `position` | `ApolloLoadSound` | Allocated buffer; the data starts at `buffer + position` (32-byte aligned) | +| `size` | `ApolloLoadSound` | Data size in bytes | +| `period` | `ApolloLoadSound` | `3546895 / sample rate` (PAL clock) | +| `stereo`, `bitspersample` | `ApolloLoadSound` (WAV, AIFF) or caller | Select the format in `ApolloPlaySound`; `bitspersample` 0 means 16-bit stereo | +| `datarate` | `ApolloLoadSound` (WAV) | Not used for playback | +| `channel` | Caller or `ApolloPlaySound` | Arne channel 0–15 | +| `staticchannel` | Caller | `true`: play on `channel`; `false`: `ApolloPlaySound` picks the first free channel from 1 to 15 | +| `loop`, `fadein`, `volume_left`, `volume_right` | Caller | Playback; volume `$00`–`$FF` per side | +| `fadeout`, `pan` | Caller | Not used by the library | + +### Functions + +| Function | What it does | +|---|---| +| `ApolloLoadSound(sound)` | Parses the WAV or AIFF header, allocates `buffer` (`AllocVec`, `MEMF_ANY`), reads the data. WAV: PCM only. Returns an `APOLLO_SOUND_…` code. | +| `ApolloAllocSound(sound)` | Allocates an aligned buffer of `sound->size` bytes for data you fill yourself | +| `ApolloFreeSound(sound)` | `FreeVec` of the buffer | +| `ApolloPlaySound(sound)` | Picks a channel if `staticchannel` is false, sets pointer, length, volume 0, CTRL and period, starts DMA (DMACON for 0–3, DMACON2 for 4–15), then sets the volume or fades in | +| `ApolloStopSound(sound)` / `ApolloStartSound(sound)` | Clears or sets the channel's DMA bit | +| `ApolloVolumeSound(sound)` | Writes `volume_left << 8 \| volume_right` to AUDxVOL | +| `ApolloFadeInSound(sound)` / `ApolloFadeOutSound(sound)` | Steps the volume by 1 per VBlank (`ApolloWaitVBL`) to or from the average of left and right; fade-out then stops the channel. Both block the caller. | + +`ApolloPlaySound` picks CTRL and the LEN unit from the format, and adds +the one-shot bit (`$0002`) when `loop` is not set: + +| Format | CTRL | LEN = size / | +|---|---|---| +| 16-bit stereo, or unknown (`bitspersample` 0) | `$0005` | 8 | +| 16-bit mono | `$0001` | 4 | +| 8-bit mono | `$0000` | 2 | + +8-bit stereo can't play: Arne's stereo mode is 16-bit. 8-bit WAV samples +are unsigned and are not converted to the signed format Arne expects. + +### Channel API (older, from the RHLOS project) + +| Function | What it does | +|---|---| +| `ApolloPlay(channel, vol_l, vol_r, loop, buffer, length, offset)` | Plays `buffer + offset`, length `(length - offset) / 8 - 32` pairs, at period 80 (44.1 kHz). Returns `false` if the channel is busy. | +| `ApolloPlayFile(filename, buffer, offset, channel, vol_l, vol_r, loop)` | Reads the file from `offset` into `buffer` and plays it on `channel`, stopping the channel first if it runs | +| `ApolloCacheFile(filename, &cache, &length, offset)` | Reads a file into `cache` for `ApolloPlay` | +| `ApolloVolume(channel, vol_l, vol_r)` | Sets the volume | +| `ApolloStartChannel(channel)` / `ApolloStopChannel(channel)` | Starts or stops a channel's DMA | +| `ApolloFadeOut(channel, from, to)` | Steps the volume down per VBlank, then stops the channel | + +### Example + +```c +struct ApolloSound music = {0}; +strcpy(music.filename, "music.wav"); +music.format = APOLLO_WAV_FORMAT; /* 16-bit stereo PCM */ +if (ApolloLoadSound(&music) == APOLLO_SOUND_OK) { + music.volume_left = music.volume_right = 0x80; + music.loop = true; + if (ApolloPlaySound(&music) == APOLLO_SOUND_OK) { + /* ... */ + ApolloStopSound(&music); + } + ApolloFreeSound(&music); +} +``` + +## Differences from AmigaOS / AROS / 68060 + +- No audio.device or AHI: the functions write the Arne registers at + `$DFF400 + n × $10` and DMACON/DMACON2 directly. Don't use them on a + channel that audio.device or AHI also uses. +- Arne plays from any RAM, so `MEMF_ANY` buffers work; Paula needs Chip RAM. + +## Do / Don't + +- DO set `stereo` and `bitspersample` yourself for raw data that isn't + 16-bit stereo. +- DO set `staticchannel` and `channel` if you need channel 0: the + automatic search starts at 1. +- DO call `ApolloFreeSound` when you are done. +- DON'T play 8-bit WAV files without converting them to signed samples. +- DON'T expect `fadeout` or `pan` to change playback. +- DON'T use the channel API and audio.device on the same channel. diff --git a/toolchain/apollolib/system-and-timing.md b/toolchain/apollolib/system-and-timing.md new file mode 100644 index 0000000..7d1406f --- /dev/null +++ b/toolchain/apollolib/system-and-timing.md @@ -0,0 +1,83 @@ +--- +title: ApolloLib system and timing routines (VBlank, CPU cycles, takeover) +type: reference +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain, cpu-68080] +applies_to: + core: "any" + os: [any] +tags: [apollolib, vblank, timer, ccc, delay, takeover, forbid, disable] +related: + - toolchain/apollolib/index.md + - core/cpu-68080/performance-counters.md + - os/os-takeover.md + - toolchain/pitfalls/apollolib-known-bugs.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib (ApolloCrossDev_LibC.c, _LibASM.s), commit 639e195 (2026-11-04)" +--- + +## Summary + +ApolloLib waits for VBlank, reads the 68080 cycle counter and waits a +number of milliseconds, counts VBlanks in an interrupt server, and has +three takeover helpers. From commit 639e195 every one of them has a +counterpart that undoes it; call it before the program exits. + +## Details + +| Function | What it does | +|---|---| +| `ApolloWaitVBL()` | Polls INTREQR bit 5 (VERTB) until set, then clears it in INTREQ | +| `ApolloCPUTick()` | Returns the clock cycle counter CCC (`movec $809,d0`, see [performance-counters.md](../../core/cpu-68080/performance-counters.md)) | +| `ApolloCPUDelay(ms)` | Busy-waits `ms × multiplier × 7094` cycles on CCC; the multiplier is the low byte of `$DFF3FC` (14 if 0) | +| `ApolloTimer()` | Adds a VBlank interrupt server (`AddIntServer`, `INTB_VERTB`) that increments `GlobalTimer` every frame | +| `ApolloTimerStop()` | Removes that server (`RemIntServer`) | +| `ApolloTakeOver()` | Opens intuition.library, `CloseWorkBench()`, sets the task priority to 20, and remembers the library base and the old priority | +| `ApolloRelease()` | Restores the old priority, `OpenWorkBench()`, closes intuition.library | +| `ApolloForbid()` / `ApolloPermit()` | Call exec `Forbid()` / `Permit()` | +| `ApolloDisable()` / `ApolloEnable()` | Call exec `Disable()` / `Enable()` | + +`ApolloTimerStop`, `ApolloRelease`, `ApolloPermit` and `ApolloEnable` +exist from ApolloLib commit 639e195. + +### Limits + +- **`ApolloWaitVBL` clears VERTB** itself. Under a running OS that takes + the event away from the OS's VBlank handling; use it in takeover code. +- **`ApolloCPUDelay`** counts `multiplier × 7.094` MHz cycles per ms, so + it follows the clock the board reports at `$DFF3FC` (see + [system.md](../../core/saga-registers/system.md)). Before 639e195 it + assumed 92 MHz, about 7 % short on a 99.31 MHz V4. +- **`ApolloRelease`** restores the priority that `ApolloTakeOver` saved. + Call it only after `ApolloTakeOver`; otherwise it sets priority 0. + +### Restore at exit + +| After | Call before exit | +|---|---| +| `ApolloTimer()` | `ApolloTimerStop()`: the server node lives in the program, so a server left behind runs freed memory | +| `ApolloTakeOver()` | `ApolloRelease()` | +| `ApolloForbid()` | `ApolloPermit()` | +| `ApolloDisable()` | `ApolloEnable()` | + +This is what [os-takeover.md](../../os/os-takeover.md) asks of every +takeover program: restore multitasking and the Workbench screen on exit. + +## Differences from AmigaOS / AROS / 68060 + +- `ApolloCPUTick` reads a 68080 control register; there is no such + counter on the 68060. Use timer.device or the CIA timers for portable + timing. +- The takeover helpers wrap single exec and Intuition calls; they don't + save the display, the interrupt enables or the DMA state. + +## Do / Don't + +- DO call `ApolloTimerStop`, `ApolloRelease`, `ApolloPermit` and + `ApolloEnable` in your exit code, in the reverse order of their + counterparts. +- DON'T use `ApolloTimer` with an ApolloLib older than 639e195 in a + program that exits back to the OS: there is no way to remove the server. diff --git a/toolchain/index.md b/toolchain/index.md index 0b12317..4b3ec9e 100644 --- a/toolchain/index.md +++ b/toolchain/index.md @@ -15,6 +15,7 @@ related: - toolchain/vasm-assembler.md - toolchain/target-os-headers.md - toolchain/project-makefile.md + - toolchain/apollolib/index.md sources: - "github.com/WDrijver/ApolloCrossDev README.md" - "github.com/WDrijver/ApolloCrossDev GCC-6.50-Dev-Linux.sh" @@ -62,6 +63,9 @@ C and C++: `-O2 -m68080 -m68881 -ffast-math -fomit-frame-pointer`. Details in - DevPac includes for assembly, in `/m68k-amigaos/DevPac` - ApolloExplorer (`acp`) to upload files to an Apollo V4 over the network - bgdbserver, a GDB server that runs on the Apollo V4 for remote debugging +- ApolloLib in `Projects/ApolloLib`: sound, picture, PIP, pointer, input, + copy and blit routines and serial debug output for SAGA and the 68080, + see [toolchain/apollolib/](apollolib/index.md) ### Host requirements diff --git a/toolchain/pitfalls/apollolib-known-bugs.md b/toolchain/pitfalls/apollolib-known-bugs.md new file mode 100644 index 0000000..940e07e --- /dev/null +++ b/toolchain/pitfalls/apollolib-known-bugs.md @@ -0,0 +1,105 @@ +--- +title: ApolloLib bugs fixed in 2026-11 and the limits that remain +type: pitfall +owner: WDrijver +status: draft +origin: ai-assisted +basis: [source-code] +components: [toolchain, saga-audio-arne, saga-video-isabelle] +applies_to: + core: "any" + os: [any] +tags: [apollolib, bugs, showpicture, timer, takeover, endian, mouse, sound] +related: + - toolchain/apollolib/index.md + - toolchain/apollolib/picture.md + - toolchain/apollolib/sound.md + - toolchain/apollolib/system-and-timing.md +sources: + - "ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib, commit ce1fcbf (2026-11-04), read on 2026-11-04" + - "ApolloCrossDev pull requests #17 and #18 (merged 2026-11-04), fixed in commit 639e195" + - "ApolloCrossDev pull request #19 (merged 2026-11-04), PiP palette, commit a9a994f" + - "ApolloCrossDev pull request #21 (merged 2026-11-04), ApolloLoadPointer, commit b9891d9" +--- + +## Symptom + +A program shows a 320-pixel picture in the wrong mode or an 8-bit picture +in wrong colours, crashes some time after it exits, never gets the +Workbench back, or plays a mono sound too fast. It was built against +ApolloLib from before 2026-11-04. + +## Cause + +ApolloLib up to commit ce1fcbf had these bugs. They were found by reading +the code while documenting the library, and fixed in commit 639e195 +(ApolloCrossDev pull request #18). None of the fixes is tested on V4 +hardware yet. + +### Fixed in 639e195 + +| Function | Bug before 639e195 | +|---|---| +| `ApolloShowPicture` | `case 320` fell through into `case 480`: 320x200 became 304x224, 320x240/256 became 1280x720/640x360 | +| `ApolloShowPicture` | The 8-bit palette was reordered a second time: wrong colours | +| `ApolloTimer` | The VBlank server was never removed; its node lives in the program, so the system crashed after the program exited. Now: `ApolloTimerStop()` | +| `ApolloTakeOver`, `ApolloForbid`, `ApolloDisable` | No way back. Now: `ApolloRelease()`, `ApolloPermit()`, `ApolloEnable()` | +| `ApolloCPUDelay` | Fixed 92 MHz; the overflow check could not work | +| `ApolloEndianSwapLongBuffer` | Swapped words instead of bytes; both buffer swaps counted their remainder wrongly | +| `ApolloPlaySound` | Always 16-bit stereo, whatever the file contained | +| `ApolloPlayFile` | Applied its offset twice | +| `ApolloMouse` | The "middle button" was the wheel counter | +| `ApolloLoadFile`/`Sound`/`Picture` | Left the file open on errors; BMP palette read from a fixed offset | +| `ApolloShowPattern` | Wrote only the first byte of each pixel | +| `ApolloCrossDev_Lib.h` | Declared `ApolloShowPiP`/`ApolloHidePiP`, which don't exist, and not `ApolloShowPiP1/2`/`ApolloHidePiP1/2` | +| `ApolloLoadPointer` (b9891d9, #21) | Returned nothing and never set `bLoaded`; accepted 24-bit BMPs without converting them (empty pointer); read 32-bit alpha correctly only with `endian` set; overwrote palette entry 255 when full; never freed the BMP it loaded. Now it returns an `APOLLO_PICTURE_…` code, converts 24-bit, reads BMP byte order, frees the BMP, and `ApolloShowPointer` does nothing without a loaded pointer. | +| PiP palette (a9a994f, #19) | From 789cbcc (2026-06-16) to a9a994f nothing loaded an 8-bit PiP palette: `ApolloLoadPicture` had stopped writing it into the port chosen by `picture->target`. Now `ApolloShowPiP1/2` load it. | +| Five functions (#17) | Wrong DMACON2R bit for channels 4–15, a write through an uninitialized pointer, missing return values, an always-on keyboard print | + +### Limits that remain + +| Function | Limit | +|---|---| +| `ApolloPlaySound` | 8-bit stereo can't play (Arne's stereo mode is 16-bit); 8-bit WAV samples are unsigned and are not converted to the signed format Arne expects | +| `ApolloPlaySound` | A sound without format information (`bitspersample` 0, for example RAW) plays as 16-bit stereo | +| `ApolloPlaySound` | The free-channel search starts at channel 1 | +| `ApolloPlay`, `ApolloPlayFile` | Subtract 32 sample pairs from the length, without an explanation | +| `ApolloLoadPicture` | Keeps its file state in `static` variables: not reentrant | +| `ApolloRelease` | Restores the priority saved by `ApolloTakeOver`; called without it, it sets priority 0 | + +## Wrong + +```c +ApolloTakeOver(); +ApolloTimer(); +/* ... */ +return 0; /* Workbench stays closed; next VBlank jumps into freed code */ +``` + +## Right + +```c +ApolloTakeOver(); +ApolloTimer(); +/* ... */ +ApolloTimerStop(); /* ApolloLib 639e195 or later */ +ApolloRelease(); +return 0; +``` + +## Detection + +- Check which ApolloLib a project builds against: `ApolloRelease` and + `ApolloTimerStop` exist only from 639e195. A build that fails on them + uses an older copy. +- Read GFXMODE back at `$DFE1F4` after `ApolloShowPicture`: the high byte + must match the picture's size (see + [chunky-plane.md](../../core/saga-registers/chunky-plane.md)). + +## Evidence + +| Claim | Source | Core | Method | +|---|---|---|---| +| The bugs before 639e195 | (SRC) | any | Code reading of commit ce1fcbf, 2026-11-04 | +| Fixed in 639e195; builds without warnings | (SRC) | any | ApolloCrossDev #18: ApolloPointer, ApolloPiP (then SAGAPiP) and a link test build | +| None of the fixes is tested on V4 hardware | – | – | – | diff --git a/toolchain/project-makefile.md b/toolchain/project-makefile.md index e0a38e6..13d52a6 100644 --- a/toolchain/project-makefile.md +++ b/toolchain/project-makefile.md @@ -50,7 +50,8 @@ project folder must be two levels below the ApolloCrossDev root. | `C_LIBS_SDL`, `C_LIBS_MUI`, `C_LIBS_MATH` | off | Extra libraries, enable by removing `#` | The template only collects `.c` and `.s` files (`C_FILES`, `S_FILES`). It -also links every `.o` file in `Projects/ApolloLib`. +also links every `.o` file in `Projects/ApolloLib` (see +[apollolib/index.md](apollolib/index.md)). ### Targets diff --git a/tools/compile-snippets.sh b/tools/compile-snippets.sh index 70ff048..c44e254 100755 --- a/tools/compile-snippets.sh +++ b/tools/compile-snippets.sh @@ -4,7 +4,9 @@ # Snippets are compiled to object files, not linked, so each one must be a # complete translation unit. Flags follow the ApolloCrossDev Makefile template # (Projects/_makefiles/Makefile). PREFIX is the ApolloCrossDev compiler folder, -# e.g. ~/ApolloCrossDev/Compilers/GCC-6.50-Dev. +# e.g. ~/ApolloCrossDev/Compilers/GCC-6.50-Dev. When APOLLOLIB is set to an +# ApolloLib folder (ApolloCrossDev Projects/ApolloLib), snippets can include +# "ApolloCrossDev_Lib.h". # # compile-snippets.sh [dir] compile all .c/.cpp/.s files in dir # (default: build/snippets) @@ -19,6 +21,7 @@ AS="${AS:-$PREFIX/bin/vasmm68k_mot}" OPTS="-O2 -m68080 -m68881 -ffast-math -fomit-frame-pointer" INCL="-I$PREFIX/$TARGET/libnix/include -I$PREFIX/$TARGET/sys-include -I$PREFIX/$TARGET/ndk32-include/Include_H" +[ -n "$APOLLOLIB" ] && INCL="$INCL -I$APOLLOLIB" CFLAGS="${CFLAGS:--noixemul $OPTS -Wall $INCL}" CXXFLAGS="${CXXFLAGS:--noixemul $OPTS -Wall $INCL}" ASFLAGS="${ASFLAGS:--quiet -Fhunk -m68080 -m68881 -opt-speed -I$PREFIX/$TARGET/DevPac/Include}" diff --git a/tools/intake/sagaregs.py b/tools/intake/sagaregs.py index 4c9148a..c1df1b4 100644 --- a/tools/intake/sagaregs.py +++ b/tools/intake/sagaregs.py @@ -33,13 +33,13 @@ BIGGUN = "Gunnar (core developer, BigGun), Apollo chat, 2026-11-04 (relayed by WDrijver)" BGS = "G, 2026-11-04" APOLLOLIB = ("ApolloLib, github.com/WDrijver/ApolloCrossDev Projects/ApolloLib " - "(ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit 2dfaa5c (2026-09-02)") + "(ApolloCrossDev_Defines.h, ApolloCrossDev_LibC.c), commit ad7f0b4 (2026-11-04)") APOLLOLIB_OLD = ("ApolloLib, older copy in ApolloClaude docs/toolchain/_ApolloLib " "(ApolloCrossDev_Defines.h), 2026-11-04") -EX_PIP = ("Example SAGAPiP.c, github.com/WDrijver/ApolloCrossDev Projects/SAGAPiP, " - "commit 2dfaa5c (2026-09-02)") +EX_PIP = ("Example ApolloPiP.c (formerly SAGAPiP), github.com/WDrijver/ApolloCrossDev " + "Projects/ApolloPiP, commit ad7f0b4 (2026-11-04)") EX_POINTER = ("Example ApolloPointer.c, github.com/WDrijver/ApolloCrossDev " - "Projects/ApolloPointer, commit 2dfaa5c (2026-09-02)") + "Projects/ApolloPointer, commit ad7f0b4 (2026-11-04)") APOLLOOS = ("ApolloOS source, github.com/ApolloTeam-dev/ApolloOS.R10 " "arch/m68k-amiga/hidd/sagagfx/sagagfx_hw.h, commit ca5ef46 (2025-06-10)") MAGGIE = "maggie.library samples, see os/libraries/maggie-library.md" @@ -448,13 +448,13 @@ def pip(rows): p1 = pick(rows, 0xDFF3D0, 0xDFF3E2) details = ["### PIP 1 registers (original)", ""] + reg_table(p1) details += ["", "The original links these rows to a page that doesn't exist; the " - "facts below come from ApolloLib and the SAGAPiP example (SRC).", "", + "facts below come from ApolloLib and the ApolloPiP example (SRC).", "", "### PIP 2 registers (SRC, not in the original)", "", "PIP 2 has the same layout as PIP 1, `$20` lower (ApolloLib):", "", "| Address | Register | Same as PIP 1 |", "|---|---|---|"] details += [f"| `${a}` | {n} | `${addr(a) + 0x20:06X}` |" for a, n in PIP2] details += ["", "Its colour port is `$DFF37C` (see [colour-ports.md](colour-ports.md)). " - "The SAGAPiP example says two PIPs exist from Core 11900 (SRC).", "", + "The ApolloPiP example says two PIPs exist from Core 11900 (SRC).", "", "### Register meanings (SRC)", "", "| Register | Meaning |", "|---|---|", "| X/Y start, X/Y stop | Window position in screen pixels. The example " @@ -480,7 +480,7 @@ def pip(rows): f"Formats and transparent colours: {WDS}. The transparent colour is " "fixed per format. ApolloLib still marks YUV as not supported on PIP; " "that is an error in ApolloLib, not in the hardware.", "", - "### Two modes (SAGAPiP example, SRC)", "", + "### Two modes (ApolloPiP example, SRC)", "", "- **Overlay:** colour key 0. The PIP is in front of the main screen; " "with format bit 8 set, pixels in the transparent colour of the " "format are transparent.",