diff --git a/examples/sdl/src/main.rs b/examples/sdl/src/main.rs index 51903a1c544e9b14f2054df2c11d2d54ca07c001..e2eae28905323dafdc354b9861cc7aca1271508a 100644 --- a/examples/sdl/src/main.rs +++ b/examples/sdl/src/main.rs @@ -4,9 +4,7 @@ fn main() { let mut game_boy = GameBoy::new(); game_boy.load_boot_default(); - game_boy.clock(); - game_boy.clock(); - game_boy.clock(); - game_boy.clock(); - game_boy.clock(); + for _ in 0..40000 { + game_boy.clock(); + } } diff --git a/src/cpu.rs b/src/cpu.rs index 7351f6beccbb9046f727740f45c1161935c9222b..7edd5dc20da6a83f07549b2552434973aef2d940 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,5 +1,7 @@ use crate::mmu::Mmu; +pub const PREFIX: u8 = 0xcb; + pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 208] = [ // 0x0 opcodes (nop, 4, "NOP"), @@ -36,7 +38,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 208] = [ (nop, 4, "NOP"), (nop, 4, "NOP"), // 0x2 opcodes - (nop, 4, "NOP"), + (jr_nz_i8, 8, "JR NZ, i8"), (ld_hl_u16, 12, "LD HL, u16"), (nop, 4, "NOP"), (nop, 4, "NOP"), @@ -224,6 +226,196 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 208] = [ (nop, 4, "NOP"), ]; +pub const BITWISE: [(fn(&mut Cpu), u8, &'static str); 176] = [ + // 0x0 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x1 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x2 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x3 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x4 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x5 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x6 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x7 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (bit_7_h, 8, "BIT 7, H"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x8 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0x9 opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + // 0xa opcodes + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), + (nop, 4, "NOP"), +]; + pub struct Cpu { pc: u16, sp: u16, @@ -264,18 +456,29 @@ impl Cpu { } pub fn clock(&mut self) { + let pc = self.pc; + // fetches the current instruction and increments // the PC (program counter) accordingly - let opcode = self.mmu.read(self.pc); - self.pc += 1; + let mut opcode = self.mmu.read(self.pc); + self.pc = self.pc.wrapping_add(1); + + let instruction: &(fn(&mut Cpu), u8, &str); + + if opcode == PREFIX { + opcode = self.mmu.read(self.pc); + self.pc = self.pc.wrapping_add(1); + instruction = &BITWISE[opcode as usize]; + } else { + instruction = &INSTRUCTIONS[opcode as usize]; + } - let instruction = INSTRUCTIONS[opcode as usize]; let (instruction_fn, instruction_size, instruction_str) = instruction; - println!("{} ({:#x})", instruction_str, opcode); + println!("{}\t({:#x})\t${:04x}", instruction_str, opcode, pc); instruction_fn(self); - self.clocks = self.clocks.wrapping_add(instruction_size as u32); + self.clocks = self.clocks.wrapping_add(*instruction_size as u32); } #[inline(always)] @@ -457,6 +660,17 @@ fn add_hl_bc(cpu: &mut Cpu) { cpu.set_hl(value); } +fn jr_nz_i8(cpu: &mut Cpu) { + let byte = cpu.read_u8() as i8; + + if cpu.get_zero() { + return; + } + + cpu.pc = (cpu.pc as i16).wrapping_add(byte as i16) as u16; + cpu.clocks += 4; +} + fn ld_hl_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); cpu.set_hl(word); @@ -480,6 +694,23 @@ fn xor_a_a(cpu: &mut Cpu) { cpu.set_carry(false); } +fn bit_7_h(cpu: &mut Cpu) { + bit_h(cpu, 7); +} + +/// Helper function to test one bit in a u8. +/// Returns true if bit is 0. +fn bit_zero(val: u8, bit: u8) -> bool { + (val & (1u8 << (bit as usize))) == 0 +} + +fn bit_h(cpu: &mut Cpu, bit: u8) { + println!("{}", cpu.h); + cpu.set_sub(false); + cpu.set_zero(bit_zero(cpu.h, bit)); + cpu.set_half_carry(true); +} + fn add_u16_u16(cpu: &mut Cpu, first: u16, second: u16) -> u16 { let first = first as u32; let second = second as u32; diff --git a/src/mmu.rs b/src/mmu.rs index a8e95ff075392df1882fc1d5b85066ca4b9eeb2f..2c163dc799f6215580f0b24fbcd3d9e80333c1c4 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -47,7 +47,7 @@ impl Mmu { println!("WRITING TO RAM"); self.ram[(addr & 0x1fff) as usize] = value; } - _ => panic!("asdad"), + addr => panic!("Writing in unknown location 0x{:04x}", addr), } }