Unofficial instruction set
This commit is contained in:
parent
0ac1511078
commit
5524c2668c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user