Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
92 changes: 92 additions & 0 deletions toolchain/apollolib/debug.md
Original file line number Diff line number Diff line change
@@ -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.
121 changes: 121 additions & 0 deletions toolchain/apollolib/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
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, SAGAPiP) 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`.

## 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`.
99 changes: 99 additions & 0 deletions toolchain/apollolib/input.md
Original file line number Diff line number Diff line change
@@ -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.
Loading
Loading