From 5524c2668c32cd23d9251f1bdb80255a03ea3f86 Mon Sep 17 00:00:00 2001 From: william Date: Sun, 12 Jan 2025 13:56:42 -0500 Subject: [PATCH] Unofficial instruction set --- core/src/cpu/operations.rs | 189 ++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) diff --git a/core/src/cpu/operations.rs b/core/src/cpu/operations.rs index 02580c6..ae3b5a4 100644 --- a/core/src/cpu/operations.rs +++ b/core/src/cpu/operations.rs @@ -25,6 +25,23 @@ impl Cpu { self.set_status_flag(CpuStatus::Overflow, is_sign_overflow(a, value, result)); } + fn sub_with_carry(&mut self, value: u8) { + let a = self.registers.a; + + let subtraction = a.wrapping_sub(value); + let mut overflow = value > a; + + let result = subtraction.wrapping_sub(self.get_status_flag_u8(CpuStatus::Carry)); + if result > subtraction { + // The subtraction resulted in a higher 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 branch(&mut self, operand: Operand, condition: bool) { let mut cycle_count = 2; @@ -263,6 +280,20 @@ impl Cpu { self.set_common_flags(result); } + /// Unofficial, DEC + CMP + fn op_dcp(&mut self, operand: Operand) { + let value = operand.read(self); + let a = self.registers.a; + + let result = value.wrapping_sub(1); + operand.write(result, self); + + let cmp_result = a.wrapping_sub(result); + + self.set_status_flag(CpuStatus::Carry, a >= result); + self.set_common_flags(result); + } + /// Decrement memory fn op_dec(&mut self, operand: Operand) { let value = operand.read(self); @@ -334,6 +365,18 @@ impl Cpu { self.set_common_flags(result); } + /// Unofficial, INC + SBC + fn op_isc(&mut self, operand: Operand) { + let value = operand.read(self); + let a = self.registers.a; + let c = self.get_status_flag_u8(CpuStatus::Carry); + + let result = value.wrapping_add(1); + operand.write(result, self); + + self.sub_with_carry(!result); + } + /// Jump fn op_jmp(&mut self, operand: Operand, addr_mode: AddressingMode) { let value = operand.value; @@ -365,6 +408,34 @@ impl Cpu { // TODO: Cycle count } + /// Unofficial, LDA and TSX + fn op_las(&mut self, operand: Operand) { + let value = operand.read(self); + let sp = self.registers.sp; + + let result = value & sp; + self.registers.a = result; + self.registers.x = result; + self.registers.sp = result; + + self.set_common_flags(result) + } + + /// Unofficial, LDA + LDX + fn op_lax(&mut self, operand: Operand) { + let value = operand.read(self); + + self.registers.a = value; + self.registers.x = value; + + self.set_common_flags(value); + } + + /// Unofficial and highly unstable, involve analog effects and won't be emulated + fn op_lxa(&mut self, operand: Operand) { + assert!(false); + } + /// Load to accumulator fn op_lda(&mut self, operand: Operand) { let value = operand.read(self); @@ -457,6 +528,22 @@ impl Cpu { // TODO: Cycle count (4) } + /// Unofficial, ROL + AND + fn op_rla(&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 = (value << 1) | carry; + operand.write(result, self); + + let and_result = a & result; + self.registers.a = and_result; + + self.set_common_flags(and_result); + self.set_status_flag_u8(CpuStatus::Carry, value & 0x80); + } + /// Rotate left fn op_rol(&mut self, operand: Operand) { let value = operand.read(self); @@ -481,6 +568,18 @@ impl Cpu { self.set_status_flag_u8(CpuStatus::Carry, value & 0x01); } + // Unofficial, ROR + ADC + fn op_rra(&mut self, operand: Operand) { + let value = operand.read(self); + let carry = self.get_status_flag_u8(CpuStatus::Carry); + + let result = (value >> 1) | (carry << 7); + operand.write(result, self); + + self.set_status_flag_u8(CpuStatus::Carry, value & 0x01); + self.add_with_carry(result); + } + /// Return from interrupt fn op_rti(&mut self, operand: Operand) { let current_status = self.registers.status & 0b00110000; @@ -505,10 +604,32 @@ impl Cpu { // TODO: Cycle count (6) } + /// Unofficial, M = A & X + fn op_sax(&mut self, operand: Operand) { + let a = self.registers.a; + let x = self.registers.x; + + let result = a & x; + operand.write(result, self); + } + /// Subtract with carry from accumulator fn op_sbc(&mut self, operand: Operand) { let value = operand.read(self); - self.add_with_carry(!value); + self.sub_with_carry(!value); + } + + /// Unofficial, CMP + DEX, flags like CMP + fn op_sbx(&mut self, operand: Operand) { + let value = operand.read(self); + let a = self.registers.a; + let x = self.registers.x; + + let result = (a & x).wrapping_sub(value); + self.registers.x = result; + + self.set_status_flag(CpuStatus::Carry, a >= value); + self.set_common_flags(result); } /// Set carry flag @@ -532,6 +653,54 @@ impl Cpu { // TODO: Cycle count (2) } + /// Unofficial and unstable, M = X & (high byte + 1) + fn op_shx(&mut self, operand: Operand) { + let value = ((operand.value & 0xFF) >> 8) as u8; + let x = self.registers.x; + + let result = x | value; + operand.write(result, self); + } + + /// Unofficial and unstable, M = Y & (high byte + 1) + fn op_shy(&mut self, operand: Operand) { + let value = ((operand.value & 0xFF) >> 8) as u8; + let y = self.registers.y; + + let result = y | value; + operand.write(result, self); + } + + /// Unofficial, ASL + ORA + fn op_slo(&mut self, operand: Operand) { + let value = operand.read(self); + let a = self.registers.a; + + let result = value << 1; + operand.write(result, self); + + let ora_result = a | result; + self.registers.a = ora_result; + + self.set_common_flags(ora_result); + self.set_status_flag_u8(CpuStatus::Carry, value & 0x80); + } + + /// Unofficial, LSR + EOR + fn op_sre(&mut self, operand: Operand) { + let value = operand.read(self); + let a = self.registers.a; + + let result = value >> 1; + operand.write(result, self); + + let or_result = a ^ result; + self.registers.a = or_result; + + self.set_common_flags(or_result); + self.set_status_flag_u8(CpuStatus::Carry, value & 0x1); + } + /// Store accumulator fn op_sta(&mut self, operand: Operand) { assert!(operand.is_address()); @@ -541,6 +710,11 @@ impl Cpu { // TODO: C code enabled page crossing in the operand, but I didn't find it in the docs } + /// Stop + fn op_stp(&mut self, operand: Operand) { + // TODO: Freeze the CPU and requires reset + } + /// Store X fn op_stx(&mut self, operand: Operand) { assert!(operand.is_address()); @@ -557,6 +731,19 @@ impl Cpu { operand.write(y, self); } + /// Unofficial and unstable, SP = A & X, M = A & X & (H + 1) + fn op_tas(&mut self, operand: Operand) { + let h = (operand.value >> 8) as u8; + let a = self.registers.a; + let x = self.registers.x; + + let sp = a & x; + let result = a & x & (h.wrapping_add(1)); + + self.registers.sp = sp; + operand.write(result, self); + } + /// Transfer A to X fn op_tax(&mut self, operand: Operand) { let a = self.registers.a;