Technical document (GB Emulator) Contact: [email protected] Author: gucchan (B1, Keio University) Jun Murai Lab., ARCH(Internet Architecture Research Team) @ Delta North. 英語の資料しかなかったのでとりあえず初代ゲームボーイに関するところだけ日本語でまとめた。 メモリマップ (CPU空間) 0x0000 ~ 0x3fff: (Ext.) ROM bank #0 (fixed, 0x0100 ~ 0x014f: カートリッジヘッダ) 0x4000 ~ 0x7fff: (Ext.) ROM bank #1..n (switchable, MBC(Memory Bank Controller)) 0x8000 ~ 0x9fff: VRAM (0x8000 ~ 0x8fff, 0x8800 ~ 0x97ff: パターンテーブル) 0xa000 ~ 0xbeff: (Ext.) 外部RAM 0xc000 ~ 0xcfff Work RAM 0 (4KB) 0xd000 ~ 0xdfff: Work RAM 1 (4KB) 0xe000 ~ 0xfdff: 0xc000 ~ 0xddff間のミラーリング 0xfe00 ~ 0xfe9f: OAM(Object Attribute Memory) 0xfea0 ~ 0xfeff: 未使用 0xff00 ~ 0xff7f: I/Oポート用レジスタ 0xff80 ~ 0xfffe: HRAM(High RAM) 0xffff: 割り込みイネーブルレジスタ jump vector 0000h, 0008h, 0010h, 0018h, 0020h, 0028h, 0030h, 0038h (RSTコマンド用) 0040h, 0048h, 0050h, 0058h, 0060h (割り込み用) 任天堂ロゴ16進ダンプ (location: 0x0104 ~ 0x0133) CE ED 66 66 CC 0D 00 0B 03 73 00 83 00 0C 00 0D 00 08 11 1F 88 89 00 0E DC CC 6E E6 DD DD D9 99 BB BB 67 63 6E 0E EC CC DD DC 99 9F BB B9 33 3E グラフィック パレット (location: 0xff47) Bit Bit Bit Bit 7-6 5-4 3-2 1-0 - Shade Shade Shade Shade for for for for Color Color Color Color Number Number Number Number 3 2 1 0 0(0b00)=白, 1(0b01)=明るいグレー, 2(0b10)=暗いグレー, 3(0b11)=黒 スプライトDMA転送(location: 0xff46) ROMやRAMの内容をOAMに転送するためにはここの領域にアドレスをセットする ここのアドレスにはDMA転送対象のアドレスを0x100で割った結果、(つまり何が言いたいかというと上位1バイト)をロードする。 DMA転送自体は160msあたりで完了する(ゲームボーイColorは80ms程度らしい) 多くのプログラムはこのDMA転送をVBlank(垂直帰線時間)期間中に行う。 VRAMとパターンテーブル VRAMの領域はメモリマップ中の 0x8000 ~ 0x97ff 中に存在しており、ここに192個のタイルが格納できるようになっている。それぞれのタイ ルは8x8ピクセルの色の深さ段階が4段階のグレー(白,薄い灰色,グレー,黒)となっている。タイルは背景やスプライトなどに利用することができ るが最前面のスプライトには3段階の色しか使えない(そのうちの1つであるColor-0は透明と定義されているため) パターンテーブルはメモリマップ上の 0x8000 ~ 0x8fff, 0x8800 ~ 0x97ff に存在しており、最初のパターンテーブルはスプライトと背景の ために利用され、番号は符号なし8-bit整数(0 ~ 255)。もう一つのパターンテーブルは背景とウィンドウ(背景の上位レイヤとして覆うもの)のた めに利用され、符号付き8-bit整数(-128 ~ +127)で番号付けされる。パターンタイルは1個あたり16byteなので、 0x8000 ~ 0x8fff 上にあるパ ターン#0は 0x8000, 0x8800 ~ 0x97ff に存在するパターン#0では、 0x8800 + (128 * 16) = 0x9000 となる。 Tile: .33333.. 22...22. 11...11. 2222222. <-- digits 33...33. represent 22...22. color 11...11. numbers ........ Image: .33333.. -> 01111100 01111100 22...22. -> 00000000 11000110 11...11. -> 11000110 00000000 2222222. -> 00000000 11111110 33...33. -> 11000110 11000110 22...22. -> 00000000 11000110 11...11. -> 11000110 00000000 ........ -> 00000000 00000000 -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> $7C $7C $00 $C6 $C6 $00 $00 $FE $C6 $C6 $00 $C6 $C6 $00 $00 $00 1ラインは2byteで表現される。どの色なのかを取得するためには、 C(x,y) = ((m+(2*y)) & (1<<(7-x))) | ((m+(2*y)+1) & (1<<(7-x))<<8) (m:pattern table address) という式で求められるということになる。 スプライトとOAM(Object Attribute Memory) 8x8, 8x16ピクセルまでの最大40個のスプライトを配置でき、ハードウェアの制約という観点の問題から1スキャンライン10個までしか同時にス プライトを描画できない。 スプライトとして描画されるタイルはOAMメモリへと移動して管理されるようにしなければならない。 ただし8x16スプライトの時はスプライトパターン番号のLSBを無視し、0として扱わなければならない 1スプライトあたりのOAMの中身は次のようになっている。 Byte0 Byte1 Byte2 Byte3 Bit7 Y position X position Tile/Pattern Number Attributes/Flags OBJ-to-BG Priority (0=OBJ Above BG, 1=OBJ Behind BG color 1-3) (Used for both BG and Window. BG color 0 is always behind OBJ) Bit6 Y flip (0=Normal, 1=Vertically mirrored) Bit5 X flip (0=Normal, 1=Horizontally mirrored) Bit4 Palette number **Non CGB Mode Only** (0=OBP0, 1=OBP1) Bit3 Tile VRAM-Bank **CGB Mode Only** (0=Bank 0, 1=Bank 1) Bit2-0 Palette number **CGB Mode Only** (OBP0-7) カートリッジヘッダ ゲームボーイにはファミコンでいう.nesや.fds、DSという.ndsのようなエミュレータ界隈で発明された野良ファイルフォーマットが存在しな い。理由はカートリッジのROM自体にヘッダが存在しているからである。便宜上.gbという拡張子を利用する。 0x0100 ~ 0x0103: エントリポイント 0x0104 ~ 0x0133: 任天堂ロゴ 0x0134 ~ 0x0143: ゲームタイトル 0x013f ~ 0x0142: 製造元コード 0x0143: CGBフラグ 0x0144 ~ 0x0145: ライセンスコード 0x0146: SGBフラグ 0x0148: ROMサイズ 0x0149: RAMサイズ 0x014a: Destination Code 0x014b: ライセンスコード(Old) 0x014c: マスクROMバージョン 0x014d: ヘッダチェックサム 0x014e ~ 0x014f: グローバルチェックサム 0x0100 ~ 0x0103: エントリポイント 任天堂ロゴが表示された後にこのエントリポイントにジャンプ命令が掛かり飛ばされてくる。大体この4byte領域にはNOP命令(=0x00)が格納さ れており、その後にJP 0150hが実行される(これはいつも実行される訳ではない模様) 0x0104 ~ 0x0133: 任天堂ロゴ ロゴのビットマップのダンプデータはメモリマップの項目の任天堂ロゴを参照のこと ゲームボーイはこのロゴを本体が起動されると上から画面の中心部分までスクロールさせた後、ブートプロシージャはこのロゴのバイナリを自 身も保持しており、この値が一致することによってROMの内容を引き続き実行することができるようになっている。一致しなかった場合、ロゴ が表示されたままフリーズすることになる。 面白いことに、ゲームボーイColor以外のゲームボーイシリーズではすべてのロゴデータ48byte分をチェックするのに対してゲームボーイColor ではロゴデータの先頭24byteのみチェックを行う(ハードウェアスペックを向上させた分どっか節約させたかったのだろうか) 0x0134 ~ 0x0143: ゲームタイトル 大文字ASCIIで16文字のゲームタイトルが入る。 もしゲームタイトルが16文字より少なかった場合は0-paddingで埋められる。ここも16文字ではなくゲームボーイColorでは15文字になってい る。 0x013f ~ 0x0142: 製造元コード この部分は製造者コードとなっているがそれは比較的GB向けに製造された新しいカートリッジがこの領域に格納されており、多くの場合 0x0134 ~ 0x0143部分に格納できなかったゲームタイトルがそのまま入る模様 0x0143: CGB-Flag この部分もゲームタイトル領域に利用されている。この部分の上位ビットはゲームボーイColor向けのカートリッジを起動する時に使われてお り、もしそうでなければ非ゲームボーイColorモード(つまりカラーではないゲームボーイ向け)だということになる。ゲームボーイColor向けのモ ードだった場合、次に二通りが存在する。 0x80: ROMがゲームボーイColorに対応しているが、カラー非対応でも動作するROM 0xc0: ROMがゲームボーイColor専用になっている 0x0144 ~ 0x045: ライセンスコード 2文字のASCIIコードで表現される。この値はどうやらゲーム内でゲーム製造元を表示するためにある値らしい。(製造元コードとは何だったの か….) ただしこの部分の領域がライセンスコードとして使われ始めたのはどうもゲームボーイSuperがリリースされた頃からのようでそれ以前の古い ゲームは0x041bを代わりにライセンスコードとして利用していたようだ。 0x0146: SGB-Flag ROMがゲームボーイSuperをサポートするかを決めているフラグ。値としては二種類。こちらは下位ニブルに対してのフラグとなっている。 0x00: ゲームボーイSuper用の機能がROMに存在しない 0x03: ROMがゲームボーイSuper向けの機能をサポートしている 0x0147: カートリッジタイプ どのMBC (Memory Bank Controller)がカートリッジで利用されているかを示すフラグ。 00h 01h 02h 03h 05h 06h 08h 09h 0Bh 0Ch 0Dh 0Fh 10h 11h 12h NROM (ROM ONLY) MBC1 MBC1+RAM MBC1+RAM+BATTERY MBC2 MBC2+BATTERY ROM+RAM ROM+RAM+BATTERY MMM01 MMM01+RAM MMM01+RAM+BATTERY MBC3+TIMER+BATTERY MBC3+TIMER+RAM+BATTERY MBC3 MBC3+RAM 13h 15h 16h 17h 19h 1Ah 1Bh 1Ch 1Dh 1Eh FCh FDh FEh FFh MBC3+RAM+BATTERY MBC4 MBC4+RAM MBC4+RAM+BATTERY MBC5 MBC5+RAM MBC5+RAM+BATTERY MBC5+RUMBLE MBC5+RUMBLE+RAM MBC5+RUMBLE+RAM+BATTERY POCKET CAMERA BANDAI TAMA5 HuC3 HuC1+RAM+BATTERY 0x0148: ROMサイズ カートリッジのROMサイズを示す領域。 下の図のアドレスの遷移に規則性があることから 0x7fff << *((uint16_t *)0x0148) という式でサイズを算出できる。 00h 01h 02h 03h 04h 05h 06h 07h 52h 53h 54h - 32KByte 64KByte 128KByte 256KByte 512KByte 1MByte 2MByte 4MByte 1.1MByte 1.2MByte 1.5MByte (no ROM banking) (4 banks) (8 banks) (16 banks) (32 banks) (64 banks) - only 63 banks used by MBC1 (128 banks) - only 125 banks used by MBC1 (256 banks) (72 banks) (80 banks) (96 banks) 0x0149: RAMサイズ 外部RAM(カートリッジ)のサイズを決めている領域 ただ、MBC2を利用しているカートリッジは512 x 4bitのRAMを内部で保持しているにも関わらず 00h指定しなければならない 00h 01h 02h 03h - None 2 KBytes 8 Kbytes 32 KBytes (4 banks of 8KBytes each) 0x014a: Destination Code (なんて訳して良いか分からない) このゲームが日本国内で販売されたかどうかを表すフラグ 00h - Japanese 01h - Non-Japanese 0x014b: ライセンスコード(Old) 256通りのうちで製造元のコードが記述されている。特にこの領域に0x33が埋められている場合は新しいライセンスコードが上のほうで示した 0x0144 ~ 0x0145の2byte領域中に存在していることを示している 0x014c: マスクROMヘッダバージョン : このゲームのマスクROMのバージョンを表している 0x014d: ヘッダーチェックサム 0x0134(タイトル)~ 0x014c(マスクROMヘッダバージョン)までのチェックサムが含まれている。 チェックサムの算出方法は以下。 x=0:FOR i=0134h TO 014Ch:x=x-MEM[i]-1:NEXT C++に直すとこうなるのかな、xがチェックサム。この値の下位8bitがこの領域に示されているチェックサムと一致しなければゲームが動作しな いようになっている。 uint16_t checksum() { uint16_t x = 0; for(uint16_t n = 0x0134; n <= 0x014c; n++) x = x - *((uint16_t *)n) - 1; return x; } 0x014e ~ 0x014f: グローバルチェックサム ROM全体のチェックサムが格納されている(ただしリトルエンディアンなのでバイトオーダーに気を付けること) ただこの領域はゲームボーイはチェックすることはない。 起動時シーケンス ゲームボーイを起動するとメモリ番地0から始まる0x0000 ~ 0x00ffまでの256byteのプログラムをロードする。このプログラムはROMの中に格 納されており、最初の処理はカートリッジの0x0104 ~ 0x0133までの任天堂ロゴをスクロールしながら中央部分まで描画を続けること。その次 の処理でカートリッジ内のROMに格納されている任天堂ロゴと内部RAMにある任天堂ロゴを比較し、このバイナリが完全に一致するかどうか をチェックする。完全に一致しなければゲームボーイはそのまま動作を停止する。 すべて等しいことを確認すると、0x0134 ~ 0x014dまでの領域をすべて足し、この総和に25を足してLSBをチェックする。LSBが0ではない場 合、ゲームボーイは実行を停止する。 0であった場合は、内部ROMが無効になり、0x0100(ブートエントリポイント)の値がpcレジスタにロードされる。 起動チェック完了後の初期値は次のようになっているが、この値が常に存在しているという信頼はできないため、リセット時に常にセットする のが望ましい。 AF=$01B0 BC=$0013 DE=$00D8 HL=$014D Stack Pointer=$FFFE [$FF05] = $00 ; TIMA [$FF06] = $00 ; TMA [$FF07] = $00 ; TAC [$FF10] = $80 ; NR10 [$FF11] = $BF ; NR11 [$FF12] = $F3 ; NR12 [$FF14] = $BF ; NR14 [$FF16] = $3F ; NR21 [$FF17] = $00 ; NR22 [$FF19] = $BF ; NR24 [$FF1A] = $7F ; NR30 [$FF1B] = $FF ; NR31 [$FF1C] = $9F ; NR32 [$FF1E] = $BF ; NR33 [$FF20] = $FF ; NR41 [$FF21] = $00 ; NR42 [$FF22] = $00 ; NR43 [$FF23] = $BF ; NR30 [$FF24] = $77 ; NR50 [$FF25] = $F3 ; NR51 [$FF26] = $F1-GB, $F0-SGB ; NR52 [$FF40] = $91 ; LCDC [$FF42] = $00 ; SCY [$FF43] = $00 ; SCX [$FF45] = $00 ; LYC [$FF47] = $FC ; BGP [$FF48] = $FF ; OBP0 [$FF49] = $FF ; OBP1 [$FF4A] = $00 ; WY [$FF4B] = $00 ; WX [$FFFF] = $00 ; IE 割り込み IME (Interrupt Master Enable Flag (W/-)) 0の時すべての割り込みを無効に、 1のときすべての割り込みを有効にするためのレジスタ(IE(Interrupt Enable)=0xfffに変更) IE (Interrupt Enable (W/R)) Bit Bit Bit Bit Bit 0: 1: 2: 3: 4: V-Blank LCD STAT Timer Serial Joypad Interrupt Interrupt Interrupt Interrupt Interrupt IF (Interrupt Flag (W/R)) Enable Enable Enable Enable Enable (INT (INT (INT (INT (INT 40h) 48h) 50h) 58h) 60h) (1=Enable) (1=Enable) (1=Enable) (1=Enable) (1=Enable) IRQフラグ Bit Bit Bit Bit Bit 0: 1: 2: 3: 4: V-Blank LCD STAT Timer Serial Joypad Interrupt Interrupt Interrupt Interrupt Interrupt Request Request Request Request Request (INT (INT (INT (INT (INT 40h) 48h) 50h) 58h) 60h) (1=Request) (1=Request) (1=Request) (1=Request) (1=Request) 割り込みが実行されるとIFの内容は自動的にCPUによってリセットされるべきで、IMEも0に戻される。IMEの値はまた次に実行される命令で RETIなどの命令を利用してIMEをイネーブルにしないといけない。 そして、上に示した割り込みベクタにPCの値を飛ばさなければならない。もし、IFに複数のビットがセットされた場合、それはIF,IEのビット0 から順番で優先度が高いと判断されるため、一番優先度が高いのはVBlank(垂直帰線時間に突入したことを示す割り込み)であり、一番優先度の 低い命令はジョイパッドからの入力ということになる。 タイマー ゲームボーイでは、4096(4.096kHz),16384(16.384kHz), 65536(65.536kHz),262144(262.144kHz)の4種類の中から周波数を選択した上でのタイマ ー割り込みが可能。 この周波数ごとにI/OレジスタのTIMA(カウンターレジスタ,)に値がインクリメントされていき、最終的にTIMAがオーバーフローした時に割り込 みが発生し、TMAレジスタにロードされた値で割られる。 TIMA, TMAレジスタの詳細を見ていく 0xff07(-----ti): TAC (Timer control register) (r/w) 下位3bitのみがTACレジスタとして利用される。 t(bit 2): タイマー ストップ(0)/スタート(1) i(bit 0-1): タイマー割り込み周波数 (0b00=4.096kHz, 0b01=262.144kHz, 0b10=65.536kHz, 0b11=16.384kHz) 0xff05(xxxxxxxx): TIMA (Timer counter register) (r/w) TACレジスタで設定したタイマ割り込み周波数値ごとに自身の値がインクリメントされていく。TIMAがオーバーフローした時に割り込みが起こ る。 0xff06(xxxxxxxx): TMA (Timer Modulo register) (r/w) このレジスタにロードされた値がTIMAがオーバーフローした時にロードされる ld ld ld ld a,1 ($ff06), a ; TMAに1を設定 a, 4 ($ff07), a ; TACに4(0b00000100)を設定,t=1,0b00=4.096kHz. TIMA=1, TAC=4なので, 1秒間に4096回割り込みが発生することになる。 ld ld ld ld a, 4 ($ff06), a ; TMAに4を設定 a, 5 ; ($ff07), a ; TACに5(0b00000101)を設定,t=1,0b01=262.144kHz. TIMA=1, TAC=5なので、262144 / TIMA = 262144 / 4 = 65536回一秒間に割り込みが発生することになる。 参考資料 GameBoy CPU Manual http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf GameBoy Technical Specifications http://problemkaputt.de/pandocs.htm http://www.geocities.co.jp/Playtown/2004/gmbspecj.txt
© Copyright 2024 Paperzz