use crate::gb::bus::DmgBus;
use crate::gb::cartridge::load_cartridge;
use crate::gb::console::Gb;
const NINTENDO_LOGO: [u8; 48] = [
0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99,
0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E,
];
const BOOT_CYCLE_LIMIT: u64 = 2_500_000;
fn build_test_rom(logo: &[u8; 48]) -> Vec<u8> {
let mut rom = vec![0u8; 0x8000];
rom[0x0100] = 0x18; rom[0x0101] = 0xFE; rom[0x0104..=0x0133].copy_from_slice(logo);
rom[0x0147] = 0x00; rom[0x0148] = 0x00; rom[0x0149] = 0x00; let chk = rom[0x0134..=0x014C]
.iter()
.fold(0u8, |acc, &b| acc.wrapping_sub(b).wrapping_sub(1));
rom[0x014D] = chk;
rom
}
fn run_until_cartridge_entry(gb: &mut Gb<DmgBus>) -> bool {
let start = gb.cycles();
loop {
if gb.cpu.regs.pc == 0x0100 {
return true;
}
if gb.cycles().saturating_sub(start) >= BOOT_CYCLE_LIMIT {
return false;
}
gb.step();
}
}
#[test]
fn test_dmg_boot_sets_correct_register_state() {
let rom = build_test_rom(&NINTENDO_LOGO);
let cart = load_cartridge(&rom).expect("valid ROM");
let mut gb = Gb::new(DmgBus::new(cart));
let reached = run_until_cartridge_entry(&mut gb);
assert!(
reached,
"Boot ROM never handed off to $0100 within the cycle limit"
);
assert_eq!(gb.cpu.regs.a, 0x01, "A register after boot");
assert_eq!(gb.cpu.regs.f, 0xB0, "F register after boot");
assert_eq!(gb.cpu.regs.b, 0x00, "B register after boot");
assert_eq!(gb.cpu.regs.c, 0x13, "C register after boot");
assert_eq!(gb.cpu.regs.d, 0x00, "D register after boot");
assert_eq!(gb.cpu.regs.e, 0xD8, "E register after boot");
assert_eq!(gb.cpu.regs.h, 0x01, "H register after boot");
assert_eq!(gb.cpu.regs.l, 0x4D, "L register after boot");
assert_eq!(gb.cpu.regs.sp, 0xFFFE, "SP after boot");
assert_eq!(gb.cpu.regs.pc, 0x0100, "PC after boot");
}
#[test]
fn test_dmg_boot_halts_on_corrupted_logo() {
let bad_logo = [0u8; 48]; let rom = build_test_rom(&bad_logo);
let cart = load_cartridge(&rom).expect("valid ROM");
let mut gb = Gb::new(DmgBus::new(cart));
let reached = run_until_cartridge_entry(&mut gb);
assert!(
!reached,
"Boot ROM must lock up on a corrupted logo; it must not hand off to $0100"
);
}