From 3897c3561eba01c8bc05b1fefc024fb22d355d8b Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Sun, 17 Oct 2021 19:14:41 -0500 Subject: [PATCH] add and sub instructions --- src/cpu.rs | 377 +++++++++++++++++++++++++++++++++++++++++++++++---- src/utils.rs | 23 ++++ 2 files changed, 372 insertions(+), 28 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index b6b25d4..3d372bf 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -4,7 +4,9 @@ use crate::utils::{ set_bit, join_bytes, add_half_carry, - sub_half_carry + sub_half_carry, + add_half_carry_16bit, + sub_half_carry_16bit, }; use crate::bus::Bus; @@ -118,6 +120,10 @@ impl Registers { Register::PC => self.pc, } } + + pub fn get_8bit(&self, register: Register) -> u8 { + self.get(register).to_be_bytes()[1] + } pub fn set(&mut self, register: Register, val: u16) { let bytes = val.to_be_bytes(); @@ -171,7 +177,7 @@ pub enum OpcodeParameter { Register(Register), Register_U8(Register, u8), Register_U16(Register, u16), - Register_I8(Register, u8), + Register_I8(Register, i8), Register_I16(Register, u16), U8_Register(u8, Register), U16_Register(u16, Register), @@ -393,6 +399,28 @@ impl CPU { self.registers.increment(reg2, 1); self.registers.increment(Register::PC, 1); }, + OpcodeParameter::RegisterIncrement_Register(reg1, reg2) => { + let val = self.registers.get(reg2).to_be_bytes()[1]; + bus.write(self.registers.get(reg1), val); + self.registers.increment(reg1, 1); + self.registers.increment(Register::PC, 1); + }, + _ => {}, + }, + // Load and decrement + Opcode::LDD(params) => match params { + OpcodeParameter::Register_RegisterDecrement(reg1, reg2) => { + let val = bus.read(self.registers.get(reg2)); + self.registers.set(reg1, val as u16); + self.registers.decrement(reg2, 1); + self.registers.increment(Register::PC, 1); + }, + OpcodeParameter::RegisterDecrement_Register(reg1, reg2) => { + let val = self.registers.get(reg2).to_be_bytes()[1]; + bus.write(self.registers.get(reg1), val); + self.registers.decrement(reg1, 1); + self.registers.increment(Register::PC, 1); + }, _ => {}, }, Opcode::AND(params) => match params { @@ -495,6 +523,103 @@ impl CPU { self.registers.set_flag(FlagRegister::HalfCarry, sub_half_carry(val1.to_be_bytes()[1], val2.to_be_bytes()[1])); self.registers.set_flag(FlagRegister::Carry, val2 > val1); }, + Opcode::ADD(params) => { + self.registers.increment(Register::PC, 1); + self.registers.set_flag(FlagRegister::Substract, false); + match params { + OpcodeParameter::Register_Register(reg1, reg2) => { + if reg1.is_8bit() && reg2.is_8bit() { + self.registers.set_flag(FlagRegister::HalfCarry, add_half_carry(self.registers.get_8bit(reg1), self.registers.get_8bit(reg2))); + self.registers.set(reg1, self.registers.get(reg1) + self.registers.get(reg2)); + } else if reg1.is_16bit() && reg2.is_16bit() { + self.registers.set_flag(FlagRegister::HalfCarry, add_half_carry_16bit(self.registers.get(reg1), self.registers.get(reg2))); + self.registers.set(reg1, self.registers.get(reg1) + self.registers.get(reg2)); + } else if reg1.is_8bit() && reg2.is_16bit() { + let val1 = self.registers.get(reg1); + let val2 = bus.read(self.registers.get(reg2)) as u16; + self.registers.set(reg1, val1 + val2); + self.registers.set_flag(FlagRegister::HalfCarry, add_half_carry(val1.to_be_bytes()[1], val2.to_be_bytes()[1])); + } + self.registers.set_flag(FlagRegister::Zero, self.registers.get(reg1) == 0); + self.registers.set_flag(FlagRegister::Carry, self.registers.get(reg1) == 0); + }, + OpcodeParameter::Register_U8(reg1, val) => { + self.registers.increment(Register::PC, 1); + let val1 = self.registers.get(reg1); + let val2 = val as u16; + self.registers.set(reg1, val1 + val2); + self.registers.set_flag(FlagRegister::HalfCarry, add_half_carry(val1.to_be_bytes()[1], val2.to_be_bytes()[1])); + self.registers.set_flag(FlagRegister::Zero, self.registers.get(reg1) == 0); + self.registers.set_flag(FlagRegister::Carry, self.registers.get(reg1) == 0); + }, + OpcodeParameter::Register_I8(reg1, value) => { + self.registers.increment(Register::PC, 1); + let val1 = self.registers.get(reg1) as i16; + let val2 = value as i16; + self.registers.set(reg1, (val1 + val2) as u16); + self.registers.set_flag(FlagRegister::HalfCarry, add_half_carry(val1.to_be_bytes()[1], val2.to_be_bytes()[1])); + self.registers.set_flag(FlagRegister::Zero, self.registers.get(reg1) == 0); + self.registers.set_flag(FlagRegister::Carry, self.registers.get(reg1) == 0); + }, + _ => {}, + }; + }, + Opcode::SUB(params) => { + self.registers.increment(Register::PC, 1); + self.registers.set_flag(FlagRegister::Substract, true); + match params { + OpcodeParameter::Register_Register(reg1, reg2) => { + if reg1.is_8bit() && reg2.is_8bit() { + let carry = self.registers.get(reg2) > self.registers.get(reg1); + self.registers.set_flag(FlagRegister::Carry, carry); + self.registers.set_flag(FlagRegister::HalfCarry, sub_half_carry(self.registers.get_8bit(reg1), self.registers.get_8bit(reg2))); + let mut val1 = self.registers.get(reg1); + let val2 = self.registers.get(reg2); + if carry { + val1 = val1 | 0x100; + } + self.registers.set(reg1, val1 - val2); + } else if reg1.is_16bit() && reg2.is_16bit() { + let mut val1 = self.registers.get(reg1) as u32; + let val2 = self.registers.get(reg2) as u32; + let carry = val2 > val1; + if carry { + val1 = val1 | 0x10000; + } + let result = val1 - val2; + self.registers.set(reg1, join_bytes(result.to_be_bytes()[2], result.to_be_bytes()[3])); + self.registers.set_flag(FlagRegister::Carry, carry); + self.registers.set_flag(FlagRegister::HalfCarry, sub_half_carry(val1.to_be_bytes()[2], val2.to_be_bytes()[2])); + } else if reg1.is_8bit() && reg2.is_16bit() { + let mut val1 = self.registers.get(reg1) as u16; + let val2 = bus.read(self.registers.get(reg2)) as u16; + let carry = val2 > val1; + if carry { + val1 = val1 | 0x100; + } + self.registers.set(reg1, val1 - val2); + self.registers.set_flag(FlagRegister::HalfCarry, sub_half_carry(val1.to_be_bytes()[1], val2.to_be_bytes()[1])); + self.registers.set_flag(FlagRegister::Carry, carry); + } + self.registers.set_flag(FlagRegister::Zero, self.registers.get(reg1) == 0); + }, + OpcodeParameter::Register_U8(reg1, val) => { + self.registers.increment(Register::PC, 1); + let mut val1 = self.registers.get(reg1) as u16; + let val2 = val as u16; + let carry = val2 > val1; + if carry { + val1 = val1 | 0x100; + } + let result = val1 - val2; + self.registers.set(reg1, join_bytes(result.to_be_bytes()[0], result.to_be_bytes()[1])); + self.registers.set_flag(FlagRegister::HalfCarry, sub_half_carry(val1.to_be_bytes()[1], val2.to_be_bytes()[1])); + self.registers.set_flag(FlagRegister::Zero, self.registers.get(reg1) == 0); + self.registers.set_flag(FlagRegister::Carry, carry); + }, + _ => {}, + }; + }, // Increment by 1 Opcode::INC(affect_flags, register) => { let prev_value = self.registers.get(register); @@ -610,7 +735,8 @@ impl CPU { self.registers.increment(Register::PC, 1); }, Opcode::NOP => self.registers.increment(Register::PC, 1), - _ => println!("Illegal instruction"), + // _ => println!("Illegal instruction"), + _ => {}, }; } @@ -736,6 +862,11 @@ impl CPU { 0x85 => Opcode::ADD(OpcodeParameter::Register_Register(Register::A, Register::L)), 0x86 => Opcode::ADD(OpcodeParameter::Register_Register(Register::A, Register::HL)), 0xC6 => Opcode::ADD(OpcodeParameter::Register_U8(Register::A, params.1)), + 0x09 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::BC)), + 0x19 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::DE)), + 0x29 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::HL)), + 0x39 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::SP)), + 0xE8 => Opcode::ADD(OpcodeParameter::Register_I8(Register::HL, params.1 as i8)), 0x8F => Opcode::ADC(OpcodeParameter::Register_Register(Register::A, Register::A)), 0x88 => Opcode::ADC(OpcodeParameter::Register_Register(Register::A, Register::B)), 0x89 => Opcode::ADC(OpcodeParameter::Register_Register(Register::A, Register::C)), @@ -823,11 +954,6 @@ impl CPU { 0x1B => Opcode::DEC(false, Register::DE), 0x2B => Opcode::DEC(false, Register::HL), 0x3B => Opcode::DEC(false, Register::SP), - 0x09 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::BC)), - 0x19 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::DE)), - 0x29 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::HL)), - 0x39 => Opcode::ADD(OpcodeParameter::Register_Register(Register::HL, Register::SP)), - 0xE8 => Opcode::ADD(OpcodeParameter::Register_I8(Register::HL, params.1)), 0x27 => Opcode::DAA, 0x2F => Opcode::CPL, 0x3F => Opcode::CCF, @@ -947,8 +1073,7 @@ mod tests { } #[test] - fn test_cpu_instructions() { - // LD + fn test_ld_instructions() { let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::A, 0xFF); @@ -1019,8 +1144,10 @@ mod tests { cpu.exec(Opcode::LD(OpcodeParameter::Register_FF00plusU8(Register::A, 4)), &mut bus); assert_eq!(cpu.registers.get(Register::A), 0xF1); assert_eq!(cpu.registers.get(Register::PC), 0x102); + } - // LDI + #[test] + fn test_ldi_instructions() { let mut bus = Bus::new(); let mut cpu = CPU::new(); let addr = 0xC000; @@ -1033,13 +1160,52 @@ mod tests { assert_eq!(cpu.registers.get(Register::HL), addr + 1); assert_eq!(cpu.registers.get(Register::PC), 0x101); - // JP + let mut bus = Bus::new(); + let mut cpu = CPU::new(); + let addr = 0xC000; + cpu.registers.set(Register::A, 0x1F); + cpu.registers.set(Register::HL, addr); + cpu.exec(Opcode::LDI(OpcodeParameter::RegisterIncrement_Register(Register::HL, Register::A)), &mut bus); + assert_eq!(bus.read(addr), 0x1F); + assert_eq!(cpu.registers.get(Register::HL), addr + 1); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + } + + #[test] + fn test_ldd_instructions() { + let mut bus = Bus::new(); + let mut cpu = CPU::new(); + let addr = 0xC000; + cpu.registers.set(Register::A, 0x00); + cpu.registers.set(Register::HL, addr); + bus.write(addr, 0xF1); + cpu.exec(Opcode::LDD(OpcodeParameter::Register_RegisterDecrement(Register::A, Register::HL)), &mut bus); + assert_eq!(bus.read(addr), 0xF1); + assert_eq!(cpu.registers.get(Register::A), 0xF1); + assert_eq!(cpu.registers.get(Register::HL), addr - 1); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + + let mut bus = Bus::new(); + let mut cpu = CPU::new(); + let addr = 0xC000; + cpu.registers.set(Register::A, 0x1F); + cpu.registers.set(Register::HL, addr); + cpu.exec(Opcode::LDD(OpcodeParameter::RegisterDecrement_Register(Register::HL, Register::A)), &mut bus); + assert_eq!(bus.read(addr), 0x1F); + assert_eq!(cpu.registers.get(Register::HL), addr - 1); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + } + + #[test] + fn test_jp_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); cpu.exec(Opcode::JP(OpcodeParameter::U16(0x1F1F)), &mut bus); assert_eq!(cpu.registers.get(Register::PC), 0x1F1F); + } - // JR + #[test] + fn test_jr_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); cpu.registers.set(Register::PC, 100); @@ -1074,15 +1240,19 @@ mod tests { cpu.registers.set_flag(FlagRegister::Zero, false); cpu.exec(Opcode::JR(OpcodeParameter::FlagRegisterReset_I8(FlagRegister::Zero, 5)), &mut bus); assert_eq!(cpu.registers.get(Register::PC), 105 + 2); + } - // DI + #[test] + fn test_di_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); cpu.exec(Opcode::DI, &mut bus); assert_eq!(bus.read(0xFFFF), 0x00); assert_eq!(cpu.registers.get(Register::PC), 0x101); + } - // RLCA + #[test] + fn test_rlca_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); cpu.registers.set_flag(FlagRegister::Carry, false); @@ -1091,6 +1261,7 @@ mod tests { assert_eq!(cpu.registers.get(Register::A), 0b00000010); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), false); assert_eq!(cpu.registers.get(Register::PC), 0x101); + let mut cpu = CPU::new(); cpu.registers.set_flag(FlagRegister::Carry, false); cpu.registers.set(Register::A, 0b00000001); @@ -1098,8 +1269,11 @@ mod tests { assert_eq!(cpu.registers.get(Register::A), 0b00000001); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), true); assert_eq!(cpu.registers.get(Register::PC), 0x101); + } - // RRCA + #[test] + fn test_rrca_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::A, 0b01000000); cpu.registers.set_flag(FlagRegister::Carry, false); @@ -1107,6 +1281,7 @@ mod tests { assert_eq!(cpu.registers.get(Register::A), 0b01000000); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), false); assert_eq!(cpu.registers.get(Register::PC), 0x101); + let mut cpu = CPU::new(); cpu.registers.set_flag(FlagRegister::Carry, false); cpu.registers.set(Register::A, 0b10000000); @@ -1114,8 +1289,11 @@ mod tests { assert_eq!(cpu.registers.get(Register::A), 0b10000000); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), true); assert_eq!(cpu.registers.get(Register::PC), 0x101); + } - // CALL + #[test] + fn test_call_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); let sp = 0xFFDF; cpu.registers.set(Register::SP, sp); @@ -1162,8 +1340,11 @@ mod tests { // assert_eq!(bus.read_16bit(sp - 2), 0x1234 + 3); assert_eq!(cpu.registers.get(Register::SP), sp); assert_eq!(cpu.registers.get(Register::PC), 0x103); + } - // RST + #[test] + fn test_rst_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); let sp = 0xFFDF; cpu.registers.set(Register::SP, sp); @@ -1172,8 +1353,10 @@ mod tests { assert_eq!(bus.read_16bit(sp - 2), 0x1234 + 3); assert_eq!(cpu.registers.get(Register::SP), sp - 2); assert_eq!(cpu.registers.get(Register::PC), 0x00F0); + } - // PUSH + #[test] + fn test_push_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); let addr = 0xD000; @@ -1183,8 +1366,10 @@ mod tests { assert_eq!(bus.read_16bit(addr - 2), 0x1234); assert_eq!(cpu.registers.get(Register::SP), addr - 2); assert_eq!(cpu.registers.get(Register::PC), 0x101); + } - // POP + #[test] + fn test_pop_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); let addr = 0xD000; @@ -1193,8 +1378,10 @@ mod tests { cpu.exec(Opcode::POP(Register::PC), &mut bus); assert_eq!(cpu.registers.get(Register::PC), 0x1234); assert_eq!(cpu.registers.get(Register::SP), addr + 2); + } - // RET + #[test] + fn test_ret_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); let sp = 0xD000; @@ -1203,8 +1390,11 @@ mod tests { cpu.exec(Opcode::RET(OpcodeParameter::NoParam), &mut bus); assert_eq!(cpu.registers.get(Register::PC), 0x1234); assert_eq!(cpu.registers.get(Register::SP), sp + 2); + } - // AND + #[test] + fn test_and_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::B, 0xF1); cpu.registers.set(Register::C, 0x1F); @@ -1274,8 +1464,11 @@ mod tests { assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), true); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), false); assert_eq!(cpu.registers.get(Register::PC), 0x102); + } - // OR + #[test] + fn test_or_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::B, 0xF1); cpu.registers.set(Register::C, 0x1F); @@ -1345,8 +1538,11 @@ mod tests { assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), false); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), false); assert_eq!(cpu.registers.get(Register::PC), 0x102); + } - // XOR + #[test] + fn test_xor_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::B, 0xF1); cpu.registers.set(Register::C, 0x1F); @@ -1416,8 +1612,11 @@ mod tests { assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), false); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), false); assert_eq!(cpu.registers.get(Register::PC), 0x102); + } - // CP + #[test] + fn test_cp_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::B, 0xF1); cpu.exec(Opcode::CP(OpcodeParameter::Register_U8(Register::B, 0xF1)), &mut bus); @@ -1513,8 +1712,125 @@ mod tests { assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), false); assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), true); assert_eq!(cpu.registers.get(Register::PC), 0x101); + } - // INC + #[test] + fn test_add_instructions() { + let mut bus = Bus::new(); + let mut cpu = CPU::new(); + cpu.registers.set(Register::B, 0b00001000); + cpu.registers.set(Register::C, 0b00001000); + cpu.exec(Opcode::ADD(OpcodeParameter::Register_Register(Register::B, Register::C)), &mut bus); + assert_eq!(cpu.registers.get(Register::B), 0b00010000); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::Substract), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), false); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + + let mut cpu = CPU::new(); + cpu.registers.set(Register::B, 0b10000000); + cpu.registers.set(Register::C, 0b10000000); + cpu.exec(Opcode::ADD(OpcodeParameter::Register_Register(Register::B, Register::C)), &mut bus); + assert_eq!(cpu.registers.get(Register::B), 0); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Substract), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), true); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + + let mut cpu = CPU::new(); + let mut bus = Bus::new(); + let addr = 0xC000; + cpu.registers.set(Register::B, 40); + cpu.registers.set(Register::HL, addr); + bus.write(addr, 40); + cpu.exec(Opcode::ADD(OpcodeParameter::Register_Register(Register::B, Register::HL)), &mut bus); + assert_eq!(cpu.registers.get(Register::B), 80); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + + let mut cpu = CPU::new(); + cpu.registers.set(Register::B, 40); + cpu.exec(Opcode::ADD(OpcodeParameter::Register_U8(Register::B, 40)), &mut bus); + assert_eq!(cpu.registers.get(Register::B), 80); + assert_eq!(cpu.registers.get(Register::PC), 0x102); + + let mut cpu = CPU::new(); + cpu.registers.set(Register::B, 40); + cpu.exec(Opcode::ADD(OpcodeParameter::Register_I8(Register::B, -40 as i8)), &mut bus); + assert_eq!(cpu.registers.get(Register::B), 0); + assert_eq!(cpu.registers.get(Register::PC), 0x102); + + let mut cpu = CPU::new(); + cpu.registers.set(Register::BC, 0b0000100000000000); + cpu.registers.set(Register::HL, 0b0000100000000000); + cpu.exec(Opcode::ADD(OpcodeParameter::Register_Register(Register::BC, Register::HL)), &mut bus); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), true); + assert_eq!(cpu.registers.get(Register::BC), 0b0001000000000000); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + } + + #[test] + fn test_sub_instructions() { + let mut bus = Bus::new(); + let mut cpu = CPU::new(); + cpu.registers.set(Register::B, 0b00001000); + cpu.registers.set(Register::C, 0b00001000); + cpu.exec(Opcode::SUB(OpcodeParameter::Register_Register(Register::B, Register::C)), &mut bus); + assert_eq!(cpu.registers.get(Register::B), 0); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Substract), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), false); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + + let mut cpu = CPU::new(); + cpu.registers.set(Register::B, 0b00010000); + cpu.registers.set(Register::C, 0b00011000); + cpu.exec(Opcode::SUB(OpcodeParameter::Register_Register(Register::B, Register::C)), &mut bus); + assert_eq!(cpu.registers.get(Register::B), 248); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::Substract), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), true); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + + let mut cpu = CPU::new(); + let mut bus = Bus::new(); + let addr = 0xC000; + cpu.registers.set(Register::B, 40); + cpu.registers.set(Register::HL, addr); + bus.write(addr, 40); + cpu.exec(Opcode::SUB(OpcodeParameter::Register_Register(Register::B, Register::HL)), &mut bus); + assert_eq!(cpu.registers.get_flag(FlagRegister::Substract), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), true); + assert_eq!(cpu.registers.get(Register::B), 0); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + + let mut cpu = CPU::new(); + cpu.registers.set(Register::B, 40); + cpu.exec(Opcode::SUB(OpcodeParameter::Register_U8(Register::B, 40)), &mut bus); + assert_eq!(cpu.registers.get_flag(FlagRegister::Substract), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), true); + assert_eq!(cpu.registers.get(Register::B), 0); + assert_eq!(cpu.registers.get(Register::PC), 0x102); + + let mut cpu = CPU::new(); + cpu.registers.set(Register::BC, 0b0001000000000000); + cpu.registers.set(Register::HL, 0b0100100000000000); + cpu.exec(Opcode::SUB(OpcodeParameter::Register_Register(Register::BC, Register::HL)), &mut bus); + assert_eq!(cpu.registers.get_flag(FlagRegister::Substract), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Zero), false); + assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), true); + assert_eq!(cpu.registers.get_flag(FlagRegister::Carry), true); + assert_eq!(cpu.registers.get(Register::BC), 0b1100100000000000); + assert_eq!(cpu.registers.get(Register::PC), 0x101); + } + + #[test] + fn test_inc_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::A, 0); cpu.exec(Opcode::INC(true, Register::A), &mut bus); @@ -1537,8 +1853,11 @@ mod tests { assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), true); assert_eq!(cpu.registers.get(Register::HL), 0b0001000000000000); assert_eq!(cpu.registers.get(Register::PC), 0x101); + } - // DEC + #[test] + fn test_dec_instructions() { + let mut bus = Bus::new(); let mut cpu = CPU::new(); cpu.registers.set(Register::A, 1); cpu.exec(Opcode::DEC(true, Register::A), &mut bus); @@ -1563,8 +1882,10 @@ mod tests { assert_eq!(cpu.registers.get_flag(FlagRegister::HalfCarry), true); assert_eq!(cpu.registers.get(Register::HL), 0b0000111111111111); assert_eq!(cpu.registers.get(Register::PC), 0x101); + } - // NOP + #[test] + fn test_nop_instructions() { let mut cpu = CPU::new(); let mut bus = Bus::new(); cpu.exec(Opcode::NOP, &mut bus); diff --git a/src/utils.rs b/src/utils.rs index 6caf1b9..369e483 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -49,6 +49,19 @@ pub fn sub_half_carry(byte1: u8, byte2: u8) -> bool { byte2 > byte1 } +pub fn add_half_carry_16bit(byte1: u16, byte2: u16) -> bool { + let byte1 = byte1 & 0b0000111111111111; + let byte2 = byte2 & 0b0000111111111111; + let result = byte1 + byte2; + get_bit(result.to_be_bytes()[0], BitIndex::I4) +} + +pub fn sub_half_carry_16bit(byte1: u16, byte2: u16) -> bool { + let byte1 = byte1 & 0b0000111111111111; + let byte2 = byte2 & 0b0000111111111111; + byte2 > byte1 +} + #[cfg(test)] mod tests { use super::*; @@ -115,8 +128,18 @@ mod tests { assert_eq!(add_half_carry(0b00000100, 0b00001000), false); assert_eq!(add_half_carry(0b00001111, 0b00000001), true); + assert_eq!(add_half_carry_16bit(0b1010101000000000, 0b1111111100000000), true); + assert_eq!(add_half_carry_16bit(0b0000010000000000, 0b0000110000000000), true); + assert_eq!(add_half_carry_16bit(0b0000010000000000, 0b0000010000000000), false); + assert_eq!(add_half_carry_16bit(0b0000010000000000, 0b0000100000000000), false); + assert_eq!(add_half_carry_16bit(0b0000111100000000, 0b0000000100000000), true); + assert_eq!(sub_half_carry(0b00010000, 0b00001000), true); assert_eq!(sub_half_carry(0b00000000, 0b00000001), true); assert_eq!(sub_half_carry(0b00001000, 0b00001000), false); + + assert_eq!(sub_half_carry_16bit(0b0001000000000000, 0b0000100000000000), true); + assert_eq!(sub_half_carry_16bit(0b0000000000000000, 0b0000000100000000), true); + assert_eq!(sub_half_carry_16bit(0b0000100000000000, 0b0000100000000000), false); } }