GBAのメモリエリアは次のようになっています。ここではザックリと概要のみ説明しますので詳細はGBATEKを読んでください。
エリア | 開始位置 | 終了位置 | 大きさ |
System ROM | 0000:0000h | 0000:3fffh | 16kb |
EWRAM | 0200:0000h | 0203:ffffh | 256kb |
IWRAM | 0300:0000h | 0300:7fffh | 32kb |
IO RAM | 0400:0000h | 0401:03ffh | 1kb |
PAL RAM | 0500:0000h | 0500:03ffh | 1kb |
VRAM | 0600:0000h | 0601:7fffh | 96kb |
OAM | 0700:0000h | 0700:03ffh | 1kb |
PAK ROM | 0800:0000h | - | - |
Cart RAM | 0e00:0000h | - | - |
別名BIOSと言われていて、CPUの00h~2Ahまでのシステムコールで呼び出します。任天堂さんが用意してくれた自前の関数群だと思ってください。除算やLZ77圧縮された画像データを解凍する関数などは使用頻度が高いです。電源ONした時に一番最初に表示されるタイトルロゴやコードもこのプログラム内に含まれます。
External work RAMの略でゲーム上で使用される画像やコードを置いたりします。もしカードリッジを挿さない状態でマルチブートケーブルを使用した場合、転送されたデータはEWRAM領域に配置されます。
GBAの中でもっとも高速な領域です。スピードを求められる処理はIWRAMに置くことをお奨めします。ただし大きさが32kbしかないため、何を置くか慎重に選ぶ必要があります。
GBAのグラフィックやサウンド、ボタンなどをコントロールしています。アクセス方法は変数を読む込んだり、書き込んだりする方法と同じです。ヘッダファイルにメモリの位置をdefineしてアクセスします。
#define REG_BASE 0x04000000 #define REG_KEYINPUT *(vu16*)(REG_BASE + 0x130) // Key Input #define REG_KEYCNT *(vu16*)(REG_BASE + 0x132) // Key Control
BG(画面)とスプライトのパレットを設定する領域です。
このメモリ領域は画面と反映像になっています。数字を書き換えることで画面が即座に変化します。画面更新の期間(垂直帰線期間)を無視して書き換えを行った場合、 画面がチラついてしまうので注意が必要です。
スプライトの設定をする領域です。
カードリッジの領域です。
ゲームのセーブデータ等に使用されます。Cart RAMには様々な種類があってSRAM、EEPROM、Flash ROMなどがあります。自作ゲーム開発では簡単に実装できるSRAMが人気のようです。
以下にGBATEKの抜粋を記載します。
Address Bus Width and CPU Read/Write Access Widths Shows the Bus-Width, supported read and write widths, and the clock cycles for 8/16/32bit accesses. Region Bus Read Write Cycles BIOS ROM 32 8/16/32 - 1/1/1 Work RAM 32K 32 8/16/32 8/16/32 1/1/1 I/O 32 8/16/32 8/16/32 1/1/1 OAM 32 8/16/32 16/32 1/1/1 * Work RAM 256K 16 8/16/32 8/16/32 3/3/6 ** Palette RAM 16 8/16/32 16/32 1/1/2 * VRAM 16 8/16/32 16/32 1/1/2 * GamePak ROM 16 8/16/32 - 5/5/8 **/*** GamePak Flash 16 8/16/32 16/32 5/5/8 **/*** GamePak SRAM 8 8 8 5 ** Timing Notes: * Plus 1 cycle if GBA accesses video memory at the same time. ** Default waitstate settings, see System Control chapter. *** Separate timings for sequential, and non-sequential accesses. One cycle equals approx. 59.59ns (ie. 16.78MHz clock). All memory (except GamePak SRAM) can be accessed by 16bit and 32bit DMA.
表のRead, Writeは、そのメモリにアクセスできるビット単位を表しています。よくみるとVRAMは8bit単位で読めるが、8bit単位で書き込めないことがわかります。これはハードウェアの制約なので十分注意してプログラミングしなくてはなりません。エミュレータで動くが実機で動かない、というよくあるハマりポイントの1つです。また、CyclesはIWRAMが1/1/1に対して、GamePak ROMは5/5/8なのでアクセススピードだけでも5倍違うということが分かります。忘れずに覚えておいてください。
自分の書いたコードを指定したメモリ位置に置くにはマクロを使います。使い方は次のとおりです。
#define IWRAM_CODE __attribute__((section(".iwram"), long_call)) #define EWRAM_CODE __attribute__((section(".ewram"), long_call)) #define IWRAM_DATA __attribute__((section(".iwram"))) #define EWRAM_DATA __attribute__((section(".ewram"))) #define EWRAM_BSS __attribute__((section(".sbss"))) #define ROM_DATA __attribute__((section(".roda")))
// IWRAM領域 IWRAM_CODE void SpriteInit() { // }
// EWRAM領域 EWRAM_CODE void SpriteInit() { // }
// ROM領域(指定なし) void SpriteInit() { // }
ヘッダファイル(.h)内のプロトタイプ宣言にも同じように指定することを忘れないでください。一方、変数の定義は次のように指定することができます。指定なしの場合、IWRAMになるので注意してください。
u32 test1 EWRAM_BSS; // EWRAM領域 u32 test2 IWRAM_DATA; // IWRAM領域 u32 test3; // IWRAM領域(指定なし)
ファイルは「C:\devkitPro\libgba\include\gba_base.h」(github)内で定義されています。正しくメモリ上に置かれているか確認する方法については、コンパイル後に生成されるマップファイル(.map)で確認可能です。