8.9 KiB
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 (
.dtftilesets, STL meshes, DTF headers, etc.) must be byte-swapped when read on Dolphin. - Use
endianLittleToHost32/endianLittleToHost16etc. fromutil/endian.hwhen 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:
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()returnsCONF_ASPECT_4_3on GameCube (always) and the user's setting on Wii. UsesystemGetAspectRatioDolphin().
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:
"/", "/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:
#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.
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 viaSAVE_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 viaSAVE_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:
// 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 with devkitPPC and
libogc installed.
# 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.hutilities 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; usefloat_tthroughout. consoleInitis shadowed toconsoleInitDolphinto avoid conflicts with the devkitPPC console API.- On GameCube
CONF_GetAspectRatio()is always 4:3; the macro is defined to returnCONF_ASPECT_4_3unconditionally. - DVD reads must be 32-byte aligned and padded -- use
ASSET_DOLPHIN_DVD_ALIGN_UP(n)when computing read sizes in ISO mode.