use crate::cpu::op::Operand; use crate::cpu::{Cpu, CpuInternals, CpuStatus}; fn is_sign_overflow(val1: u8, val2: u8, result: u8) -> bool { (val1 & 0x80 == val2 & 0x80) && (val1 & 0x80 != result & 0x80) } impl Cpu { fn add_with_carry(&mut self, value: u8) { let a = self.registers.a; let addition = a.wrapping_add(value); let mut overflow = value < a; let result = addition.wrapping_add(self.get_status_flag_u8(CpuStatus::Carry)); if result < addition { // The addition resulted in a smaller number, there was overflow overflow = true; } self.registers.a = result; self.set_status_flag(CpuStatus::Carry, overflow); self.set_status_flag(CpuStatus::Overflow, is_sign_overflow(a, value, result)); } fn set_common_flags(&mut self, result: u8) { self.set_status_flag(CpuStatus::Zero, result == 0); self.set_status_flag(CpuStatus::Negative, result & 0x80 != 0); } // ADC operations /// Add with carry to accumulator fn op_adc(&mut self, operand: Operand) { let value = operand.read(self); self.add_with_carry(value); } /// Unofficial, stores A, X and (high byte of address + 1) /// Unstable in the hardware fn op_ahx(&mut self, operand: Operand) { assert!(operand.is_address()); let addr = operand.value; let a = self.registers.a; let x = self.registers.x; let h = (addr >> 8) as u8; let result = a & x & h; operand.write(result, self); } /// Unofficial, AND + LSR fn op_alr(&mut self, operand: Operand) { let value = operand.read(self); let a = self.registers.a; let result = a & value; // Sets the dropped bit in the carry register self.set_status_flag_u8(CpuStatus::Carry, result & 0x01); let result_shift = result >> 1; operand.write(result_shift, self); self.set_common_flags(result_shift); } /// Unofficial, bitwise AND and set carry from shift left fn op_anc(&mut self, operand: Operand) { let value = operand.read(self); let a = self.registers.a; let result = a & value; self.registers.a = result; self.set_common_flags(result); self.set_status_flag_u8(CpuStatus::Carry, result & 0x80); } /// Bitwise AND with accumulator fn op_and(&mut self, operand: Operand) { let value = operand.read(self); let a = self.registers.a; let result = a & value; self.registers.a = result; self.set_common_flags(result); } /// Unofficial, depends on analog effects and cannot be emulated easily. fn op_ane(&self, _: Operand) { assert!(false); } /// Unofficial, AND + ROR fn op_arr(&mut self, operand: Operand) { let value = operand.read(self); let a = self.registers.a; let carry = self.get_status_flag_u8(CpuStatus::Carry); let result = a & value; let result_shift = result >> 1 | (carry << 7); self.registers.a = result_shift; let result_added = result.wrapping_add(value); self.set_common_flags(result_shift); self.set_status_flag_u8(CpuStatus::Carry, result & 0x01); self.set_status_flag( CpuStatus::Overflow, is_sign_overflow(result, value, result_added), ); } /// Arithmetic shift left fn op_asl(&mut self, operand: Operand) { let value = operand.read(self); let result = value << 1; operand.write(result, self); self.set_common_flags(result); self.set_status_flag_u8(CpuStatus::Carry, value & 0x80); } /// Compare to accumulator fn op_cmp(&mut self, operand: Operand) { let value = operand.read(self); let a = self.registers.a; let result = a.wrapping_sub(value); self.set_status_flag(CpuStatus::Carry, a >= value); self.set_common_flags(result); } /// Bitwise exclusive OR with accumulator fn op_eor(&mut self, operand: Operand) { let value = operand.read(self); let a = self.registers.a; let result = a ^ value; self.registers.a = result; self.set_common_flags(result); } /// Load to accumulator fn op_lda(&mut self, operand: Operand) { let value = operand.read(self); self.registers.a = value; self.set_common_flags(value); } /// Bitwise OR with accumulator fn op_ora(&mut self, operand: Operand) { let value = operand.read(self); let a = self.registers.a; let result = a | value; self.registers.a = result; } /// Subtract with carry from accumulator fn op_sbc(&mut self, operand: Operand) { let value = operand.read(self); self.add_with_carry(!value); } /// Store accumulator fn op_sta(&mut self, operand: Operand) { assert!(operand.is_address()); let a = self.registers.a; operand.write(a, self); // TODO: C code enabled page crossing in the operand, but I didn't find it in the docs } }