ゲームボーイを作るその5。元に戻ってblargg-gb-testsのcpu_instrsの解析を続ける。
cpu_instrsテストの解析
前回のお試しビルドで、zipに同梱されている01-special.gb
と自前でビルドしたバイナリの比較を行った。
LCDへの出力の文字列と思しき差分以外は見当たらなかったので、shell.inc
内のいくつかあるdefineオプションは、オプション未指定時のbuild_rom.s
という事で良さそう(と考えている)。
01-special.gb
やそれ以降のテストを、ひととおり実行できるテスト環境を作りたいので、もう少し01-special.gb
の細かい部分を調べておく。
リセット解除〜メインまでの動き
前回調べた部分も一部重複するけど、改めて流れを追っていく。
ひとまず、GameBoyのCPUの初期PCは$0100
でここから処理が始まる。
ソースコード的にはbuild_rom.s
が以下の部分。
; GB header read by bootrom .org $100 nop jp reset
ここからリセット直後の初期化処理が行われるが、ジャンプ先のファイルはcommon/runtime.s
になる。アドレス的には$0200
からがruntime.s
のコード。
.org $200 ;; アドレスオフセットを$200に設定 ;;;; Shell ;; その直後にruntime.sのインクルード .include "runtime.s" .include "console.s"
runtime.s
の先頭のコードは、ROM領域のデータをRAM領域にコピーするcopy_to_wram_then_run
のコードになる。
copy_to_wram_then_run: ld b,a ld de,$C000 ld c,$10 - ldi a,(hl) ld (de),a inc e
この部分をデバッガでみると次のようになっており、上記の説明とも一致している。
build_rom.s
のjp reset
でruntime.s
内の処理にジャンプしてきた後、上記に記載したcopy_to_wram_then_run
を実行した後、$c000
にジャンプする。
copy_to_wram_then_run: ld b,a ld de,$C000 ld c,$10 - ldi a,(hl) ld (de),a inc e jr nz,- inc d dec c jr nz,- ld a,b jp $C000 ;; $c000にジャンプ .ifndef CUSTOM_RESET reset: ; Run code from $C000, as is done on devcart. This ; ensures minimal difference in how it behaves. ld hl,$4000 jp copy_to_wram_then_run .bank 1 slot 1 .org $0 ; otherwise wla pads with lots of zeroes jp std_reset .endif
このときのジャンプ先$c000
は、.bank 1 slot 1
とその次の行.org $0
により、jp std_reset
になる。
このジャンプ命令の直後には次のインクルードにより、各種処理のコードブロックが存在している。そのため、この部分を飛ばして基本のリセット処理を実行する。
jp std_reset .endif ; 以下のブロックを飛ばして、std_resetへ。 ; Common routines .include "gb.inc" .include "macros.inc" .include "delay.s" .include "crc.s" .include "printing.s" .include "numbers.s" .include "testing.s" ; Sets up hardware and runs main std_reset:
ここまでくれば、メインの実行まで後一歩。std_reset
内では各ペリフェラルの初期化等を行った後、call main
にてメインのテスト処理が実行される。
; Sets up hardware and runs main std_reset: ; Init hardware di ld sp,std_stack ; Save DMG/CGB id ld (gb_id),a ; Init hardware .ifndef BUILD_GBS wreg TAC,$00 wreg IF,$00 wreg IE,$00 .endif wreg NR52,0 ; sound off wreg NR52,$80 ; sound on wreg NR51,$FF ; mono wreg NR50,$77 ; volume ; TODO: clear all memory? ld hl,std_print call init_printing call init_testing call init_runtime call reset_crc ; in case init_runtime prints anything delay_msec 250 ; Run user code call main ; Default is to successful exit ld a,0 jp exit
cpu_instrs(というかblargg-gb-tests)はかなり、実際のROMに近い処理が行われてて、初期化処理で周辺のデバイスの設定等も結構やってくれてるっぽい? これverilatorとかとうまく連携したら、周辺環境コミコミのテスト環境とか作れそう。ちょっと考えてみたいな。