AGBについて個人的にまとめたものです。内容には間違いが含まれている場合があります。
CPU
ARM7TDMI
- ARMv4Tアーキテクチャ
- 32ビットのRISC CPU
- 16.78MHz = 約59.59ns/clks
- 16つのレジスタを持つ
- 6つのプロセッサモードを持つ
- 2つのCPU状態を持つ
- フェッチ、デコード、実行の3段のパイプラインを持つ
レジスタ
- r0,…,r12:汎用用途のレジスタ
- r13(SR):スタックポインタ。プロセッサモードに応じて既定値が異なる
- USR:03007F00h
- IRQ:03007FA0h
- SVC:03007FE0h
- r14(LR):リンクレジスタ。
BL命令によって次の命令へのアドレスが格納される
- r15(PC):プログラムカウンタ。CPUが3段のパイプラインを持つので、
PCは2命令分だけ常に先行している
- CPSR:現在のプログラムの実行状態を持つレジスタ
- 0-4ビット目:プロセッサモード
- 5ビット目:Thumbモードで動作しているか
- 6ビット目:FIQが無効化されているか
- 7ビット目:IRQが無効化されているか
- 8-27ビット目:予約済み
- 28ビット目:オーバーフロー
- 29ビット目:キャリー
- 30ビット目:ゼロ
- 31ビット目:負
- SPSR:各プロセッサモードのCPSRを保持するレジスタ
プロセッサモード
- USR(ユーザー):プログラムを実行するための通常のモード
- SYS(システム):OSのための特権ユーザーモード。AGBでは使われない
- IRQ(割り込み):通常の割り込みを処理するモード
- FIQ(高速割り込み):高速で低レイテンシな高速割り込みを処理するモード。AGBでは使われない
- SVC(スーパーバイザーコール):OSのリソースにアクセスするためのモード。AGBではSWI命令を介してBIOSを呼び出すために使われる
- ABT(アボート):メモリアクセスが正常に完了できなかったときに入る
- UND(未定義):定義されていない命令が実行されたときに入る
CPU状態
- 32ビット長の命令を実行するARM state
- ✔ 1命令でできることが多い
- ✔ すべてのレジスタが使える
- ❌️ コードサイズが大きくなる
- 16ビット長の命令を実行するThumb state
- ✔ コードサイズが小さくなる
- ❌️ 1命令でできることが少ない
- ❌️ すべてのレジスタが使えない
メモリ
- メモリの読み書きは固定で1クロックかかり、追加でメモリの特性に応じた待ち時間がかかる
- 16ビット幅のメモリは32ビットの読み書き1回を16ビットの読み書き2回で行う
- プログラムの格納場所は命令長とバス幅を合わせると最適なパフォーマンスを得られる
- 1命令を1回のメモリアクセスで読み出せるようになるため
- リトルエンディアンのみをサポートする
- ディスプレイコントローラとCPUのメモリアクセスがかち合ったとき、CPUの方に待ち時間を挿入する
- 各メモリは0#000000hから0#FFFFFFhまで有効な領域がミラーリングされる
- 例えば、IWRAMは03FF8000hから03FFFFFFhまででもアクセスできる
System ROM
- 00000000h-00003FFFh(16KB)
- 16ビット幅
- BIOSが格納される
- 読み書き不可、実行可
EWRAM(External Work RAM)
- 02000000h-0203FFFF(256KB)
- 16ビット幅
- 低速なオンボードメモリ
- プログラムやデータを格納する
- マルチブート時、ダウンロードしたプログラムが格納される
IWRAM(Internal Work RAM)
- 03000000h-03007FFF(32KB)
- 32ビット幅
- 高速なオンチップメモリ
- プログラムやデータを格納する
IO RAM
- 04000000-040003FF(1KB)
- 32ビット幅
- 各種機能を制御するメモリマップドなIOレジスタ
Palette RAM
- 05000000h-050003FF(1KB)
- 05000000h-050001FFhをBGで使う
- 05000200h-050003FFhをOBJで使う
- 16ビット幅
- 16ビットの色情報を格納する配列として扱う
- 8ビット書き込み不可
VRAM
- 06000000h-06017FFFh(96KB)
- 16ビット幅
- ビデオモードに応じてレイアウトが異なる
- ビットマップのモードでは色情報または色番号を格納する
- タイルベースのモードでは各BGのタイル情報とマップ情報を格納する
- 8ビット書き込み不可
OAM(Object Attribute Memory)
- 07000000h-070003FF(1KB)
- 32ビット幅
- OBJの制御情報を格納する
- 8ビット書き込み不可
GamePak ROM
- 08000000h-09FFFFFFh(最大32MB)
- 16ビット幅
- ゲームデータが格納される
WAITCNTの2-3ビット目の値に従って初回のアクセスに待ち時間が挿入される
WAITCNTの4ビット目の値に従って後続の連続アクセスに待ち時間が挿入される
- 書き込み不可
- 通常はこちらが使われる
GamePak ROM
- 0A000000h-0BFFFFFFh(最大32MB)
- 16ビット幅
- ゲームデータが格納される
WAITCNTの5-6ビット目の値に従って初回のアクセスに待ち時間が挿入される
WAITCNTの7ビット目の値に従って後続の連続アクセスに待ち時間が挿入される
- 書き込み不可
GamePak ROM
- 0C000000h-0DFFFFFFh(最大32MB)
- 16ビット幅
- ゲームデータが格納される
WAITCNTの8-9ビット目の値に従って初回のアクセスに待ち時間が挿入される
WAITCNTの10ビット目の値に従って後続の連続アクセスに待ち時間が挿入される
- 書き込み不可
GamePak RAM
- 0E000000h-0E00FFFFh(最大64KB)
- 8ビット幅
- セーブデータを格納する
WAITCNTの0-1ビット目の値に従ってアクセスに待ち時間が挿入される
- 8ビットの読み書き可
ディスプレイ
- 240x160ピクセル
- フレームあたり280896サイクル = 約59.73Hz
- HDraw中はディスプレイコントローラがVRAM、OAM、Palette RAMを使っている
- 基本的にVRAM、OAM、Palette RAMの書き換えはHBlank中かVBlank中に行う
タイミング
- HDraw:1行分を更新するのにかかる時間
- HBlank:1行を更新し終わってから次の行の更新が始まるまでの空き時間
- スキャンライン:HDraw + HBlank = 1232サイクル
- VDraw:1画面分を更新するのにかかる時間
- 197120サイクル(160スキャンライン分)かかる
- VBlank:1画面を更新し終わってから次の画面の更新が始まるまでの空き時間
色フォーマット
- 色情報は16ビットで、RGB各5ビットずつ、計32768色を表現できる
- 0-4:赤
- 5-9:緑
- 10-14:青
- 15:未使用
struct Color {
uint16_t red : 5;
uint16_t green : 5;
uint16_t blue : 5;
uint16_t _unused : 1;
};
パレット
- パレットとはPalette RAMに格納された色情報の集合を指す
- Palette RAMはBGとOBJそれぞれに対して256色の色情報を格納できる
- 16色モードでは16色を持つ16つのパレットとしてデータを解釈する
- 256色モードでは256色を持つ1つのパレットとしてデータを解釈する
// 256色モードのパレット
struct Palette256 {
Color colors[256];
};
// 16色モードのパレット
struct Subpalette {
Color colors[16];
};
struct Palette16 {
Subpalette subpalettes[16];
};
固定小数点数
struct fixed28_t {
uint32_t fraction : 8; // 小数点以下の値
uint32_t integer : 19; // 整数部分の値
uint32_t sign : 1; // 符号
};
struct fixed16_t {
uint16_t fraction : 8; // 小数点以下の値
uint16_t integer : 7; // 整数部分の値
uint16_t sign : 1; // 符号
};
struct fixed32_t {
uint32_t fraction : 8; // 小数点以下の値
uint32_t integer : 23; // 整数部分の値
uint32_t sign : 1; // 符号
};
背景
ビデオモード
DISPCNTの0-2ビット目でビデオモードを指定する
- 0, 1, 2 => タイルベース方式
- 3, 4, 5 => はビットマップ方式
タイルベース
- タイル単位で管理する
- VRAMの先頭64KBを使う
- タイル情報へのオフセットは16KB単位で
BG#CNTの2-3ビット目に指定する
- マップ情報へのオフセットは2KB単位で
BG#CNTの8-12ビット目に指定する
| モード | レイヤ | タイル数 | 色 | 備考 |
|---|
| 0 | 0,1,2,3 | 1024 | 16,256 | スクロールできる |
| 1 | - | - | - | BG0とBG1をモード0として、BG2をモード2として表示する |
| 2 | 2,3 | 256 | 256 | アフィン変換できる |
タイル
- 8x8ピクセルを1タイルとする
- ピクセルあたりに1つの色番号を指定する
BG#CNTの7ビット目によってレイアウトが異なる
- 16色モードの場合
- 4ビットのパレット番号をマップ情報として指定する
- 4ビットの色番号をタイル情報として指定する
- 256色モードの場合
マップ
- モードによってレイアウトが異なる
- モード0の場合
- エントリあたり2バイトの情報を用意する
- 0-9:タイル番号(0から1023まで)
- 10:水平方向に鏡写しにするか
- 11:垂直方向に鏡写しにするか
- 12-15:パレット番号
- マップサイズは
BG#CNTの14-15ビット目の値に従う
- 0 => 32x32タイル(2KB)
- 1 => 64x32タイル(4KB)
- 2 => 32x64タイル(4KB)
- 3 => 64x64タイル(8KB)
- モード2の場合
- エントリあたり1バイトの情報を用意する
- マップサイズは
BG#CNTの14-15ビット目の値に従う
- 0 => 16x16タイル(256B)
- 1 => 32x32タイル(1KB)
- 2 => 64x64タイル(4KB)
- 3 => 128x128タイル(16KB)
ビットマップ
- ピクセル単位で管理する
- VRAMの先頭80KBを使う
- BG2のみ有効
- アフィン変換できる
- 表示に使うページは
DISPCNTの4ビット目で指定する
| モード | ピクセルサイズ | ページ数 | 色 |
|---|
| 3 | 240x160 | 1 | 32768 |
| 4 | 240x160 | 2 | 256 |
| 5 | 160x128 | 2 | 32768 |
スクロール
- モード0のBGに対して適用される
- 左上を(0, 0)として、
BG#HOFSとBG#VOFSの値だけ表示位置がオフセットされる
アフィン変換
- モード2,3,4,5のBG2,3に対して適用される
BG#XおよびBG#Yは平行移動成分を指定する
- 28ビットの符号付き固定小数点数で表現される
- 0-7:小数点以下
- 8-26:整数部
- 27:符号
- 28-31:未使用
BG#PA、BG#PB、BG#PC、BG#PDは変換行列の各成分を指定する
- 16ビットの符号付き固定小数点数で表現される
- 0-7:小数点以下
- 8-14:整数部分
- 15:符号
変換処理の詳細
- コピー先座標はスキャンラインごとに各ピクセルの位置が計算される
- 対応するコピー元座標は変換行列の各成分に従って以下のように計算される
BG#XとBG#Yを初期値とする
BG#PBとBG#PDをスキャンラインごとの変化量として、コピー元座標の始点を計算する
BG#PAとBG#PCをピクセルごとの変化量として、ピクセルの位置を計算する
const int SCREEN_WIDTH = 240;
const int SCREEN_HEIGHT = 160;
for (int dst_y = 0; dst_y < SCREEN_HEIGHT; dst_y++) {
int src_x = BG2X, src_y = BG2Y;
for (int dst_x = 0; dst_x < SCREEN_WIDTH; dst_x++) {
draw(src_x, src_y, dst_x, dst_y);
src_x += BG2PA;
src_y += BG2PC;
}
BG2X += BG2PB;
BG2Y += BG2PD;
}
BG#XとBG#Yはコピー元座標の始点位置を保持している(ように見える)
- 実際には確認できないので、そのように解釈できるというだけの話
BG#XとBG#YをHBlank中に書き換えると、それまでに累積した変位がリセットされる
まとめると
- この変換処理はコピー元の視点を変化させると考えるのが分かりやすい
BG#XとBG#Yによって平行移動した後、行列で変形する
- その座標系から、1行240ピクセルを160行分だけディスプレイに表示する
- 計算途中に介入できる手段があるという点で単なるアフィン変換とは異なる
- その状態は
BG#XとBG#Yに保管されていると見て良い
オブジェクト
- 各OBJは最大64x64ピクセルの大きさを取れる
- 最大128つを一度に表示できる
- 32つの変換行列を格納できる
属性
- エントリあたり8バイトの情報を用意する
- 7-8バイト目は変換行列の成分を順々に配置する
- 例えば0番目の行列は07000006hにPA、0700000EhにPA、07000016hにPC、0700001EhにPDを格納する
struct ObjectAttribute {
// attribute 0
struct {
uint16_t y : 8; // Y座標
uint16_t enable_transformation : 1; // 変換するか
uint16_t enable_double_size : 1; // サイズを2倍にするか
uint16_t mode : 2; // 0:通常、1:半透明、2:ウィンドウ
uint16_t enable_mosaic : 1; // モザイクを有効化するか
uint16_t palette_mode : 1; // 0:16色、1:256色
uint16_t shape : 2; // 0:正方、1:横長、2:縦長
};
// attribute 1
union {
// 変換ありの場合
struct {
uint16_t x : 9; // X座標
uint16_t transformation_matrix_index : 5; // 変換行列のインデックス
uint16_t size : 2; // shape = 0のとき、0:8x8、1:16x16、2:32x32、3:64x64
// shape = 1のとき、0:16x8、1:32x8、2:32x16、3:64x32
// shape = 2のとき、0:8x16、1:8x32、2:16x32、3:32x64
};
// 変換なしの場合
struct {
uint16_t x : 9; // X座標
uint16_t _unused_29 : 3;
uint16_t enable_horizontal_flip : 1; // 水平方向に鏡写しにするか
uint16_t enable_vertical_flip : 1; // 垂直方向に鏡写しにするか
uint16_t size : 2; // shape = 0のとき、0:8x8、1:16x16、2:32x32、3:64x64
// shape = 1のとき、0:16x8、1:32x8、2:32x16、3:64x32
// shape = 2のとき、0:8x16、1:8x32、2:16x32、3:32x64
};
};
// attribute 2
uint16_t tile_offset : 10; // 06010000hからタイルへの32B単位のオフセット
// => 256色モードでは必ず偶数になる
// ビットマップモードでは512から1023までの範囲になる
uint16_t priority : 2; // 0を最前面とする優先度
uint16_t palette_index : 4; // 16色モードの場合のパレット番号
// attribute 3
uint16_t transformation_matrix_element; // 変換行列の成分
};
union TransformationMatrix {
ObjectAttribute attributes[4];
struct {
uint16_t _attributes_pa[3];
fixed16_t pa;
uint16_t _attributes_pb[3];
fixed16_t pb;
uint16_t _attributes_pc[3];
fixed16_t pc;
uint16_t _attributes_pd[3];
fixed16_t pd;
};
};
タイル
- 8x8ピクセルを1タイルとする
- OBJに割り当てられるVRAM領域はビデオモードによって異なる
- モード0,1,2では32KB
- モード3,4,5では16KB
- 加えて、扱う色数によって格納できるタイル数が決まる
- モード3と256色モードで256タイルを格納できる
- モード0と16色モードで1024タイルを格納できる
// 16色モードでのタイル
union ObjectTile16Row {
uint32_t combined_pixels;
struct {
uint32_t _0 : 4;
uint32_t _1 : 4;
uint32_t _2 : 4;
uint32_t _3 : 4;
uint32_t _4 : 4;
uint32_t _5 : 4;
uint32_t _6 : 4;
uint32_t _7 : 4;
};
};
struct ObjectTile16 {
ObjectTile16Row rows[8];
};
// 256色モードでのタイル
struct ObjectTile256Row {
uint8_t pixels[8];
};
struct ObjectTile256 {
ObjectTile256Row rows[8];
};
マッピング
- OBJサイズが8x8より大きい時、後続のタイルのオフセットを自動で計算する
- 列単位で見ると、線形に(16色モードなら1ずつ、256色モードなら2ずつ)増加する
- 行単位で見ると、マッピング方式によって異なる
- マッピング方式は
DISPCNTの6ビット目で指定する
- 2Dマッピング:各行ごとに32ずつ増加する
- 1Dマッピング:各行ごとに1ずつ増加する
例:16色モード、4x4タイル(32x32ピクセル)の場合
2Dマッピング:
| | | |
|---|
| 0 | 1 | 2 | 3 |
| 32 | 33 | 34 | 35 |
| 64 | 65 | 66 | 67 |
| 96 | 97 | 98 | 99 |
1Dマッピング:
効果
ウィンドウ
- ウィンドウの内側または外側に表示するBGおよびOBJを制御できる
モザイク
- 水平または垂直方向にピクセルを伝播させる機能を持つ
- 左端または上端の色を何ピクセル先まで伝播させるかを制御できる
ブレンディング
- アルファブレンディング、フェードイン、フェードアウトを行う機能を持つ
- BGまたはOBJのうち、最前面であるものを第1ターゲットとし、それより後ろにある最も近いものを第2ターゲットとする
アルファブレンディング
BLDCNTの6-7ビット目が1の場合
BLDALPHAの0-4ビット目の値()に従って第1ターゲットに係数をかけて、BLDALPHAの8-12ビット目の値()に従って第2ターゲットに係数をかけて、足し合わせる
- ターゲットが2つ揃わない場合、ブレンディングは行われない
フェードイン・フェードアウト
BLDYの0-4ビット目の値()に従って第1ターゲットに係数を掛け合わせる
BLDCNTの6-7ビット目が2の場合:
BLDCNTの6-7ビット目が3の場合:
割り込み
- 割り込みを有効化するには3段階の有効無効ビットをセットする必要がある
- CPUの割り込み機能を無効化するにはCPSRの7ビット目を1にする
IMEの0ビット目に割り込み処理全体の有効無効を指定する
- 各種割り込みの有効無効は
IEと各レジスタで指定する
- VBlank
- HBlank
- VCountの一致:処理するスキャンラインの行数が
DISPSTATの8-15ビット目の値と一致するとき
- Timer 0
- Timer 1
- Timer 2
- Timer 3
- シリアル通信の完了
- DMA 0
IEの8ビット目
DMA0CNT_Hの14ビット目
- DMA 1
IEの9ビット目
DMA1CNT_Hの14ビット目
- DMA 2
IEの10ビット目
DMA2CNT_Hの14ビット目
- DMA 3
IEの11ビット目
DMA3CNT_Hの14ビット目
- Keypad
IEの12ビット目
KEYCNTの14ビット目にを指定する
- GamePak(RTCやカードリーダなど)
IEの13ビット目
- GamePakが指定するビット
割り込み処理
- システムの割り込みハンドラのアドレスは03FFFFFChに格納する
- 発生した割り込みの種類は
IFの各ビットから確認できる
割り込みへの応答
- プログラムは割り込みを処理したことを伝える必要がある
- ハードウェアに伝えるには、当該ビットを立てて
IFに書き込む
- そのビットは後にクリアされる
- BIOSに伝えるには、3007FF8hにある割り込み確認フラグの当該ビットを立てる
- 割り込みハンドラからリターンした後にクリアされる
ユーザーハンドラの呼び出し
- 呼び出された時点でのレジスタ状態を保存しておく
- r0、r1、r2、r3、r12、LR、SPSR
- リターンする前に復元する
- ハンドラの実行はシステムモードで行う
- モード切り替えと一緒にIRQ割り込みを無効化する
- ハンドラを呼び出す前にユーザーモードのLRをスタックに避難させる
- 制御が戻った後はIRQモードに戻してリターンする
DMA
- 4つのDMAチャネルを持つ
- 0が最も優先度が高い
- 優先度が高いものから処理される
- その他のチャネルは実行中のチャネルが完了するまで一時停止する
- DMAコントローラとCPUはメモリバスを取り合うので排他的である
レジスタ
DMA#SADはコピー元のアドレスを入れる
DMA#DADはコピー先のアドレスを入れる
DMA#CNT_Lはワードの個数を入れる
- ワードの大きさは
DMA#CNT_Hの10ビット目に16ビットか32ビットかを指定する
内部状態
- 実際の転送処理はレジスタとは別の内部状態を持つ
DMA#SAD、DMA#DAD、DMA#CNT_Lは初期値として用いる
DMA#CNT_Hの15ビット目を0から1に書き換えると内部状態を初期化する
- リピートしない設定の場合、転送が完了するとDMAは自動的に無効化される
- リピートする設定の場合、転送が完了してもDMAは有効化されたまま
想定される使用用途
- DMA0:HBlank中のデータ転送
- HBlank中に制御情報を書き換えることでより柔軟な表現が可能になる
- ラスタースクロール
- スキャンラインごとにスクロール位置を変える
- より高度なモード7表示
- 途中でビデオモードを切り替える
- 任意形状のウィンドウ
- DMA1,2:サウンドのストリーミング
- サウンドコントローラと協調動作する特別モードがある
- DMA3:GamePak ROMのデータ転送
- 唯一、ワードの個数を16ビットまで取れる(最大64KBを転送できる)
タイマー
- タイマー0とタイマー1はサウンドのストリーミングを制御するのに使われる
TM#CNT_Lはカウンタの値を読み書きできる
- 読み込む場合、現在のカウンタの値が返る
- 書き込む場合、リロードで使われる初期値を設定できる
- タイマーがオーバーフローしたり再開したりすると反映される
TM#CNT_Hの2ビット目を1にすると、1つ前のタイマーがオーバーフローしたときにカウントアップするようになる
サウンド
- 内部処理はステレオ
SOUNDCNT_Lでマスタ音量やチャネル1-4の制御を行う
SOUNDCNT_HでチャネルA,Bの制御を行う
SOUNDBIASで最終出力を調整する
- 最終的なサンプリングレートが32.768kHzとなるよう調整する
チャネル1:矩形波
SOUND1CNT_L、SOUND1CNT_H、SOUND1CNT_Xで制御する
- Hzを基本として秒だけ鳴らす
X[14]が1であれば、再生時間を超過するときにマスタレジスタをクリアする
スイープ
- 周波数を段々と大きく/小さくする機能
- ミリ秒の間隔で周期を倍する
L[3]で増減の符号を指定する
- 周波数が0または最大値に達すると増減が止まる
エンベロープ
- 音量をフェードイン/アウトさせる機能
- 秒の間隔で音量を増減する
H[11]で増減の符号を指定する
H[12:15]で音量の初期値を指定する
- 書き込んだ時には反映されず、リセット時に反映される
- 音量が0または最大値に達すると増減が止まる
デューティー比
- 矩形波が”オン”(ハイレベル)になっている時間割合を指定する機能
H[6:7]の値で指定する
- 0 => 12.5%
- 1 => 25%
- 2 => 50%
- 3 => 75%
チャネル2:矩形波
- スイープできない以外はチャネル1と同じ
SOUND2CNT_LはSOUND1CNT_Hと同様のレイアウトを取る
SOUND2CNT_HはSOUND1CNT_Xと同様のレイアウトを取る
チャネル3:波形メモリ
- Hzのサンプルレートで秒だけ再生する
- 32サンプルの2バンクモードと64サンプルの1バンクモードがある
- サンプルあたり4ビットの波形データを16バイトの
WAVE_RAMに書き込む
- 音量は
H[13:15]の値に従って指定する
- 0 => 0%
- 1 => 100%
- 2 => 50%
- 3 => 25%
チャネル4:ノイズ
- 7段または15段の線形帰還シフトレジスタ(Linear Feedback Shift Register; LFSR)
- Hzで秒だけ再生する
- ただし、
H[0:2]が0のときは代わりにとして計算する
- エンベロープは秒の間隔で増減する
H[14]を立てると、L[0:5]の分だけ再生した後に自動で停止する
- 再生中にレジスタを書き換えても大丈夫
- エンベロープの初期音量(
H[12:15])や周波数の分割数(H[0:2])などを反映するにはH[15]を立てて初期化する必要がある
チャネルA,B:PCM
- サンプルあたり8ビットの音声データを
FIFOに書き込む
- 一度に4サンプルずつを計32サンプルを書き込むことができる
- タイマー割り込みかDMAを使ってサウンドエンジンのサンプル消費に合わせて書き込む
- 基本的にはDMA1,2を使ってサンプルを書き込む
- シリアル通信と併用したいときはタイマー割り込みで処理する
BIOS
- BIOSにはシステムコールによって呼び出される関数が定義されている
0xNN番の関数を呼び出す場合
- ARMステートでは
swi 0xNN0000
- Thumbステートでは
swi 0xNN
- 引数の受け渡しには
r0、r1、r2、r3を使う
- 結果の受け渡しには
r0、r1、r3を使う
r2、r4からr14は関数の実行によって変化しない
00h - SoftReset
- ソフトリセット
- AGBをリセットして80000000hから実行し直す?
01h - RegisterRamReset
- 指定したメモリやレジスタをクリアする
- 引数:
- r0:フラグ
- 0:EWRAM
- 1:IWRAM(末尾512Bを除く)
- 2:Palette RAM
- 3:VRAM
- 4:OAM
- 5:SIOレジスタ
- 6:サウンドレジスタ
- 7:その他すべてのレジスタ
03h - Stop
- ハードウェアの大部分を割り込みが発生するまで停止させる
- CPU、クロック、サウンド、ビデオ、SIOのシフトクロック、DMA、タイマーは停止する
- キーパッド、GamePak、汎用用途SIOは生きている
- “システムクロックが止まっているのでIFフラグはセットされない”
04h - IntrWait
- 指定の割り込みが発生するまでCPUを停止させる
- 発生した割り込みに応答するとき、3007FF8hの当該ビットを立てる
- 引数:
- r0:開始時に確認用フラグをクリアするか
- r1:待機する割り込みの種別フラグ(
IEやIFと同じレイアウト)
05h - VBlankIntrWait
- VBlank割り込みが発生するまでCPUを停止させる
r0 = 1とr1 = 1でswi 0x04を実行するのと同じ
06h - Div
- 整数の除算を計算する
- ゼロ除算は無限ループを引き起こす
- 引数:
- r0:分子(符号あり32ビット整数)
- r1:分母(符号あり32ビット整数)
- 戻り値:
- r0:商(符号あり32ビット整数)
- r2:剰余(符号あり32ビット整数)
- r3:商の絶対値(符号なし32ビット整数)
07h - DivArm
- 引数の順序が入れ替わっているDiv
- Divより若干(3クロック)遅い
08h - Sqrt
- 整数の平方根を計算する
- 引数:
- 戻り値:
- r0:(符号なし16ビット整数)
09h - ArcTan
- アークタンジェントを計算する
- の範囲で有効
- 引数:
- 戻り値:
- r0:ラジアン角(符号あり16ビット整数)
- がにマッピングされる
0Ah - ArcTan2
- を計算する
- 引数:
- (符号あり32ビット整数)
- (符号あり32ビット整数)
- 戻り値:
- r0:ラジアン角(符号あり16ビット整数)
- がにマッピングされる
0Bh - CpuSet
- 2バイトまたは4バイト単位でデータをコピーする
- 引数:
- r0:コピー元のアドレス
- r1:コピー先のアドレス
- r2:
- 0-20:転送回数
- 24:コピー元アドレスを固定するか
- 26:転送単位サイズ(0 => 16ビット、1 => 32ビット)
0Ch - CpuFastSet
- 4バイト単位でデータをコピーする
- AGBでは32バイト単位に丸められる
- 引数:
- r0:コピー元のアドレス
- r1:コピー先のアドレス
- r2:
- 0-20:4バイト単位の個数
- 24:コピー元アドレスを固定するか
0Dh - BiosChecksum
- BIOSのチェックサムを取得する
- 32ビット単位で足し合わせる
- GB系のBIOSは
0xBAAE187Fを返す
- DS系のBIOSは
0xBAAE1880を返す
- 戻り値:
0Eh - BgAffineSet
- BGの変換行列を計算する
- 引数:
- r0:入力データの配列へのポインタ
- r1:出力データの配列へのポインタ
- r2:配列の個数
struct Input {
int32_t center_x; // 中心のX座標(8ビットの小数部)
int32_t center_y; // 中心のY座標(8ビットの小数部)
int16_t display_x; // ディスプレイの中心のX座標
int16_t display_y; // ディスプレイの中心のY座標
int16_t scaling_x; // X方向の拡大率(8ビットの小数部)
int16_t scaling_y; // Y方向の拡大率(8ビットの小数部)
uint16_t rotation; // 回転角(0-65536が0-360にマッピングされる)
};
struct Output {
int16_t pa; // $a_{11}$
int16_t pb; // $a_{12}$
int16_t pc; // $a_{21}$
int16_t pd; // $a_{22}$
int32_t x; // X軸の平行移動成分
int32_t y; // Y軸の平行移動成分
};
0Fh - ObjAffineSet
- OBJの変換行列を計算する
- 引数:
- r0:入力データの配列へのポインタ
- r1:出力データの配列へのポインタ
- r2:配列の個数
- r3:ストライド(2=連続、8=OAM)
struct Input {
int16_t scaling_x; // X方向の拡大率(8ビットの小数部)
int16_t scaling_y; // Y方向の拡大率(8ビットの小数部)
uint16_t rotation; // 回転角(0-65535が0-360にマッピングされる)
};
struct OutputWithStride2 {
int16_t pa; // $a_{11}$
int16_t pb; // $a_{12}$
int16_t pc; // $a_{21}$
int16_t pd; // $a_{22}$
};
struct OutputWithStride8 {
int16_t dummies0[3];
int16_t pa; // $a_{11}$
int16_t dummies1[3];
int16_t pb; // $a_{12}$
int16_t dummies_c[3];
int16_t pc; // $a_{21}$
int16_t dummy_for_pd[3];
int16_t pd; // $a_{22}$
};
カートリッジ
ヘッダ
| アドレス | バイト数 | 説明 |
|---|
| 00h | 4 | プログラムの始点へのジャンプ命令 |
| 04h | 156 | ロゴの圧縮済みビットマップ画像 |
| A0h | 12 | ゲームタイトル |
| ACh | 4 | ゲームコード |
| B0h | 2 | メーカーコード |
| B2h | 1 | 固定値(96h) |
| B3h | 1 | メインユニットコード |
| B4h | 1 | デバイスタイプ |
| B5h | 7 | 予約済み |
| BCh | 1 | ソフトウェアバージョン |
| BDh | 1 | ヘッダのチェックサム |
| BEh | 2 | 予約済み |
- ROMの先頭192バイトは実行可能な領域でありながらROMのヘッダ情報が格納される
- エントリポイントである80000000hにはヘッダを避けるためのジャンプ命令がある