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