前回のメモリエリアについてはカードリッジ以外のメモリ(IWRAM, EWRAM, PAK ROM)にコードや変数を置く方法を説明をしました。ところが電源を入れたとき、すべてのデータはROM領域(カードリッジ)にあります。その時点からいったいどうやってIWRAMやEWRAMに配置されていくのか、その流れを見ていきましょう。先に答えを言っておきますとROM領域にアクセスされた時「C:\devkitPro\devkitARM\arm-none-eabi\lib\gba_crt0.ld」(github)がまず一番最初に実行されます。よかったら平行して読んでみてください。
実機のGBAにカードリッジを挿し電源をONにすると、そのカードリッジ内容はメモリの0x08000000からアクセスできるようになります。つまり.gbaファイルとは、その内容をファイル化しただけのものです。もちろんカードリッジはROM(リードオンリーメモリ)なので書き換え不可。あと大昔ということもあってデータは暗号化もされていませんでした。いい時代やったなあ・・・。
GBA上だと0x08000000~0x080000bf、.gbaファイル上だと0x00~0xbfまでの192(0xc0)サイズ分をヘッダと呼びます。内容は特に気にすることはないので素通りしましょう。一応次のような意味を持っています。
0x00 - 0x03 | 32 bit ARM B Jump to start of ROM executable |
0x04 - 0x9F | Nintendo Logo data |
0xA0 - 0xAB | Game Title |
0xAC - 0xAF | Game Code |
0xB0 - 0xB1 | Maker Code |
0xB2 - 0xB2 | 0x96 Fixed |
0xB3 - 0xB3 | Main Unit Code |
0xB4 - 0xB4 | Device Type |
0xB5 - 0xBB | Reserved Area |
0xBC - 0xBC | Mask ROM Version |
0xBD - 0xBD | Compliment Check |
0xBE - 0xBF | Reserved Area |
エミュレータで見るとこのようになります。(Tools -> Memory viewer)
main関数が実行されるまでの流れは以下のとおりです。
エミュレータで逆アセンブルするとこんな表示になります。
@--------------------------------------------------------------------------------- start_vector: @--------------------------------------------------------------------------------- mov r0, #0x4000000 @ REG_BASE str r0, [r0, #0x208] mov r0, #0x12 @ Switch to IRQ Mode msr cpsr, r0 ldr sp, =__sp_irq @ Set IRQ stack mov r0, #0x1f @ Switch to System Mode msr cpsr, r0 ldr sp, =__sp_usr @ Set user stack
自作ゲームを作って実機を動かそうとしたらタイトルロゴで止まる。でもエミュレータ上では動く。こんなことがあった時はカードリッジのチェックサムを疑ってみてください。devkitProにはgbafixと呼ばれるチェックサム計算ツールがあります。実機前には忘れずにツールを通してからにしてください。
マルチブートとはカードリッジを使わずに通信ケーブル(ブートケーブル)などで起動をする仕組みです。実機を2台持っていて対戦をしたい場合を想像するとわかりやすいと思います。一方はマリオカートのカードリッジを装着していて、一方はない状態で通信ケーブルのみで繋がっている。ホスト側からゲスト側にデータを転送します。この仕組みをマルチブートと呼びます。
devkitProではカードリッジなし状態を想定したマルチブートロムの制作は可能です。VBA-1.8.0-beta3ではファイル名で区別しており、xxx.gbaでしたらxxx.mb.gbaまたはxxx.mbです。インターネットでダウンロードしてきた自作ゲームがフリーズする場合、そもそもIWRAM, EWRAM領域にのみ展開されることを想定して作られているわけでそりゃフリーズしますよね、という話です。