diff --git a/src/cpu.rs b/src/cpu.rs index 38a917fbfe13b4ab311bb732a859ea9d51afffc7..ec512278b1ecd174854497e09743523db7293841 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -578,3 +578,146 @@ impl Cpu { self.gbc = value; } } + +impl Default for Cpu { + fn default() -> Self { + let gbc: Rc<RefCell<GameBoyConfig>> = Rc::new(RefCell::new(GameBoyConfig::default())); + Cpu::new(Mmu::default(), gbc.clone()) + } +} + +#[cfg(test)] +mod tests { + use crate::cpu::Cpu; + + #[test] + fn test_cpu_clock() { + let mut cpu = Cpu::default(); + cpu.boot(); + cpu.mmu.allocate_default(); + + // test NOP instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x00); + let cycles = cpu.clock(); + assert_eq!(cycles, 4); + assert_eq!(cpu.pc, 0xc001); + + // test LD A, d8 instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x3e); + cpu.mmu.write(0xc001, 0x42); + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc002); + assert_eq!(cpu.a, 0x42); + + // test LD (HL+), A instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x22); + cpu.set_hl(0xc000); + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc001); + assert_eq!(cpu.hl(), 0xc001); + assert_eq!(cpu.mmu.read(cpu.hl()), 0x42); + + // test INC A instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x3c); + cpu.a = 0x42; + let cycles = cpu.clock(); + assert_eq!(cycles, 4); + assert_eq!(cpu.pc, 0xc001); + assert_eq!(cpu.a, 0x43); + + // test DEC A instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x3d); + cpu.a = 0x42; + let cycles = cpu.clock(); + assert_eq!(cycles, 4); + assert_eq!(cpu.pc, 0xc001); + assert_eq!(cpu.a, 0x41); + + // test LD A, (HL) instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x7e); + cpu.set_hl(0xc001); + cpu.mmu.write(0xc001, 0x42); + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc001); + assert_eq!(cpu.a, 0x42); + assert_eq!(cpu.hl(), 0xc001); + + // test LD (HL), d8 instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x36); + cpu.set_hl(0xc000); + cpu.mmu.write(0xc001, 0x42); + let cycles = cpu.clock(); + assert_eq!(cycles, 12); + assert_eq!(cpu.pc, 0xc002); + assert_eq!(cpu.hl(), 0xc000); + assert_eq!(cpu.mmu.read(cpu.hl()), 0x42); + + // test JR n instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0x18); + cpu.mmu.write(0xc001, 0x03); + let cycles = cpu.clock(); + assert_eq!(cycles, 12); + assert_eq!(cpu.pc, 0xc005); + + // test ADD A, d8 instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0xc6); + cpu.mmu.write(0xc001, 0x01); + cpu.a = 0x42; + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc002); + assert_eq!(cpu.a, 0x43); + + // test SUB A, d8 instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0xd6); + cpu.mmu.write(0xc001, 0x01); + cpu.a = 0x42; + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc002); + assert_eq!(cpu.a, 0x41); + + // test AND A, d8 instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0xe6); + cpu.mmu.write(0xc001, 0x0f); + cpu.a = 0x0a; + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc002); + assert_eq!(cpu.a, 0x0a & 0x0f); + + // test OR A, d8 instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0xf6); + cpu.mmu.write(0xc001, 0x0f); + cpu.a = 0x0a; + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc002); + assert_eq!(cpu.a, 0x0a | 0x0f); + + // test XOR A, d8 instruction + cpu.pc = 0xc000; + cpu.mmu.write(0xc000, 0xee); + cpu.mmu.write(0xc001, 0x0f); + cpu.a = 0x0a; + let cycles = cpu.clock(); + assert_eq!(cycles, 8); + assert_eq!(cpu.pc, 0xc002); + assert_eq!(cpu.a, 0x0a ^ 0x0f); + } +} diff --git a/src/mmu.rs b/src/mmu.rs index 2a5924453b9a63950dad12bbe6624389fdabded1..bdcecbf6c6f2ab35b17d578d52f0814b30dba95b 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -525,3 +525,19 @@ impl Mmu { self.gbc = value; } } + +impl Default for Mmu { + fn default() -> Self { + let mode = GameBoyMode::Dmg; + let gbc = Rc::new(RefCell::new(GameBoyConfig::default())); + let components = Components { + ppu: Ppu::new(mode, gbc.clone()), + apu: Apu::default(), + dma: Dma::default(), + pad: Pad::default(), + timer: Timer::default(), + serial: Serial::default(), + }; + Mmu::new(components, mode, gbc.clone()) + } +}