Created
May 5, 2026 10:39
-
-
Save liamlangli/de720e0df69ee5e4313163283a41bf30 to your computer and use it in GitHub Desktop.
GBA dev env agents.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # AGENTS.md - Game Boy Advance Development Guide | |
| This repository targets Nintendo Game Boy Advance homebrew in C/C++/ARM assembly, built with the official `devkitpro/devkitarm` Docker image and tested/debugged with mGBA. Treat this file as the standing instruction set for any AI coding agent, human contributor, or automation working in this project. | |
| Primary learning/reference source: TONC, "GBA Programming in rot13" by Jasper Vijn and the gbadev.net community. Use TONC for concepts, libtonc-style conventions, register explanations, and working examples. Use GBATEK for exact register-level reference when TONC is not specific enough. | |
| --- | |
| ## 1. Mission and Scope | |
| Build GBA software that is: | |
| - Correct on real GBA hardware, not merely on one emulator. | |
| - Efficient enough for a 16.78 MHz ARM7TDMI with tiny RAM and no operating system. | |
| - Easy to build reproducibly through Docker. | |
| - Debuggable through mGBA, GDB, logs, assertions, test ROMs, and small isolated demos. | |
| - Written in clear C first, with C++ used cautiously and assembly reserved for measured hot paths. | |
| Do not assume POSIX, a filesystem, dynamic loading, threads, heap abundance, floating-point hardware, a GPU command processor, or an operating system. The GBA is memory-mapped hardware plus CPU plus cartridge ROM. | |
| --- | |
| ## 2. Canonical Build Environment | |
| ### 2.1 Toolchain | |
| Use the official Docker image: | |
| ```sh | |
| docker pull devkitpro/devkitarm:latest | |
| ``` | |
| For reproducible CI/release builds, pin a dated tag instead of `latest`, for example: | |
| ```sh | |
| docker pull devkitpro/devkitarm:20260221 | |
| ``` | |
| Use `latest` during active prototyping only when accepting toolchain drift is okay. Record the exact image tag or digest used for releases. | |
| The container provides devkitARM under `/opt/devkitpro/devkitARM` and devkitPro tools under `/opt/devkitpro/tools/bin`. Expected environment: | |
| ```sh | |
| DEVKITPRO=/opt/devkitpro | |
| DEVKITARM=/opt/devkitpro/devkitARM | |
| PATH=/opt/devkitpro/devkitARM/bin:/opt/devkitpro/tools/bin:$PATH | |
| ``` | |
| ### 2.2 Build Commands | |
| Run builds from the repository root: | |
| ```sh | |
| docker run --rm -it \ | |
| -v "$PWD":/work \ | |
| -w /work \ | |
| devkitpro/devkitarm:latest \ | |
| make | |
| ``` | |
| Clean: | |
| ```sh | |
| docker run --rm -it -v "$PWD":/work -w /work devkitpro/devkitarm:latest make clean | |
| ``` | |
| Release build with a pinned image: | |
| ```sh | |
| docker run --rm -it \ | |
| -v "$PWD":/work \ | |
| -w /work \ | |
| devkitpro/devkitarm:20260221 \ | |
| make clean all | |
| ``` | |
| ### 2.3 Expected Build Outputs | |
| A standard GBA build should produce at least: | |
| - `build/*.o` object files. | |
| - `*.elf` unstripped ELF with symbols for debugging. | |
| - `*.gba` final ROM image with a valid GBA header. | |
| - Optional `*.map` linker map for memory inspection. | |
| The final ROM must be passed through `gbafix` unless the Makefile or devkitPro template already does this. A ROM that runs in mGBA but has an unfixed header may fail elsewhere. | |
| ### 2.4 Makefile Rules | |
| Prefer the devkitPro GBA Makefile pattern or a minimal equivalent. The build should be incremental, separate compilation from linking, and include asset conversion steps. | |
| Typical project layout: | |
| ```text | |
| . | |
| ├── AGENTS.md | |
| ├── Makefile | |
| ├── source/ | |
| │ ├── main.c | |
| │ ├── video.c | |
| │ ├── audio.c | |
| │ ├── input.c | |
| │ └── irq.c | |
| ├── include/ | |
| │ └── project/*.h | |
| ├── data/ | |
| │ ├── gfx/ | |
| │ ├── maps/ | |
| │ ├── audio/ | |
| │ └── generated/ | |
| ├── build/ | |
| └── dist/ | |
| ``` | |
| Never commit generated object files. Generated C/header asset files may be committed only if the project intentionally avoids requiring converter tools in the build. | |
| --- | |
| ## 3. Running and Debugging | |
| ### 3.1 Normal Emulator Run | |
| ```sh | |
| mgba dist/game.gba | |
| ``` | |
| or, if the Makefile writes the ROM at the root: | |
| ```sh | |
| mgba game.gba | |
| ``` | |
| Use mGBA for everyday testing because it is accurate enough for development and includes developer tooling such as memory viewers, debug logging, and a GDB server. | |
| ### 3.2 mGBA Command-Line Debugger | |
| Start mGBA's built-in command-line debugger: | |
| ```sh | |
| mgba -d dist/game.gba | |
| ``` | |
| Use it for quick breakpoints, disassembly, register inspection, stepping, and CPU-state checks. | |
| ### 3.3 GDB Remote Debugging with mGBA | |
| Start mGBA with the GDB stub: | |
| ```sh | |
| mgba -g dist/game.gba | |
| ``` | |
| By default, mGBA uses port `2345`. In another terminal: | |
| ```sh | |
| docker run --rm -it \ | |
| -v "$PWD":/work \ | |
| -w /work \ | |
| --network host \ | |
| devkitpro/devkitarm:latest \ | |
| arm-none-eabi-gdb dist/game.elf | |
| ``` | |
| Inside GDB: | |
| ```gdb | |
| target remote localhost:2345 | |
| break main | |
| continue | |
| ``` | |
| If `--network host` is unavailable, run GDB on the host or expose/connect to the correct host address. Always debug the ELF file, not the `.gba`, because the ELF contains symbols. | |
| ### 3.4 Debug Build Flags | |
| For debug builds, prefer: | |
| ```make | |
| CFLAGS += -g -Og | |
| ``` | |
| For release builds, prefer: | |
| ```make | |
| CFLAGS += -O2 | |
| ``` | |
| Use `-O3` only after measurement. Do not blindly optimize for speed if code size grows enough to harm cache/fetch behavior or ROM bandwidth. | |
| ### 3.5 Emulator Matrix | |
| Use at least: | |
| - mGBA: default development emulator and GDB debugging. | |
| - NanoBoyAdvance or SkyEmu: accuracy cross-check for timing-sensitive behavior. | |
| - Real hardware or flash cart: final validation, especially for DMA timing, audio, save memory, and interrupt behavior. | |
| - no$gba debug version when a visual debugger, profiler, or memory-access checking is needed. | |
| --- | |
| ## 4. Non-Negotiable Hardware Facts | |
| ### 4.1 CPU | |
| - CPU: ARM7TDMI, 32-bit RISC, clocked at `2^24 Hz` = about `16.78 MHz`. | |
| - Two instruction sets: ARM, 32-bit instructions; Thumb, 16-bit instructions. | |
| - Normal code in ROM should usually be Thumb for compactness and ROM bus efficiency. | |
| - Hot code may be ARM placed in IWRAM for speed. | |
| - No floating-point unit. Use fixed-point math and lookup tables for gameplay, transforms, audio rates, and effects. | |
| ### 4.2 Display | |
| - Resolution: `240 x 160` pixels. | |
| - Color: 15-bit BGR, stored in 16-bit values: `0bbbbbgggggrrrrr` with one unused high bit. | |
| - Refresh: about `59.73 Hz`. | |
| - One frame: `280,896` CPU cycles. | |
| - One scanline: `1,232` cycles. | |
| - HDraw: `240` pixels, `960` cycles. | |
| - HBlank: `68` pixel-times, `272` cycles. | |
| - VDraw: `160` scanlines, `197,120` cycles. | |
| - VBlank: `68` scanlines, `83,776` cycles. | |
| Use VBlank for OAM, palette, VRAM, scroll register, and high-level state commits whenever possible. Use HBlank only for intentional raster effects or HDMA. | |
| ### 4.3 Memory Map | |
| Core regions: | |
| | Region | Address | Size | Bus | Purpose | | |
| |---|---:|---:|---:|---| | |
| | BIOS ROM | `0x00000000` | 16 KiB | 32-bit | BIOS/SWI routines; executable but not normally readable | | |
| | EWRAM | `0x02000000` | 256 KiB | 16-bit | General work RAM; good for large data | | |
| | IWRAM | `0x03000000` | 32 KiB | 32-bit | Fast internal RAM; hot code/data/IRQ stacks | | |
| | I/O | `0x04000000` | 1 KiB | 32-bit | Memory-mapped registers | | |
| | Palette RAM | `0x05000000` | 1 KiB | 16-bit | 256 BG colors + 256 OBJ colors | | |
| | VRAM | `0x06000000` | 96 KiB | 16-bit | BG/OBJ tile, map, and bitmap data | | |
| | OAM | `0x07000000` | 1 KiB | 32-bit | 128 hardware object entries | | |
| | Game Pak ROM | `0x08000000` | up to 32 MiB | 16-bit | Code and read-only data | | |
| | Cart RAM | `0x0E000000` | variable | 8-bit | Save memory: SRAM/Flash/EEPROM | | |
| Never write to ROM. Never treat I/O registers as ordinary RAM. Use `volatile` for memory-mapped registers and shared IRQ state. | |
| ### 4.4 Video Capabilities | |
| - 6 video modes: modes 0-2 tiled, modes 3-5 bitmap. | |
| - 4 background layers in tiled modes, with mode-dependent regular/affine support. | |
| - 128 hardware objects/sprites. | |
| - Up to 4 tilemap backgrounds, one sprite/object layer, windows, mosaic, alpha blending, brightness fade, affine transforms. | |
| - Objects range from `8x8` to `64x64` pixels. | |
| - Sprite and BG pixels with palette index 0 are transparent in paletted modes. | |
| ### 4.5 Audio Capabilities | |
| - 6 channels total. | |
| - 4 Game Boy PSG channels: two square-wave channels, one programmable wave channel, one noise channel. | |
| - 2 DirectSound FIFO channels, A and B, for signed 8-bit PCM samples. | |
| - DirectSound playback is timer-driven and usually fed by DMA channel 1 or 2. | |
| - Audio code must be timing-aware; underfeeding FIFO causes pops/clicks. | |
| ### 4.6 Input | |
| - 10 buttons: A, B, Select, Start, Right, Left, Up, Down, R, L. | |
| - `REG_KEYINPUT` bits are active-low: a pressed key reads as `0`. | |
| - Always edge-detect for menu actions and button-down for continuous movement. | |
| - Debounce game actions at the gameplay layer, not by sleeping the CPU. | |
| ### 4.7 DMA | |
| - 4 DMA channels. | |
| - DMA0: highest priority; internal RAM only; avoid casual use. | |
| - DMA1/DMA2: often used for DirectSound FIFO feeding. | |
| - DMA3: general-purpose copies/fills and bulk transfers. | |
| - DMA can start immediately, at VBlank, at HBlank, or special refresh/FIFO timing depending on channel/mode. | |
| - DMA count is in units of halfwords or words, not bytes. | |
| - DMA fill source is an address containing the fill value, not the immediate value itself. | |
| - DMA halts the CPU during transfer. Do not assume interrupts continue normally during a large DMA copy. | |
| ### 4.8 Timers | |
| - 4 hardware timers. | |
| - Base clock: CPU clock, about `16.78 MHz`. | |
| - Prescalers: 1, 64, 256, 1024 cycles. | |
| - Timers can overflow, cascade, raise IRQs, and drive DirectSound sample rates. | |
| - VBlank is the primary game clock for most gameplay. Hardware timers are for sub-frame timing, profiling, audio, fixed-rate systems, or precise delays. | |
| ### 4.9 Interrupts | |
| - Main registers: `REG_IE`, `REG_IF`, `REG_IME`. | |
| - `REG_IME` is the master interrupt enable. | |
| - `REG_IE` selects which interrupts are accepted. | |
| - `REG_IF` records pending interrupts; acknowledge by writing `1` to the handled bit. | |
| - Many interrupts require enabling both the receiver (`REG_IE`) and sender-side register bit, e.g. VBlank/HBlank/VCount in `REG_DISPSTAT`. | |
| - Interrupt routines must be short, deterministic, and careful with shared state. | |
| - Use VBlank IRQ or `VBlankIntrWait` instead of busy-waiting when practical. | |
| ### 4.10 BIOS/SWI | |
| The BIOS provides SWI calls for reset, halt, `IntrWait`, `VBlankIntrWait`, division, square root, arctangent, CPUSet/CPUFastSet, affine setup, decompression, sound routines, multiboot, and more. Prefer libtonc/devkitPro wrappers where available. | |
| --- | |
| ## 5. Rendering Strategy | |
| ### 5.1 Choose the Right Video Mode | |
| Use tiled modes for most games. | |
| - Mode 0: four regular tiled backgrounds. Best default for tile-based 2D games. | |
| - Mode 1: two regular BGs plus one affine BG. | |
| - Mode 2: two affine BGs. | |
| - Mode 3: `240x160`, 16bpp bitmap, one frame. Easy but slow and VRAM-heavy. | |
| - Mode 4: `240x160`, 8bpp paletted bitmap, two pages. Useful for page-flipped software rendering. | |
| - Mode 5: `160x128`, 16bpp bitmap, two pages. Smaller framebuffer, page-flipped. | |
| Bitmap modes are good for demos, generated images, software 3D, or highly dynamic full-screen effects. They are usually not the right default for conventional sprite/tile games. | |
| ### 5.2 VBlank Discipline | |
| During active drawing, VRAM/OAM/palette writes can cause visual artifacts or undefined behavior. The standard frame loop should be: | |
| ```c | |
| while (1) { | |
| read_input(); | |
| update_game_logic(); | |
| prepare_render_state(); | |
| VBlankIntrWait(); // or vid_vsync() / irq-driven equivalent | |
| commit_oam(); | |
| commit_bg_scrolls(); | |
| commit_palette_changes(); | |
| commit_vram_uploads_small(); | |
| } | |
| ``` | |
| Large VRAM uploads should be split across frames, done during forced blank, or scheduled during loading screens. | |
| ### 5.3 Backgrounds | |
| For tiled backgrounds: | |
| - Tiles are always `8x8` pixels. | |
| - Use charblocks for tile graphics and screenblocks for tile maps. | |
| - A screenblock is a tilemap block in VRAM. | |
| - Use 4bpp for memory efficiency when 16 colors per palette is enough. | |
| - Use 8bpp when the art needs a full 256-color palette. | |
| - Scroll with BG scroll registers instead of redrawing pixels. | |
| - Use affine BGs for rotation/scaling, Mode 7 style effects, or large transformed surfaces. | |
| ### 5.4 Sprites / Objects | |
| To display a sprite: | |
| 1. Convert image data into 4bpp or 8bpp GBA object tiles. | |
| 2. Load object tiles into object VRAM. | |
| 3. Load object palette data into object palette RAM. | |
| 4. Fill OAM attributes: position, shape, size, tile index, palette bank, priority, affine flags. | |
| 5. Enable objects in `REG_DISPCNT` and choose 1D or 2D mapping. | |
| Use 1D object mapping unless the project has a specific reason not to. Keep a shadow OAM array in normal RAM, update it during game logic, then DMA/copy to real OAM in VBlank. | |
| ### 5.5 Palettes | |
| - 15-bit colors: 5 bits each for red, green, blue. | |
| - BG palette memory and OBJ palette memory are separate. | |
| - In 4bpp, each tile references one of 16 palette banks. | |
| - In 8bpp, tiles reference one 256-color palette. | |
| - Palette index 0 is transparent for sprites and commonly transparent for tile layers depending on context. | |
| Palette effects are cheap. Prefer palette cycling/fading over rewriting large tile data. | |
| ### 5.6 Special Effects | |
| Use hardware effects where possible: | |
| - Mosaic for chunky transitions. | |
| - Alpha blending for layer combinations. | |
| - Brightness increase/decrease for fades. | |
| - Window registers for masks, spotlights, UI clipping, and split-screen effects. | |
| - HBlank IRQ/HDMA for scanline effects. | |
| Keep raster effects isolated and documented. Timing-sensitive code should be tested in at least two emulators and, before release, real hardware. | |
| --- | |
| ## 6. Audio Strategy | |
| ### 6.1 PSG Channels | |
| Use the four legacy Game Boy channels for simple sound effects when appropriate: | |
| - Square 1 and Square 2: beeps, UI sounds, simple melody. | |
| - Wave: small custom waveform playback. | |
| - Noise: explosions, hits, footsteps, percussion. | |
| These are hardware-generated and CPU-light, but limited. | |
| ### 6.2 DirectSound | |
| Use DirectSound A/B for PCM music and sample playback: | |
| - Samples are signed 8-bit PCM. | |
| - Feed FIFO A/B with DMA1 or DMA2. | |
| - Use a hardware timer to set sample rate. | |
| - Keep mixing code deterministic and efficient. | |
| - Double-buffer or ring-buffer audio data if writing a custom mixer. | |
| For a game-scale project, strongly consider a known GBA audio library or devkitPro-compatible engine rather than inventing a full tracker/streaming stack immediately. | |
| ### 6.3 Audio Rules | |
| - Do not allocate audio buffers dynamically during gameplay. | |
| - Avoid expensive mixing in VBlank if it risks missing rendering commits. | |
| - Keep audio IRQ/DMA handling minimal. | |
| - Document sample rates, buffer sizes, and timer reload values. | |
| - Test for pops/clicks under gameplay load, not only in empty scenes. | |
| --- | |
| ## 7. Code Style and Architecture | |
| ### 7.1 Language | |
| - Use C99 or conservative C++ only if the Makefile and runtime are configured for it. | |
| - Prefer fixed-size integer types: `u8`, `u16`, `u32`, `s8`, `s16`, `s32` or `<stdint.h>` equivalents. | |
| - Use `volatile` for hardware registers and data shared with IRQ handlers. | |
| - Avoid heap allocation in gameplay code. Prefer static pools, arenas, and compile-time buffers. | |
| - Avoid recursion. | |
| - Avoid floating point in runtime code. Use fixed-point math. | |
| ### 7.2 Register Access | |
| Use libtonc/devkitPro headers when possible. If defining registers manually: | |
| ```c | |
| #define REG_DISPCNT (*(volatile u16*)0x04000000) | |
| ``` | |
| Never hide volatile register reads behind non-volatile cached variables unless intentionally taking a snapshot. | |
| ### 7.3 Frame Loop Ownership | |
| Separate systems: | |
| - `input`: reads and edge-detects keypad state. | |
| - `game`: updates gameplay state. | |
| - `render`: builds shadow OAM/BG/palette state. | |
| - `video`: commits state to hardware during VBlank. | |
| - `audio`: owns timers/DMA/FIFO/audio buffers. | |
| - `irq`: owns interrupt setup and dispatch. | |
| - `assets`: generated data and metadata. | |
| Avoid mixing direct hardware writes into gameplay logic. Gameplay should request visual/audio changes; platform layers should perform hardware writes at safe times. | |
| ### 7.4 Fixed-Point Math | |
| Use a project-wide fixed-point convention, for example: | |
| ```c | |
| typedef s32 fix16; // 16.16 fixed point | |
| #define FIX_SHIFT 16 | |
| #define FIX_ONE (1 << FIX_SHIFT) | |
| #define INT2FIX(n) ((n) << FIX_SHIFT) | |
| #define FIX2INT(x) ((x) >> FIX_SHIFT) | |
| ``` | |
| Document any alternative such as 8.8 for affine parameters or subpixel positions. | |
| ### 7.5 Assembly | |
| Assembly is allowed only when: | |
| - Profiling shows C is insufficient. | |
| - The function boundary and ABI are documented. | |
| - A C fallback or test harness exists where practical. | |
| - The code specifies ARM vs Thumb state and target section. | |
| Place hot ARM code in IWRAM only after measuring benefit and confirming memory budget. | |
| --- | |
| ## 8. Assets Pipeline | |
| ### 8.1 Graphics | |
| Use tools that produce GBA-native data: | |
| - Tiles: 4bpp/8bpp, `8x8` tile order. | |
| - Tilemaps: screenblock-compatible maps or project-defined compressed maps. | |
| - Palettes: 15-bit BGR values. | |
| - Sprites: object tiles respecting shape/size limits. | |
| Preferred rule: convert assets at build time from source PNG/Tiled/etc. to generated C/header/binary data. | |
| ### 8.2 Maps | |
| For large maps: | |
| - Store metatiles when possible. | |
| - Stream chunks into screenblocks as the camera moves. | |
| - Keep collision maps separate from visual maps. | |
| - Compress ROM data where useful, decompress into EWRAM/VRAM during loading. | |
| ### 8.3 Compression | |
| GBA BIOS supports decompression SWIs including LZ77, Huffman, RLE, and differential filters. Use them for ROM-size reduction, but budget decompression time and destination restrictions. | |
| ### 8.4 Audio Assets | |
| Track, for each asset: | |
| - Format. | |
| - Sample rate. | |
| - Signed/unsigned conversion status. | |
| - Loop points. | |
| - Target playback channel/system. | |
| - Memory residency: ROM, EWRAM, IWRAM, streaming buffer. | |
| --- | |
| ## 9. Performance Rules | |
| ### 9.1 Frame Budget | |
| At 59.73 Hz, one frame is `280,896` cycles. Most of that is visible scanout, not a safe time to blindly mutate display memory. VBlank is `83,776` cycles. Treat VBlank as precious. | |
| ### 9.2 Prefer Hardware | |
| - Use BG scroll registers instead of moving pixels. | |
| - Use sprites instead of software blitting actors. | |
| - Use palette effects instead of mass pixel edits. | |
| - Use DMA for bulk copies, but do not spam DMA for tiny copies. | |
| - Use affine hardware where it fits. | |
| ### 9.3 Measure | |
| Use timers, mGBA tooling, no$gba profiling, and controlled stress scenes. Do not optimize based only on intuition. | |
| ### 9.4 Common Pitfalls | |
| - Writing too much VRAM during active display. | |
| - Forgetting active-low keypad bits. | |
| - DMA count in bytes instead of halfwords/words. | |
| - DMA fill using an immediate value instead of an address. | |
| - Updating real OAM outside VBlank. | |
| - Dividing by zero in BIOS `Div`. | |
| - Assuming emulator behavior equals hardware behavior. | |
| - Using `int`/`float` casually in tight loops without understanding codegen. | |
| - Letting Makefile paths contain spaces. | |
| - Debugging a `.gba` file instead of the symbol-rich `.elf`. | |
| --- | |
| ## 10. Testing and Validation | |
| ### 10.1 Minimum Checks Before Commit | |
| Run: | |
| ```sh | |
| docker run --rm -it -v "$PWD":/work -w /work devkitpro/devkitarm:latest make clean all | |
| mgba dist/game.gba | |
| ``` | |
| Manually verify: | |
| - Boot succeeds. | |
| - First screen renders correctly. | |
| - Input works. | |
| - Audio starts/stops without obvious clicks. | |
| - No visible tearing during normal gameplay. | |
| - No OAM corruption when many sprites are active. | |
| ### 10.2 Regression ROMs | |
| When fixing hardware bugs, create tiny test scenes: | |
| - `tests/vblank_oam/` | |
| - `tests/dma_copy/` | |
| - `tests/timer_audio/` | |
| - `tests/bg_scroll/` | |
| - `tests/sprite_affine/` | |
| Each should build to a ROM and document expected visual/audio behavior. | |
| ### 10.3 Hardware Verification Checklist | |
| Before a release: | |
| - Test on mGBA. | |
| - Test on at least one stricter emulator. | |
| - Test on real GBA/DS/Lite/Micro or trusted hardware route if available. | |
| - Test save behavior if cart RAM is used. | |
| - Test long-running audio and scene transitions. | |
| - Test after a cold boot, not only emulator reset. | |
| --- | |
| ## 11. CI Guidance | |
| A minimal CI build can run Docker and invoke `make`: | |
| ```sh | |
| docker run --rm \ | |
| -v "$PWD":/work \ | |
| -w /work \ | |
| devkitpro/devkitarm:20260221 \ | |
| make clean all | |
| ``` | |
| Archive `.gba`, `.elf`, and `.map` as build artifacts. For releases, also record: | |
| - Git commit hash. | |
| - Docker image tag/digest. | |
| - Compiler version: `arm-none-eabi-gcc --version`. | |
| - ROM SHA-256. | |
| --- | |
| ## 12. Documentation Rules for Agents | |
| When editing this project: | |
| 1. Prefer small, reviewable changes. | |
| 2. Update comments when changing hardware assumptions. | |
| 3. Do not invent register values from memory; verify with TONC, libtonc headers, GBATEK, or devkitPro examples. | |
| 4. Do not introduce dependencies that are unavailable in `devkitpro/devkitarm` unless the Docker workflow is updated. | |
| 5. Keep asset-source files and generated files clearly separated. | |
| 6. Document any timing-sensitive code with the relevant frame/scanline/VBlank budget. | |
| 7. When adding assembly, document ABI, clobbers, alignment, ARM/Thumb state, and section placement. | |
| 8. If behavior is emulator-specific, say so in the code comment or issue. | |
| 9. Preserve the `.elf` for debugging. | |
| 10. Never remove `gbafix`/ROM-header finalization unless replacing it with an equivalent. | |
| --- | |
| ## 13. Suggested Starter Make Targets | |
| ```make | |
| .PHONY: all clean run debug gdb release | |
| all: | |
| $(MAKE) build | |
| run: all | |
| mgba dist/game.gba | |
| debug: all | |
| mgba -g dist/game.gba | |
| gdb: all | |
| docker run --rm -it -v "$(PWD)":/work -w /work --network host devkitpro/devkitarm:latest arm-none-eabi-gdb dist/game.elf | |
| release: | |
| docker run --rm -it -v "$(PWD)":/work -w /work devkitpro/devkitarm:20260221 make clean all | |
| clean: | |
| rm -rf build dist | |
| ``` | |
| Adapt this to the actual devkitPro template in the repository. Do not blindly overwrite a working Makefile. | |
| --- | |
| ## 14. Source References | |
| Use these references in this order: | |
| 1. TONC introduction and chapter index: `https://gbadev.net/tonc/intro.html` | |
| 2. TONC hardware overview: `https://gbadev.net/tonc/hardware.html` | |
| 3. TONC setup/devkitARM/mGBA: `https://gbadev.net/tonc/setup.html` | |
| 4. TONC video timing and display: `https://gbadev.net/tonc/video.html` | |
| 5. TONC bitmap modes: `https://gbadev.net/tonc/bitmaps.html` | |
| 6. TONC sprites/backgrounds: `https://gbadev.net/tonc/objbg.html`, `https://gbadev.net/tonc/regobj.html`, `https://gbadev.net/tonc/regbg.html` | |
| 7. TONC DMA: `https://gbadev.net/tonc/dma.html` | |
| 8. TONC timers: `https://gbadev.net/tonc/timers.html` | |
| 9. TONC interrupts: `https://gbadev.net/tonc/interrupts.html` | |
| 10. TONC BIOS/SWI: `https://gbadev.net/tonc/swi.html` | |
| 11. TONC ARM assembly: `https://gbadev.net/tonc/asm.html` | |
| 12. GBATEK technical reference: `https://problemkaputt.de/gbatek-index.htm` | |
| 13. devkitPro Docker Hub: `https://hub.docker.com/r/devkitpro/devkitarm/tags/` | |
| 14. mGBA: `https://mgba.io/` | |
| --- | |
| ## 15. Default Agent Response to New Tasks | |
| When asked to implement a feature: | |
| 1. Identify which subsystem is affected: input, gameplay, video, audio, DMA, IRQ, assets, build, or debug. | |
| 2. State any hardware limits that constrain the feature. | |
| 3. Make the smallest implementation plan. | |
| 4. Modify code and assets. | |
| 5. Build with Docker. | |
| 6. Provide run/debug commands. | |
| 7. Note what was not tested on hardware. | |
| When asked a hardware question: | |
| 1. Answer with the relevant register/memory/timing facts. | |
| 2. Explain the safe usage pattern. | |
| 3. Mention common failure modes. | |
| 4. Point to TONC/GBATEK section names or URLs. | |
| When asked to optimize: | |
| 1. Measure or explain how to measure. | |
| 2. Check algorithmic cost first. | |
| 3. Prefer hardware features. | |
| 4. Consider memory placement and data width. | |
| 5. Use assembly only after evidence. | |
| --- | |
| ## 16. Working Assumptions | |
| Unless a task says otherwise: | |
| - Target hardware: Game Boy Advance-compatible hardware. | |
| - Toolchain: `devkitpro/devkitarm` Docker image. | |
| - Main language: C. | |
| - Library baseline: libtonc/devkitPro GBA headers are allowed. | |
| - Emulator: mGBA first. | |
| - Frame pacing: VBlank-synchronized 59.73 Hz. | |
| - Rendering default: tiled backgrounds plus sprites. | |
| - Audio default: PSG for simple SFX, DirectSound/timer/DMA or library for PCM/music. | |
| - Debug symbols: keep `.elf`. | |
| - Release ROM: fixed `.gba` header. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment