diff --git a/gameboy-lib/src/cpu/instructions.rs b/gameboy-lib/src/cpu/instructions.rs index 7f13da4..22bacca 100644 --- a/gameboy-lib/src/cpu/instructions.rs +++ b/gameboy-lib/src/cpu/instructions.rs @@ -13,6 +13,10 @@ pub enum Instruction { LdHd, // Load A into HL - 1 Push(Register), // Push register onto stack Pop(Register), // Pop register from stack + Add(Register), // Add register to A + Adc(Register), // Add register to A with carry + Sub(Register), // Subtract register from A + Sbc(Register), // Subtract register from A with carry } impl Instruction { @@ -151,6 +155,46 @@ impl Instruction { 0xD1 => Some(Instruction::Pop(Register::DE)), 0xE1 => Some(Instruction::Pop(Register::HL)), + 0x87 => Some(Instruction::Add(Register::A)), + 0x80 => Some(Instruction::Add(Register::B)), + 0x81 => Some(Instruction::Add(Register::C)), + 0x82 => Some(Instruction::Add(Register::D)), + 0x83 => Some(Instruction::Add(Register::E)), + 0x84 => Some(Instruction::Add(Register::H)), + 0x85 => Some(Instruction::Add(Register::L)), + 0x86 => Some(Instruction::Add(Register::HL)), + 0xC6 => Some(Instruction::Add(Register::D8)), + + 0x8F => Some(Instruction::Adc(Register::A)), + 0x88 => Some(Instruction::Adc(Register::B)), + 0x89 => Some(Instruction::Adc(Register::C)), + 0x8A => Some(Instruction::Adc(Register::D)), + 0x8B => Some(Instruction::Adc(Register::E)), + 0x8C => Some(Instruction::Adc(Register::H)), + 0x8D => Some(Instruction::Adc(Register::L)), + 0x8E => Some(Instruction::Adc(Register::HL)), + 0xCE => Some(Instruction::Adc(Register::D8)), + + 0x97 => Some(Instruction::Sub(Register::A)), + 0x90 => Some(Instruction::Sub(Register::B)), + 0x91 => Some(Instruction::Sub(Register::C)), + 0x92 => Some(Instruction::Sub(Register::D)), + 0x93 => Some(Instruction::Sub(Register::E)), + 0x94 => Some(Instruction::Sub(Register::H)), + 0x95 => Some(Instruction::Sub(Register::L)), + 0x96 => Some(Instruction::Sub(Register::HL)), + 0xD6 => Some(Instruction::Sub(Register::D8)), + + 0x9F => Some(Instruction::Sbc(Register::A)), + 0x98 => Some(Instruction::Sbc(Register::B)), + 0x99 => Some(Instruction::Sbc(Register::C)), + 0x9A => Some(Instruction::Sbc(Register::D)), + 0x9B => Some(Instruction::Sbc(Register::E)), + 0x9C => Some(Instruction::Sbc(Register::H)), + 0x9D => Some(Instruction::Sbc(Register::L)), + 0x9E => Some(Instruction::Sbc(Register::HL)), + 0xDE => Some(Instruction::Sbc(Register::D8)), + _ => None, } } diff --git a/gameboy-lib/src/cpu/mod.rs b/gameboy-lib/src/cpu/mod.rs index c4a1a1f..42522b4 100644 --- a/gameboy-lib/src/cpu/mod.rs +++ b/gameboy-lib/src/cpu/mod.rs @@ -57,10 +57,137 @@ impl Cpu { | Instruction::LdHd => self.load_special(instruction), Instruction::Push(register) => self.push(register), Instruction::Pop(register) => self.pop(register), + Instruction::Add(_) | Instruction::Adc(_) => self.add(instruction), + Instruction::Sub(_) | Instruction::Sbc(_) => self.sub(instruction), _ => panic!("[CPU] Not implementet {:?}", instruction), } } + fn exec_add(&mut self, a: u8, b: u8, carry: bool) { + let carry_value = if carry && self.registers.f.carry { 1 } else { 0 }; + let (add, frist_did_overflow) = a.overflowing_add(b); + let (new_value, result_did_overflow) = add.overflowing_add(carry_value); + + self.registers.f.zero = new_value == 0; + self.registers.f.subtract = false; + self.registers.f.half_carry = (((a & 0xF) + (b & 0xF)) & 0x10) == 0x10; + self.registers.f.carry = frist_did_overflow || result_did_overflow; + self.registers.set(&Register::A, new_value); + } + + fn add(&mut self, instruction: Instruction) -> u16 { + match instruction { + Instruction::Add(from) => match &from { + Register::D8 => { + let value = self.memory.read(self.pc + 1); + let a = self.registers.get(&Register::A); + self.exec_add(a, value, false); + self.pc.wrapping_add(2) + } + Register::HL => { + let value = self.memory.read(self.registers.get_16(&Register::HL)); + let a = self.registers.get(&Register::A); + self.exec_add(a, value, false); + self.pc.wrapping_add(1) + } + _ => { + let value = self.registers.get(&from); + let a = self.registers.get(&Register::A); + self.exec_add(a, value, false); + self.pc.wrapping_add(1) + } + }, + Instruction::Adc(from) => match &from { + Register::D8 => { + let value = self.memory.read(self.pc + 1); + let a = self.registers.get(&Register::A); + self.exec_add(a, value, true); + self.pc.wrapping_add(2) + } + Register::HL => { + let value = self.memory.read(self.registers.get_16(&Register::HL)); + let a = self.registers.get(&Register::A); + self.exec_add(a, value, true); + self.pc.wrapping_add(1) + } + _ => { + let value = self.registers.get(&from); + let a = self.registers.get(&Register::A); + self.exec_add(a, value, true); + self.pc.wrapping_add(1) + } + }, + _ => panic!("[CPU] Invalid instruction {:?}", instruction), + } + } + + fn exec_sub(&mut self, a: u8, b: u8, carry: bool) { + let carry_value = if carry && self.registers.f.carry { 1 } else { 0 }; + let (sub, first_did_underflow) = a.overflowing_sub(b); + let (new_value, result_did_underflow) = sub.overflowing_sub(carry_value); + + self.registers.set(&Register::A, new_value); + self.registers.f.zero = new_value == 0; + self.registers.f.subtract = true; + self.registers.f.half_carry = (((a & 0xF) + (b & 0xF)) & 0x10) == 0x10; + println!( + "[CPU] SUB: 0x{:x} - 0x{:x} = 0x{:x}", + a, b, new_value + ); + println!( + "[CPU] SUB: Half carry: {}", + (((a & 0xF) + (b & 0xF)) & 0x10) == 0x10 + + ); + self.registers.f.carry = first_did_underflow || result_did_underflow; + } + + fn sub(&mut self, instruction: Instruction) -> u16 { + match instruction { + Instruction::Sub(from) => match &from { + Register::D8 => { + let value = self.memory.read(self.pc + 1); + let a = self.registers.get(&Register::A); + self.exec_sub(a, value, false); + self.pc.wrapping_add(2) + } + Register::HL => { + let value = self.memory.read(self.registers.get_16(&Register::HL)); + let a = self.registers.get(&Register::A); + self.exec_sub(a, value, false); + self.pc.wrapping_add(1) + } + _ => { + let value = self.registers.get(&from); + let a = self.registers.get(&Register::A); + self.exec_sub(a, value, false); + self.pc.wrapping_add(1) + } + }, + Instruction::Sbc(from) => match &from { + Register::D8 => { + let value = self.memory.read(self.pc + 1); + let a = self.registers.get(&Register::A); + self.exec_sub(a, value, true); + self.pc.wrapping_add(2) + } + Register::HL => { + let value = self.memory.read(self.registers.get_16(&Register::HL)); + let a = self.registers.get(&Register::A); + self.exec_sub(a, value, true); + self.pc.wrapping_add(1) + } + _ => { + let value = self.registers.get(&from); + let a = self.registers.get(&Register::A); + self.exec_sub(a, value, true); + self.pc.wrapping_add(1) + } + }, + _ => panic!("[CPU] Invalid instruction {:?}", instruction), + } + } + fn push(&mut self, register: Register) -> u16 { let value = self.registers.get_16(®ister); self.registers @@ -667,4 +794,323 @@ mod tests { cpu.step(); assert_eq!(cpu.registers.get_16(&Register::HL), 0x1234); } + + #[test] + fn execute_add() { + let mut cpu = Cpu::new(); + cpu.registers.set(&Register::A, 0x00); + cpu.registers.set(&Register::B, 0x01); + cpu.registers.set(&Register::C, 0x02); + cpu.registers.set(&Register::D, 0x03); + cpu.registers.set(&Register::E, 0x04); + cpu.registers.set(&Register::H, 0x05); + cpu.registers.set(&Register::L, 0x06); + cpu.memory.write(0x0506, 0x07); + + cpu.boot(vec![ + 0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xC6, 0x42, + ]); + cpu.step(); + + // Add A 0x00 + assert_eq!(cpu.registers.get(&Register::A), 0x00); + cpu.step(); + + // Add A 0x01 + assert_eq!(cpu.registers.get(&Register::A), 0x01); + cpu.step(); + + // Add A 0x02 + assert_eq!(cpu.registers.get(&Register::A), 0x03); + cpu.step(); + + // Add A 0x03 + assert_eq!(cpu.registers.get(&Register::A), 0x06); + cpu.step(); + + // Add A 0x04 + assert_eq!(cpu.registers.get(&Register::A), 0x0A); + cpu.step(); + + // Add A 0x05 + assert_eq!(cpu.registers.get(&Register::A), 0x0F); + cpu.step(); + + // Add A 0x06 + assert_eq!(cpu.registers.get(&Register::A), 0x15); + cpu.step(); + + // Add A (HL) + assert_eq!(cpu.registers.get(&Register::A), 0x1C); + } + + #[test] + fn execute_add_carry() { + let mut cpu = Cpu::new(); + cpu.registers.set(&Register::A, 0x00); + cpu.registers.set(&Register::B, 0xFF); + cpu.registers.set(&Register::C, 0x01); + cpu.registers.set(&Register::D, 0x0F); + cpu.registers.set(&Register::E, 0x10); + cpu.registers.set(&Register::H, 0x0F); + cpu.registers.set(&Register::L, 0x10); + cpu.memory.write(0x0F10, 0x01); + + cpu.boot(vec![0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xC6, 0x42]); + cpu.step(); + + // Add A 0xFF from B + assert_eq!(cpu.registers.get(&Register::A), 0xFF); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, false); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Add A 0x01 from C + assert_eq!(cpu.registers.get(&Register::A), 0x00); + assert_eq!(cpu.registers.f.zero, true); + assert_eq!(cpu.registers.f.subtract, false); + assert_eq!(cpu.registers.f.half_carry, true); + assert_eq!(cpu.registers.f.carry, true); + cpu.step(); + + // Add A 0x0F from D + assert_eq!(cpu.registers.get(&Register::A), 0x0F); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, false); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Add A 0x10 from E + assert_eq!(cpu.registers.get(&Register::A), 0x1F); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, false); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Add A 0x0F from H + assert_eq!(cpu.registers.get(&Register::A), 0x2E); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, false); + assert_eq!(cpu.registers.f.half_carry, true); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Add A 0x10 from L + assert_eq!(cpu.registers.get(&Register::A), 0x3E); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, false); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Add A (HL) + assert_eq!(cpu.registers.get(&Register::A), 0x3F); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, false); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + } + + #[test] + fn execute_adc() { + let mut cpu = Cpu::new(); + + cpu.registers.set(&Register::A, 0x00); + cpu.registers.set(&Register::B, 0xFF); + cpu.registers.set(&Register::C, 0x01); + cpu.registers.set(&Register::D, 0x0F); + cpu.registers.set(&Register::E, 0x10); + cpu.registers.set(&Register::H, 0x0F); + cpu.registers.set(&Register::L, 0x10); + cpu.memory.write(0x0F10, 0x01); + + cpu.boot(vec![0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0xCE, 0x42]); + + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x00); // Add A 0x00 from A + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0xFF); // Add A 0xFF from B + cpu.step(); + println!("{:?}", cpu.registers); + assert_eq!(cpu.registers.get(&Register::A), 0x00); // Add A 0x01 from C + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x10); // Add A 0x0F from D carry 1 + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x20); // Add A 0x10 from E + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x2F); // Add A 0x0F from H + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x3F); // Add A 0x10 from L + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x40); // Add A (HL) + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x82); // Add A 0x42 + } + + #[test] + fn execute_sub() { + let mut cpu = Cpu::new(); + cpu.registers.set(&Register::A, 0x00); + cpu.registers.set(&Register::B, 0x01); + cpu.registers.set(&Register::C, 0x02); + cpu.registers.set(&Register::D, 0x03); + cpu.registers.set(&Register::E, 0x04); + cpu.registers.set(&Register::H, 0x05); + cpu.registers.set(&Register::L, 0x06); + cpu.memory.write(0x0506, 0x07); + + cpu.boot(vec![ + 0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0xD6, 0x42, + ]); + cpu.step(); + + // Sub A 0x00 + assert_eq!(cpu.registers.get(&Register::A), 0x00); + cpu.step(); + + // Sub A 0x01 + assert_eq!(cpu.registers.get(&Register::A), 0xFF); + cpu.step(); + + // Sub A 0x02 + assert_eq!(cpu.registers.get(&Register::A), 0xFD); + cpu.step(); + + // Sub A 0x03 + assert_eq!(cpu.registers.get(&Register::A), 0xFA); + cpu.step(); + + // Sub A 0x04 + assert_eq!(cpu.registers.get(&Register::A), 0xF6); + cpu.step(); + + // Sub A 0x05 + assert_eq!(cpu.registers.get(&Register::A), 0xF1); + cpu.step(); + + // Sub A 0x06 + assert_eq!(cpu.registers.get(&Register::A), 0xEB); + cpu.step(); + + // Sub A (HL) + assert_eq!(cpu.registers.get(&Register::A), 0xE4); + } + + #[test] + fn execute_sub_carry() { + let mut cpu = Cpu::new(); + cpu.registers.set(&Register::A, 0x00); + cpu.registers.set(&Register::B, 0xFF); + cpu.registers.set(&Register::C, 0x01); + cpu.registers.set(&Register::D, 0x0F); + cpu.registers.set(&Register::E, 0x10); + cpu.registers.set(&Register::H, 0x0F); + cpu.registers.set(&Register::L, 0x10); + cpu.memory.write(0x0F10, 0x01); + + cpu.boot(vec![0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0xD6, 0x42]); + cpu.step(); + + // Sub A 0xFF from B + assert_eq!(cpu.registers.get(&Register::A), 0x01); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, true); + cpu.step(); + + // Sub A 0x01 from C + assert_eq!(cpu.registers.get(&Register::A), 0x00); + assert_eq!(cpu.registers.f.zero, true); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Sub A 0x0F from D + assert_eq!(cpu.registers.get(&Register::A), 0xF1); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, true); + cpu.step(); + + // Sub A 0x10 from E + assert_eq!(cpu.registers.get(&Register::A), 0xE1); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Sub A 0x0F from H + assert_eq!(cpu.registers.get(&Register::A), 0xD2); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, true); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Sub A 0x10 from L + assert_eq!(cpu.registers.get(&Register::A), 0xC2); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Sub A (HL) + assert_eq!(cpu.registers.get(&Register::A), 0xC1); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + cpu.step(); + + // Sub A 0x42 + assert_eq!(cpu.registers.get(&Register::A), 0x7F); + assert_eq!(cpu.registers.f.zero, false); + assert_eq!(cpu.registers.f.subtract, true); + assert_eq!(cpu.registers.f.half_carry, false); + assert_eq!(cpu.registers.f.carry, false); + } + + #[test] + fn execute_sbc() { + let mut cpu = Cpu::new(); + + cpu.registers.set(&Register::A, 0x00); + cpu.registers.set(&Register::B, 0xFF); + cpu.registers.set(&Register::C, 0x01); + cpu.registers.set(&Register::D, 0x0F); + cpu.registers.set(&Register::E, 0x10); + cpu.registers.set(&Register::H, 0x0F); + cpu.registers.set(&Register::L, 0x10); + cpu.memory.write(0x0F10, 0x01); + + cpu.boot(vec![0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0xDE, 0x42]); + + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x00); // Sub A 0x00 from A + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x01); // Sub A 0xFF from B + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0xFF); // Sub A 0x01 from C + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0xEF); // Sub A 0x0F from D carry 1 + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0xDF); // Sub A 0x10 from E + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0xD0); // Sub A 0x0F from H + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0xC0); // Sub A 0x10 from L + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0xBF); // Sub A (HL) + cpu.step(); + assert_eq!(cpu.registers.get(&Register::A), 0x7D); // Sub A 0x42 + } } diff --git a/gameboy-lib/src/cpu/registers/flag_register.rs b/gameboy-lib/src/cpu/registers/flag_register.rs index 8e8f7fb..99d0889 100644 --- a/gameboy-lib/src/cpu/registers/flag_register.rs +++ b/gameboy-lib/src/cpu/registers/flag_register.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub struct FlagRegister { pub zero: bool, pub subtract: bool, diff --git a/gameboy-lib/src/cpu/registers/mod.rs b/gameboy-lib/src/cpu/registers/mod.rs index 27b0fd0..75a304c 100644 --- a/gameboy-lib/src/cpu/registers/mod.rs +++ b/gameboy-lib/src/cpu/registers/mod.rs @@ -22,6 +22,7 @@ pub enum Register { D16, } +#[derive(Debug)] pub struct Registers { pub a: u8, pub b: u8, diff --git a/gameboy-lib/src/cpu/registers/stack_pointer.rs b/gameboy-lib/src/cpu/registers/stack_pointer.rs index b3f241d..29e88d9 100644 --- a/gameboy-lib/src/cpu/registers/stack_pointer.rs +++ b/gameboy-lib/src/cpu/registers/stack_pointer.rs @@ -1,4 +1,5 @@ +#[derive(Debug)] pub struct StackPointer { pub value: u16, }