289 lines
8.9 KiB
Markdown
289 lines
8.9 KiB
Markdown
# Platform -- Dolphin (GameCube and Wii)
|
|
|
|
`DUSK_TARGET_SYSTEM`: `gamecube` / `wii`
|
|
Source layer: `src/duskdolphin/`
|
|
Renderer: libogc GX (native Nintendo hardware)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
GameCube and Wii are collectively called the **Dolphin** targets. They
|
|
share a single source layer (`src/duskdolphin/`) and a shared CMake base
|
|
(`cmake/targets/dolphin.cmake`). Individual targets add `DUSK_GAMECUBE`
|
|
or `DUSK_WII` on top.
|
|
|
|
Both are **big-endian** PowerPC platforms. They do **not** use SDL2 or
|
|
OpenGL -- rendering and input go through `libogc` (the open-source
|
|
GameCube/Wii SDK) and the GX hardware API directly.
|
|
|
|
---
|
|
|
|
## Hardware
|
|
|
|
| Attribute | GameCube | Wii |
|
|
|-----------|---------|-----|
|
|
| CPU | IBM PowerPC 750CL (Gekko), 485 MHz | IBM Broadway (Wii CPU), 729 MHz |
|
|
| RAM | 24 MB (16 MB MEM1 + 8 MB ARAM) | 88 MB (24 MB MEM1 + 64 MB MEM2) |
|
|
| GPU | ATI Flipper (GX) | ATI Hollywood (GX) |
|
|
| Display | 640x480 (480p max) | 640x480 (480p/576i), 480p/1080i via component |
|
|
| Storage | Memory Card (slots A/B), SD Gecko | SD card, USB, NAND |
|
|
| Endian | Big-endian | Big-endian |
|
|
|
|
Treat the **GameCube 16 MB MEM1** as the worst-case RAM budget for data
|
|
structures shared between both targets.
|
|
|
|
---
|
|
|
|
## Compile-time macros
|
|
|
|
| Macro | GameCube | Wii | Notes |
|
|
|-------|---------|-----|-------|
|
|
| `DUSK_DOLPHIN` | yes | yes | Set by `dolphin.cmake` |
|
|
| `DUSK_GAMECUBE` | yes | no | |
|
|
| `DUSK_WII` | no | yes | |
|
|
| `DUSK_INPUT_GAMEPAD` | yes | yes | |
|
|
| `DUSK_DISPLAY_WIDTH` | 640 | 640 | |
|
|
| `DUSK_DISPLAY_HEIGHT` | 480 | 480 | |
|
|
| `DUSK_THREAD_PTHREAD` | yes | yes | devkitPPC pthreads |
|
|
| `DUSK_PLATFORM_ENDIAN_BIG` | yes | yes | Not set by cmake -- apply manually |
|
|
| `DOL` | 1 | 1 | Build type token |
|
|
| `ISO` | 2 | 2 | Build type token |
|
|
| `DUSK_DOLPHIN_BUILD_TYPE` | `DOL` or `ISO` | `DOL` or `ISO` | |
|
|
| `DUSK_DOLPHIN_BUILD_ISO` | if ISO mode | if ISO mode | |
|
|
|
|
No `DUSK_SDL2`, no `DUSK_OPENGL`, no `DUSK_INPUT_KEYBOARD`,
|
|
no `DUSK_INPUT_POINTER`, no `DUSK_TIME_DYNAMIC`.
|
|
|
|
Attempting to use `DUSK_INPUT_KEYBOARD` or `DUSK_INPUT_POINTER` causes
|
|
a compile-time `#error` in `inputdolphin.h`.
|
|
|
|
---
|
|
|
|
## Endianness
|
|
|
|
**Both GameCube and Wii are big-endian.** This is the most critical
|
|
platform difference from all other targets.
|
|
|
|
- All binary asset data (`.dtf` tilesets, STL meshes, DTF headers, etc.)
|
|
must be byte-swapped when read on Dolphin.
|
|
- Use `endianLittleToHost32` / `endianLittleToHost16` etc. from
|
|
`util/endian.h` when reading any multi-byte value from a file.
|
|
- Save files are stored in little-endian order; the save stream handles
|
|
this transparently via the `saveFile*` macros.
|
|
- Network data likewise needs endian conversion.
|
|
|
|
See `.claude/util.md` (Endian section) for the full API.
|
|
|
|
---
|
|
|
|
## Display
|
|
|
|
- Fixed 640x480 resolution, driven by GX (the hardware rasteriser).
|
|
- Uses double-buffered framebuffers:
|
|
```c
|
|
typedef struct {
|
|
void *frameBuffer[2]; // double-buffered
|
|
int_t whichFrameBuffer;
|
|
GXRModeObj *screenMode;
|
|
void *fifoBuffer; // GX command FIFO, 256 KB
|
|
} displaydolphin_t;
|
|
```
|
|
- The GX pipeline uses display lists for efficient draw call batching --
|
|
avoid immediate-mode GX calls in the hot path.
|
|
- `CONF_GetAspectRatio()` returns `CONF_ASPECT_4_3` on GameCube (always)
|
|
and the user's setting on Wii. Use `systemGetAspectRatioDolphin()`.
|
|
|
|
---
|
|
|
|
## Asset loading
|
|
|
|
Two modes are selected at CMake configure time via
|
|
`DUSK_DOLPHIN_BUILD_TYPE`:
|
|
|
|
### DOL mode (default -- `DUSK_DOLPHIN_BUILD_TYPE=DOL`)
|
|
|
|
Assets are loaded from `dusk.dsk` on a FAT filesystem -- SD card on Wii
|
|
(via SD slot), or SD Gecko / SD adapter on GameCube. The loader searches
|
|
these paths in order:
|
|
|
|
```c
|
|
"/", "/Dusk", "/dusk", "/DUSK",
|
|
"/apps", "/apps/Dusk", "/apps/dusk", "/apps/DUSK",
|
|
".", "./Dusk", "./dusk", ...
|
|
```
|
|
|
|
Uses `libfat` for filesystem access.
|
|
|
|
### ISO mode (`DUSK_DOLPHIN_BUILD_TYPE=ISO`)
|
|
|
|
`dusk.dsk` is read directly off the DVD disc via the libogc DVD driver
|
|
(`assetdolphindvd.c`). Reads are 32-byte aligned:
|
|
|
|
```c
|
|
#define ASSET_DOLPHIN_DVD_ALIGN 32u
|
|
```
|
|
|
|
The DVD FST (file-system table) is parsed at init to locate the data
|
|
file. All reads go through `assetDolphinDVDRead(offset, size)` which
|
|
returns an aligned heap buffer that the caller must free.
|
|
|
|
Post-build in ISO mode, `makedolphiniso.py` produces **three disc
|
|
images** (NTSC-J, NTSC-U, PAL).
|
|
|
|
---
|
|
|
|
## Input
|
|
|
|
Uses libogc `PAD` API. Only GameCube controllers are supported (port 0
|
|
by default; up to 4 via `PAD_CHANMAX`).
|
|
|
|
Available axes (6 total per controller):
|
|
|
|
| Axis | Enum |
|
|
|------|------|
|
|
| Left stick X/Y | `INPUT_GAMEPAD_AXIS_LEFT_X/Y` |
|
|
| C-stick X/Y | `INPUT_GAMEPAD_AXIS_C_X/Y` |
|
|
| L trigger | `INPUT_GAMEPAD_AXIS_TRIGGER_LEFT` |
|
|
| R trigger | `INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT` |
|
|
|
|
Axis values are normalised by dividing the raw 8-bit value by 128.0.
|
|
Deadzone: 0.2 (hardcoded).
|
|
|
|
Default bindings set at init: D-pad/left stick = directional actions,
|
|
A = ACCEPT, B = CANCEL, X = CONSOLE, Start = RAGEQUIT.
|
|
|
|
Wii Remote / Nunchuk / Classic Controller / Pro Controller are not yet
|
|
implemented (noted as TODO in `inputdolphin.h`).
|
|
|
|
---
|
|
|
|
## Save system
|
|
|
|
Uses the libogc Memory Card API (`CARD_*`) to read/write save slots.
|
|
|
|
```c
|
|
typedef struct {
|
|
card_file cardFile;
|
|
uint8_t cardBuffer[CARD_WORKAREA] __attribute__((aligned(32)));
|
|
bool_t mounted;
|
|
} savedolphin_t;
|
|
```
|
|
|
|
- Default channel: `CARD_SLOTA` (Memory Card slot A).
|
|
Override via `SAVE_DOLPHIN_CHANNEL`.
|
|
- Sector size: 8192 bytes (`SAVE_DOLPHIN_SECTOR_SIZE`).
|
|
- Buffers must be 32-byte aligned (enforced by `__attribute__((aligned(32)))`).
|
|
- Game code: `DUSK` (4 chars, override via `SAVE_DOLPHIN_GAME_CODE`).
|
|
- The card must be mounted before any read/write. `saveInitDolphin()`
|
|
mounts slot A; failures are treated as "no save present".
|
|
- Save stream handles little-endian encoding transparently -- all data
|
|
stored little-endian on the card even though the CPU is big-endian.
|
|
|
|
---
|
|
|
|
## Network
|
|
|
|
### GameCube
|
|
|
|
`net_init()` is commented out. Networking is **non-functional** on
|
|
GameCube in the current codebase. The BBA (Broadband Adapter) link
|
|
library is in a commented `# bba` in `gamecube.cmake`.
|
|
|
|
### Wii
|
|
|
|
Uses `if_config()` from libogc which reads Wi-Fi settings saved in the
|
|
Wii System Menu. The call **blocks** the main thread until DHCP
|
|
completes or fails. Wii network is available only when `DUSK_WII` is
|
|
defined; the GameCube path always fails immediately.
|
|
|
|
IPv6 is not supported on either Dolphin target.
|
|
|
|
---
|
|
|
|
## Time
|
|
|
|
- No `DUSK_TIME_DYNAMIC`. All ticks are fixed 16 ms steps.
|
|
- Tick source: `__SYS_GetSystemTime()` returns PowerPC bus ticks.
|
|
- Real time: ticks converted to microseconds via `ticks_to_microsecs()`,
|
|
then offset from the GameCube epoch (2000-01-01 00:00:00) to the UNIX
|
|
epoch (1970-01-01 00:00:00) by adding **946 684 800 seconds**.
|
|
- Timezone: always returned as 0 -- no timezone data without network time.
|
|
|
|
---
|
|
|
|
## System
|
|
|
|
Language and aspect ratio queries:
|
|
|
|
```c
|
|
// Language (used for locale selection):
|
|
systemGetLanguageDolphin();
|
|
// -> SYS_GetLanguage() on GameCube
|
|
// -> CONF_GetLanguage() on Wii
|
|
|
|
// Aspect ratio:
|
|
systemGetAspectRatioDolphin();
|
|
// -> CONF_ASPECT_4_3 always on GameCube
|
|
// -> CONF_GetAspectRatio() on Wii (4:3 or 16:9)
|
|
```
|
|
|
|
---
|
|
|
|
## Build and toolchain
|
|
|
|
Requires [devkitPro](https://devkitpro.org/) with `devkitPPC` and
|
|
`libogc` installed.
|
|
|
|
```sh
|
|
# GameCube (SD card / DOL mode)
|
|
cmake -B build \
|
|
-DDUSK_TARGET_SYSTEM=gamecube \
|
|
-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/GameCube.cmake \
|
|
-DCMAKE_BUILD_TYPE=Release
|
|
cmake --build build
|
|
|
|
# Wii (SD card / DOL mode)
|
|
cmake -B build \
|
|
-DDUSK_TARGET_SYSTEM=wii \
|
|
-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Wii.cmake \
|
|
-DCMAKE_BUILD_TYPE=Release
|
|
cmake --build build
|
|
|
|
# Either target in ISO mode
|
|
cmake -B build \
|
|
-DDUSK_TARGET_SYSTEM=gamecube \
|
|
-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/GameCube.cmake \
|
|
-DDUSK_DOLPHIN_BUILD_TYPE=ISO \
|
|
-DCMAKE_BUILD_TYPE=Release
|
|
cmake --build build
|
|
```
|
|
|
|
Post-build outputs (DOL mode): `Dusk.elf` + `Dusk.dol` (generated by
|
|
`elf2dol`). Copy `Dusk.dol` and `dusk.dsk` to the SD card.
|
|
|
|
Post-build outputs (ISO mode): `Dusk.dol` + disc images in
|
|
`NTSC-J/`, `NTSC-U/`, `PAL/` subdirectories.
|
|
|
|
Dependencies: libogc, devkitPPC, `fat` (DOL mode), cglm, zip, bz2,
|
|
zstd, z, lzma, m.
|
|
|
|
---
|
|
|
|
## Gotchas
|
|
|
|
- **Big-endian is the most common source of bugs** when porting code
|
|
from Linux. Always use `endian.h` utilities for file I/O and network.
|
|
- Memory is tight on GameCube -- 16 MB MEM1 must hold code, stack, heap,
|
|
framebuffers (2x 640x480x2 bytes), and the GX FIFO (256 KB).
|
|
- GX display lists are the correct rendering path; immediate-mode GX
|
|
calls carry heavy CPU overhead on the short FIFO pipeline.
|
|
- The GameCube has no FPU for integer paths. Avoid `double`; use
|
|
`float_t` throughout.
|
|
- `consoleInit` is shadowed to `consoleInitDolphin` to avoid conflicts
|
|
with the devkitPPC console API.
|
|
- On GameCube `CONF_GetAspectRatio()` is always 4:3; the macro is
|
|
defined to return `CONF_ASPECT_4_3` unconditionally.
|
|
- DVD reads must be 32-byte aligned and padded -- use
|
|
`ASSET_DOLPHIN_DVD_ALIGN_UP(n)` when computing read sizes in ISO mode.
|