GBAのSystem ROM(BIOS)には、あらかじめ用意されているいくつかの機能があります。具体的には次のようなものです。
BIOS Function Summary SWI Hex Function 0 00h SoftReset 1 01h RegisterRamReset 2 02h Halt 3 03h Stop 4 04h IntrWait 5 05h VBlankIntrWait 6 06h Div 7 07h DivArm 8 08h Sqrt 9 09h ArcTan 10 0Ah ArcTan2 11 0Bh CpuSet 12 0Ch CpuFastSet 13 0Dh -Undoc- ("GetBiosChecksum") 14 0Eh BgAffineSet 15 0Fh ObjAffineSet 16 10h BitUnPack 17 11h LZ77UnCompWram 18 12h LZ77UnCompVram 19 13h HuffUnComp 20 14h RLUnCompWram 21 15h RLUnCompVram 22 16h Diff8bitUnFilterWram 23 17h Diff8bitUnFilterVram 24 18h Diff16bitUnFilter 25 19h SoundBias 26 1Ah SoundDriverInit 27 1Bh SoundDriverMode 28 1Ch SoundDriverMain 29 1Dh SoundDriverVSync 30 1Eh SoundChannelClear 31 1Fh MidiKey2Freq 32-36 20h-24h -Undoc- (Sound Related ???) 37 25h MultiBoot 38 26h -Undoc- ("HardReset") 39 27h -Undoc- ("CustomHalt") 40 28h SoundDriverVSyncOff 41 29h SoundDriverVSyncOn 42 2Ah -Undoc- ("GetJumpList" for Sound ???) 43-255 2Bh-FFh -Not used- The BIOS SWI handler does not perform any range checks, so calling SWI 43-255 will blindly lock up the GBA.
この機能群はC言語でいうところの関数の集まりと思ってください。呼び出し方法が少し特殊で、CPUのSWI命令と機能番号を使います。GBATEKの忠告どおり、SWI 43-255はコールしないでください。壊れると思って構いません。
使用例として機能番号18(12h)のLZ77UnCompVramを使います。この機能はLZ77圧縮された画像ファイルを解凍しつつ、指定されたメモリ領域に展開する機能です。LZ77のアルゴリズムについてはgoogle先生に聞いてみてください。
作業の順番としては
となります。
ここではdevkitProに標準で用意されているgritを使用します。コマンドのオプションに-gzlを付け加えることでLZ77圧縮の指定になります。ちなみにGBAでデータを圧縮して使いたい場合は、脳死でこのフォーマットを選んで構いません。
無圧縮 | 76800バイト | 100% |
LZ77 | 16968バイト | 22% |
仕様についてはGBATEKより抜粋してきたものを以下に表します。
SWI 17 (11h) - LZ77UnCompWram SWI 18 (12h) - LZ77UnCompVram Expands LZ77-compressed data. The Wram function is faster, and writes in units of 8bits. For the Vram function the destination must be halfword aligned, data is written in units of 16bits. If the size of the compressed data is not a multiple of 4, please adjust it as much as possible by padding with 0. Align the source address to a 4-Byte boundary. r0 Source address, pointing to data as such: Data header (32bit) Bit 0-3 Reserved Bit 4-7 Compressed type (must be 1 for LZ77) Bit 8-31 Size of decompressed data Repeat below. Each Flag Byte followed by eight Blocks. Flag data (8bit) Bit 0-7 Type Flags for next 8 Blocks, MSB first Block Type 0 - Uncompressed - Copy 1 Byte from Source to Dest Bit 0-7 One data byte to be copied to dest Block Type 1 - Compressed - Copy N+3 Bytes from Dest-Disp-1 to Dest Bit 0-3 Disp MSBs Bit 4-7 Number of bytes to copy (minus 3) Bit 8-15 Disp LSBs r1 Destination address Return: No return value.
引数には転送元のアドレス(r0)と転送先のアドレス(r1)の値が必要なのがわかりました。早速、コードを載せていきましょう。libgbaと同じものを使用しました。
#if defined ( __thumb__ ) #define SystemCall(Number) __asm ("SWI "#Number"\n" ::: "r0", "r1", "r2", "r3") #else #define SystemCall(Number) __asm ("SWI "#Number" << 16\n" :::"r0", "r1", "r2", "r3") #endif
IWRAM_CODE void LZ77UnCompVram(void *source, void *dest) { SystemCall(18); }
#include "lib/gba.h" #include "res.h" //--------------------------------------------------------------------------- void WaitForVsync(void) { while (*(volatile u16*)0x4000006 >= 160) {}; while (*(volatile u16*)0x4000006 < 160) {}; } //--------------------------------------------------------------------------- int main(void) { SetMode(MODE_3 | BG2_ENABLE); LZ77UnCompVram((void*)&imageBitmap, (void*)VRAM); for(;;) { WaitForVsync(); } }