Files
dusk/.claude/platform-dolphin.md
T
2026-06-16 10:15:59 -05:00

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 (.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:
    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:

"/", "/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 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:

// 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.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.