mirror of
https://github.com/FranLMSP/snes.git
synced 2026-01-01 07:21:35 -05:00
decouple cycle increment logic from cpu struct (#1)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use super::cpu::CPU;
|
||||
use crate::utils::addressing::{AddressingMode, IndexRegister};
|
||||
|
||||
use crate::cpu::registers::Registers;
|
||||
|
||||
type A = AddressingMode;
|
||||
type I = IndexRegister;
|
||||
|
||||
@@ -42,396 +43,433 @@ const COMP_INDEX_CONDITIONS: [Condition; 2] = [
|
||||
Condition::IndexCrossesPageBoundary,
|
||||
];
|
||||
|
||||
impl CPU {
|
||||
fn common_conditions(&mut self, addressing_mode: AddressingMode, conditions: &[Condition]) -> (u16, usize) {
|
||||
let mut bytes = 0;
|
||||
let mut cycles = 0;
|
||||
fn common_conditions(cpu_registers: &Registers, addressing_mode: AddressingMode, conditions: &[Condition]) -> (u16, usize) {
|
||||
let mut bytes = 0;
|
||||
let mut cycles = 0;
|
||||
|
||||
for condition in conditions {
|
||||
match condition {
|
||||
// Add 1 byte and 1 cycle if m = 0 (16-bit memory/accumulator)
|
||||
Condition::MemorySelectFlag => {
|
||||
if self.registers.is_16bit_mode() {
|
||||
cycles += 1;
|
||||
match addressing_mode {
|
||||
A::Immediate => bytes += 1,
|
||||
_ => {},
|
||||
for condition in conditions {
|
||||
match condition {
|
||||
// Add 1 byte and 1 cycle if m = 0 (16-bit memory/accumulator)
|
||||
Condition::MemorySelectFlag => {
|
||||
if cpu_registers.is_16bit_mode() {
|
||||
cycles += 1;
|
||||
match addressing_mode {
|
||||
A::Immediate => bytes += 1,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
// Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)
|
||||
Condition::DirectPageIsZero => {
|
||||
match addressing_mode {
|
||||
A::DirectPage | A::DirectPageIndirect | A::DirectPageIndirectLong |
|
||||
A::DirectPageIndexed(_) | A::DirectPageIndexedIndirect(_) |
|
||||
A::DirectPageIndirectIndexed(_) |
|
||||
A::DirectPageIndirectLongIndexed(_) => {
|
||||
if cpu_registers.direct_page_low() != 0 {
|
||||
cycles += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
// Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)
|
||||
Condition::DirectPageIsZero => {
|
||||
match addressing_mode {
|
||||
A::DirectPage | A::DirectPageIndirect | A::DirectPageIndirectLong |
|
||||
A::DirectPageIndexed(_) | A::DirectPageIndexedIndirect(_) |
|
||||
A::DirectPageIndirectIndexed(_) |
|
||||
A::DirectPageIndirectLongIndexed(_) => {
|
||||
if self.registers.direct_page_low() != 0 {
|
||||
cycles += 1;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
// Add 1 cycle if adding index crosses a page boundary
|
||||
Condition::IndexCrossesPageBoundary => {
|
||||
match addressing_mode {
|
||||
A::AbsoluteIndexed(index) | A::DirectPageIndirectIndexed(index) => {
|
||||
let page = self.registers.get_pc_address() & 0xFF;
|
||||
let index = match index {
|
||||
I::X => self.registers.x,
|
||||
I::Y => self.registers.y,
|
||||
};
|
||||
if (page + index as u32) > 0xFF {
|
||||
cycles += 1
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
// Add 1 cycle if 65C02 and d = 1 (decimal mode, 65C02)
|
||||
Condition::DecimalMode => {
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
cycles += 1;
|
||||
}
|
||||
},
|
||||
// Add 1 byte if <index> = 0 (16-bit index registers)
|
||||
Condition::IndexIs16Bit => {
|
||||
if self.registers.is_16bit_index() {
|
||||
bytes += 1; cycles += 1;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
(bytes, cycles)
|
||||
}
|
||||
|
||||
fn common_bytes_cycles_arithmetic(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
match addressing_mode {
|
||||
A::Immediate => (2, 2),
|
||||
A::Absolute => (3, 4),
|
||||
A::AbsoluteLong => (4, 5),
|
||||
A::DirectPage => (2, 3),
|
||||
A::DirectPageIndirect => (2, 5),
|
||||
A::DirectPageIndirectLong => (2, 6),
|
||||
A::AbsoluteIndexed(_) => (3, 4),
|
||||
A::AbsoluteLongIndexed(_) => (4, 5),
|
||||
A::DirectPageIndexed(_) => (2, 4),
|
||||
A::DirectPageIndexedIndirect(_) => (2, 6),
|
||||
A::DirectPageIndirectIndexed(_) => (2, 5),
|
||||
A::DirectPageIndirectLongIndexed(_) => (2, 6),
|
||||
A::StackRelative => (2, 4),
|
||||
A::StackRelativeIndirectIndexed(_) => (2, 7),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn common_bytes_cycles_shift(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
match addressing_mode {
|
||||
A::Accumulator => (1, 2),
|
||||
A::Absolute => (3, 6),
|
||||
A::DirectPage => (2, 5),
|
||||
// Note: in some documentations you will find that this addressing mode has
|
||||
// 7 cycles for shift instructions, and then it says to substract
|
||||
// 1 cycles if no page boundary is crossed.
|
||||
// But to make it simpler, we are assigning 6 cycles here and then incrementing
|
||||
// it by 1 later if a page boundary is crossed.
|
||||
A::AbsoluteIndexed(_) => (3, 6),
|
||||
A::DirectPageIndexed(_) => (2, 6),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn common_bytes_cycles_bit(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
match addressing_mode {
|
||||
A::Immediate => (2, 2),
|
||||
A::Absolute => (3, 4),
|
||||
A::DirectPage => (2, 3),
|
||||
A::AbsoluteIndexed(_) => (3, 4),
|
||||
A::DirectPageIndexed(_) => (2, 4),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_cycles_arithmetic(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &ALL_CONDITIONS);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_bitwise(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &BITWISE_CONDITIONS);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_shift(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_shift(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
// Add 2 cycles if m = 1
|
||||
let (_, cycles) = self.common_conditions(addressing_mode, &[Condition::MemorySelectFlag]);
|
||||
self.cycles += cycles;
|
||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &BITWISE_CONDITIONS);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_bit(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_bit(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &BITWISE_CONDITIONS);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_clear(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_branch(&mut self) {
|
||||
self.registers.increment_pc(2); self.cycles += 2;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_branch_taken(&mut self, page_boundary_crossed: bool) {
|
||||
self.cycles += 1;
|
||||
if page_boundary_crossed {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_cycles_branch_long(&mut self) {
|
||||
self.registers.increment_pc(3); self.cycles += 4;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_comp_index(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &COMP_INDEX_CONDITIONS);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_inc_dec(&mut self, addressing_mode: AddressingMode) {
|
||||
self.increment_cycles_shift(addressing_mode);
|
||||
}
|
||||
|
||||
pub fn increment_cycles_inc_dec_index(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_nop(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_wdm(&mut self) {
|
||||
self.registers.increment_pc(2); self.cycles += 2;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_jmp(&mut self, addressing_mode: AddressingMode) {
|
||||
let (_, cycles) = match addressing_mode {
|
||||
A::Absolute => (3, 3),
|
||||
A::AbsoluteIndirect => (3, 5),
|
||||
A::AbsoluteIndexedIndirect(_) => (3, 6),
|
||||
A::AbsoluteLong => (4, 4),
|
||||
A::AbsoluteIndirectLong => (3, 6),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
// Add 1 cycle if adding index crosses a page boundary
|
||||
Condition::IndexCrossesPageBoundary => {
|
||||
match addressing_mode {
|
||||
A::AbsoluteIndexed(index) | A::DirectPageIndirectIndexed(index) => {
|
||||
let page = cpu_registers.get_pc_address() & 0xFF;
|
||||
let index = match index {
|
||||
I::X => cpu_registers.x,
|
||||
I::Y => cpu_registers.y,
|
||||
};
|
||||
if (page + index as u32) > 0xFF {
|
||||
cycles += 1
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
// Add 1 cycle if 65C02 and d = 1 (decimal mode, 65C02)
|
||||
Condition::DecimalMode => {
|
||||
if cpu_registers.get_decimal_mode_flag() {
|
||||
cycles += 1;
|
||||
}
|
||||
},
|
||||
// Add 1 byte if <index> = 0 (16-bit index registers)
|
||||
Condition::IndexIs16Bit => {
|
||||
if cpu_registers.is_16bit_index() {
|
||||
bytes += 1; cycles += 1;
|
||||
}
|
||||
},
|
||||
};
|
||||
// Incrementing PC here is kind of irrelevant since we
|
||||
// are performing a JMP anyway.
|
||||
// However, we have to keep in mind PBR if we happen to increment PC at 0xFFFF
|
||||
// self.registers.increment_pc(bytes); // TODO: consider above comment
|
||||
self.cycles += cycles;
|
||||
}
|
||||
|
||||
/// Note: the bytes should be incremented *before* pushing onto the stack
|
||||
pub fn increment_cycles_jsr(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = match addressing_mode {
|
||||
A::Absolute => (3, 6),
|
||||
A::AbsoluteIndexedIndirect(_) => (3, 8),
|
||||
A::AbsoluteLong => (4, 8),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Incrementing PC here is kind of irrelevant since we
|
||||
// are performing a JMP anyway.
|
||||
// However, we have to keep in mind PBR if we happen to increment PC at 0xFFFF
|
||||
// self.registers.increment_pc(bytes); // TODO: consider above comment
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
(bytes, cycles)
|
||||
}
|
||||
|
||||
fn common_bytes_cycles_arithmetic(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
match addressing_mode {
|
||||
A::Immediate => (2, 2),
|
||||
A::Absolute => (3, 4),
|
||||
A::AbsoluteLong => (4, 5),
|
||||
A::DirectPage => (2, 3),
|
||||
A::DirectPageIndirect => (2, 5),
|
||||
A::DirectPageIndirectLong => (2, 6),
|
||||
A::AbsoluteIndexed(_) => (3, 4),
|
||||
A::AbsoluteLongIndexed(_) => (4, 5),
|
||||
A::DirectPageIndexed(_) => (2, 4),
|
||||
A::DirectPageIndexedIndirect(_) => (2, 6),
|
||||
A::DirectPageIndirectIndexed(_) => (2, 5),
|
||||
A::DirectPageIndirectLongIndexed(_) => (2, 6),
|
||||
A::StackRelative => (2, 4),
|
||||
A::StackRelativeIndirectIndexed(_) => (2, 7),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn common_bytes_cycles_shift(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
match addressing_mode {
|
||||
A::Accumulator => (1, 2),
|
||||
A::Absolute => (3, 6),
|
||||
A::DirectPage => (2, 5),
|
||||
// Note: in some documentations you will find that this addressing mode has
|
||||
// 7 cycles for shift instructions, and then it says to substract
|
||||
// 1 cycles if no page boundary is crossed.
|
||||
// But to make it simpler, we are assigning 6 cycles here and then incrementing
|
||||
// it by 1 later if a page boundary is crossed.
|
||||
A::AbsoluteIndexed(_) => (3, 6),
|
||||
A::DirectPageIndexed(_) => (2, 6),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn common_bytes_cycles_bit(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
match addressing_mode {
|
||||
A::Immediate => (2, 2),
|
||||
A::Absolute => (3, 4),
|
||||
A::DirectPage => (2, 3),
|
||||
A::AbsoluteIndexed(_) => (3, 4),
|
||||
A::DirectPageIndexed(_) => (2, 4),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_cycles_arithmetic(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
let (bytes, cycles) = common_bytes_cycles_arithmetic(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (bytes, cycles) = common_conditions(cpu_registers, addressing_mode, &ALL_CONDITIONS);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_bitwise(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
let (bytes, cycles) = common_bytes_cycles_arithmetic(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (bytes, cycles) = common_conditions(cpu_registers, addressing_mode, &BITWISE_CONDITIONS);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_shift(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
let (bytes, cycles) = common_bytes_cycles_shift(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
// Add 2 cycles if m = 1
|
||||
let (_, cycles) = common_conditions(cpu_registers, addressing_mode, &[Condition::MemorySelectFlag]);
|
||||
total_cycles += cycles;
|
||||
let (bytes, cycles) = common_conditions(cpu_registers, addressing_mode, &BITWISE_CONDITIONS);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_bit(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
let (bytes, cycles) = common_bytes_cycles_bit(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (bytes, cycles) = common_conditions(cpu_registers, addressing_mode, &BITWISE_CONDITIONS);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_clear() -> (u16, usize) {
|
||||
(1, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_branch() -> (u16, usize) {
|
||||
(2, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_branch_taken(page_boundary_crossed: bool) -> (u16, usize) {
|
||||
let mut total_cycles = 1;
|
||||
if page_boundary_crossed {
|
||||
total_cycles += 1;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_lda(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &LDA_CONDITIONS);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
(0, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_ld_index(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &LD_INDEX_CONDITIONS);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
pub fn increment_cycles_branch_long() -> (u16, usize) {
|
||||
(3, 4)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_pea(&mut self) {
|
||||
self.registers.increment_pc(3); self.cycles += 5;
|
||||
}
|
||||
pub fn increment_cycles_comp_index(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
pub fn increment_cycles_pei(&mut self) {
|
||||
self.registers.increment_pc(2); self.cycles += 6;
|
||||
let (bytes, cycles) = self.common_conditions(
|
||||
AddressingMode::DirectPageIndirect,
|
||||
&[Condition::DirectPageIsZero],
|
||||
);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
let (bytes, cycles) = common_bytes_cycles_arithmetic(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (bytes, cycles) = common_conditions(cpu_registers, addressing_mode, &COMP_INDEX_CONDITIONS);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
pub fn increment_cycles_per(&mut self) {
|
||||
self.registers.increment_pc(3); self.cycles += 6;
|
||||
}
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_pha(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
if self.registers.is_16bit_mode() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
pub fn increment_cycles_inc_dec(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
increment_cycles_shift(cpu_registers, addressing_mode)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_phb(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
}
|
||||
pub fn increment_cycles_inc_dec_index() -> (u16, usize) {
|
||||
(1, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_phd(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 4;
|
||||
}
|
||||
pub fn increment_cycles_nop() -> (u16, usize) {
|
||||
(1, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_phk(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
}
|
||||
pub fn increment_cycles_wdm() -> (u16, usize) {
|
||||
(2, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_php(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
}
|
||||
pub fn increment_cycles_jmp(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let (_, cycles) = match addressing_mode {
|
||||
A::Absolute => (3, 3),
|
||||
A::AbsoluteIndirect => (3, 5),
|
||||
A::AbsoluteIndexedIndirect(_) => (3, 6),
|
||||
A::AbsoluteLong => (4, 4),
|
||||
A::AbsoluteIndirectLong => (3, 6),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Incrementing PC here is kind of irrelevant since we
|
||||
// are performing a JMP anyway.
|
||||
// However, we have to keep in mind PBR if we happen to increment PC at 0xFFFF
|
||||
// self.registers.increment_pc(bytes); // TODO: consider above comment
|
||||
(0, cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_push_index(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
if self.registers.is_16bit_index() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
/// Note: the bytes should be incremented *before* pushing onto the stack
|
||||
pub fn increment_cycles_jsr(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let (bytes, cycles) = match addressing_mode {
|
||||
A::Absolute => (3, 6),
|
||||
A::AbsoluteIndexedIndirect(_) => (3, 8),
|
||||
A::AbsoluteLong => (4, 8),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Incrementing PC here is kind of irrelevant since we
|
||||
// are performing a JMP anyway.
|
||||
// However, we have to keep in mind PBR if we happen to increment PC at 0xFFFF
|
||||
// self.registers.increment_pc(bytes); // TODO: consider above comment
|
||||
(bytes, cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_pla(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 4;
|
||||
if self.registers.is_16bit_mode() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
pub fn increment_cycles_lda(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
pub fn increment_cycles_plb(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 4;
|
||||
}
|
||||
let (bytes, cycles) = common_bytes_cycles_arithmetic(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (bytes, cycles) = common_conditions(cpu_registers, addressing_mode, &LDA_CONDITIONS);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
pub fn increment_cycles_pld(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 5;
|
||||
}
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_plp(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 4;
|
||||
}
|
||||
pub fn increment_cycles_ld_index(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
pub fn increment_cycles_pl_index(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 4;
|
||||
if self.registers.is_16bit_index() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
let (bytes, cycles) = common_bytes_cycles_arithmetic(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (bytes, cycles) = common_conditions(cpu_registers, addressing_mode, &LD_INDEX_CONDITIONS);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
pub fn increment_cycles_rep(&mut self) {
|
||||
self.registers.increment_pc(2); self.cycles += 3;
|
||||
}
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_sep(&mut self) {
|
||||
self.registers.increment_pc(2); self.cycles += 3;
|
||||
}
|
||||
pub fn increment_cycles_pea() -> (u16, usize) {
|
||||
(3, 5)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_return_subroutine(&mut self) {
|
||||
self.cycles += 6;
|
||||
}
|
||||
pub fn increment_cycles_pei(cpu_registers: &Registers) -> (u16, usize) {
|
||||
let mut total_bytes = 2;
|
||||
let mut total_cycles = 6;
|
||||
|
||||
pub fn increment_cycles_return_interrupt(&mut self) {
|
||||
self.cycles += 6;
|
||||
if !self.registers.emulation_mode {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
let (bytes, cycles) = common_conditions(
|
||||
cpu_registers,
|
||||
AddressingMode::DirectPageIndirect,
|
||||
&[Condition::DirectPageIsZero],
|
||||
);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
|
||||
pub fn increment_cycles_set_flag(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_sta(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (_, cycles) = self.common_conditions(addressing_mode, &[
|
||||
Condition::MemorySelectFlag,
|
||||
Condition::DirectPageIsZero,
|
||||
]);
|
||||
self.cycles += cycles;
|
||||
}
|
||||
pub fn increment_cycles_per() -> (u16, usize) {
|
||||
(3, 6)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_st_index(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (_, cycles) = self.common_conditions(addressing_mode, &[
|
||||
Condition::IndexIs16Bit,
|
||||
Condition::DirectPageIsZero,
|
||||
]);
|
||||
self.cycles += cycles;
|
||||
}
|
||||
pub fn increment_cycles_pha(is_16bit_mode: bool) -> (u16, usize) {
|
||||
(1, if is_16bit_mode {4} else {3})
|
||||
}
|
||||
|
||||
pub fn increment_cycles_transfer(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
pub fn increment_cycles_phb() -> (u16, usize) {
|
||||
(1, 3)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_exchange(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
pub fn increment_cycles_phd() -> (u16, usize) {
|
||||
(1, 4)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_xba(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
}
|
||||
pub fn increment_cycles_phk() -> (u16, usize) {
|
||||
(1, 3)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_brk(&mut self) {
|
||||
self.registers.increment_pc(2); self.cycles += 7;
|
||||
if self.registers.emulation_mode {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
pub fn increment_cycles_php() -> (u16, usize) {
|
||||
(1, 3)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_stp(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
}
|
||||
pub fn increment_cycles_push_index(is_16bit_index: bool) -> (u16, usize) {
|
||||
(1, if is_16bit_index {4} else {3})
|
||||
}
|
||||
|
||||
pub fn increment_cycles_while_stopped(&mut self) {
|
||||
self.cycles += 1;
|
||||
}
|
||||
pub fn increment_cycles_pla(is_16bit_mode: bool) -> (u16, usize) {
|
||||
(1, if is_16bit_mode {5} else {4})
|
||||
}
|
||||
|
||||
pub fn increment_cycles_move(&mut self, count: usize) {
|
||||
self.registers.increment_pc(3); self.cycles += 7 * count;
|
||||
}
|
||||
pub fn increment_cycles_plb() -> (u16, usize) {
|
||||
(1, 4)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_test(&mut self, addressing_mode: AddressingMode) {
|
||||
let (bytes, cycles) = match addressing_mode {
|
||||
AddressingMode::Absolute => (3, 6),
|
||||
AddressingMode::DirectPage => (2, 5),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let (_, cycles) = self.common_conditions(addressing_mode, &[
|
||||
Condition::MemorySelectFlag,
|
||||
Condition::DirectPageIsZero,
|
||||
]);
|
||||
self.cycles += cycles;
|
||||
}
|
||||
pub fn increment_cycles_pld() -> (u16, usize) {
|
||||
(1, 5)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_plp() -> (u16, usize) {
|
||||
(1, 4)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_pl_index(is_16bit_index: bool) -> (u16, usize) {
|
||||
(1, if is_16bit_index {5} else {4})
|
||||
}
|
||||
|
||||
pub fn increment_cycles_rep() -> (u16, usize) {
|
||||
(2, 3)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_sep() -> (u16, usize) {
|
||||
(2, 3)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_return_subroutine() -> (u16, usize) {
|
||||
(0, 6)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_return_interrupt(is_emulation_mode: bool) -> (u16, usize) {
|
||||
(0, if is_emulation_mode {7} else {6})
|
||||
}
|
||||
|
||||
pub fn increment_cycles_set_flag() -> (u16, usize) {
|
||||
(1, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_sta(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
let (bytes, cycles) = common_bytes_cycles_arithmetic(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (_, cycles) = common_conditions(cpu_registers, addressing_mode, &[
|
||||
Condition::MemorySelectFlag,
|
||||
Condition::DirectPageIsZero,
|
||||
]);
|
||||
total_cycles += cycles;
|
||||
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_st_index(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
let (bytes, cycles) = common_bytes_cycles_arithmetic(addressing_mode);
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (_, cycles) = common_conditions(cpu_registers, addressing_mode, &[
|
||||
Condition::IndexIs16Bit,
|
||||
Condition::DirectPageIsZero,
|
||||
]);
|
||||
total_cycles += cycles;
|
||||
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_transfer() -> (u16, usize) {
|
||||
(1, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_exchange() -> (u16, usize) {
|
||||
(1, 2)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_xba() -> (u16, usize) {
|
||||
(1, 3)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_brk(is_emulation_mode: bool) -> (u16, usize) {
|
||||
(2, if is_emulation_mode {8} else {7})
|
||||
}
|
||||
|
||||
pub fn increment_cycles_stp() -> (u16, usize) {
|
||||
(1, 3)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_while_stopped() -> (u16, usize) {
|
||||
(0, 1)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_move(count: usize) -> (u16, usize) {
|
||||
(3, 7 * count)
|
||||
}
|
||||
|
||||
pub fn increment_cycles_test(cpu_registers: &Registers, addressing_mode: AddressingMode) -> (u16, usize) {
|
||||
let mut total_bytes = 0;
|
||||
let mut total_cycles = 0;
|
||||
|
||||
let (bytes, cycles) = match addressing_mode {
|
||||
AddressingMode::Absolute => (3, 6),
|
||||
AddressingMode::DirectPage => (2, 5),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
total_bytes += bytes; total_cycles += cycles;
|
||||
let (_, cycles) = common_conditions(cpu_registers, addressing_mode, &[
|
||||
Condition::MemorySelectFlag,
|
||||
Condition::DirectPageIsZero,
|
||||
]);
|
||||
total_cycles += cycles;
|
||||
|
||||
(total_bytes, total_cycles)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -440,73 +478,72 @@ mod cpu_instructions_tests {
|
||||
|
||||
#[test]
|
||||
fn test_common_conditions() {
|
||||
let mut cpu = CPU::new();
|
||||
cpu.registers.emulation_mode = false;
|
||||
let mut registers = Registers::new();
|
||||
registers.emulation_mode = false;
|
||||
|
||||
// 16-bit Memory/accumulator flag condition
|
||||
cpu.registers.pc = 0;
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
let (bytes, cycles) = cpu.common_conditions(AddressingMode::Immediate, &ALL_CONDITIONS);
|
||||
registers.pc = 0;
|
||||
registers.set_decimal_mode_flag(false);
|
||||
registers.set_16bit_mode(false);
|
||||
let (bytes, cycles) = common_conditions(®isters, AddressingMode::Immediate, &ALL_CONDITIONS);
|
||||
assert_eq!(bytes, 0);
|
||||
assert_eq!(cycles, 0);
|
||||
|
||||
cpu.registers.pc = 0;
|
||||
cpu.registers.set_16bit_mode(true);
|
||||
let (bytes, cycles) = cpu.common_conditions(AddressingMode::Immediate, &ALL_CONDITIONS);
|
||||
registers.pc = 0;
|
||||
registers.set_16bit_mode(true);
|
||||
let (bytes, cycles) = common_conditions(®isters, AddressingMode::Immediate, &ALL_CONDITIONS);
|
||||
assert_eq!(bytes, 1);
|
||||
assert_eq!(cycles, 1);
|
||||
|
||||
// Decimal flag condition
|
||||
cpu.registers.pc = 0;
|
||||
cpu.registers.set_16bit_mode(true);
|
||||
cpu.registers.set_decimal_mode_flag(true);
|
||||
let (bytes, cycles) = cpu.common_conditions(AddressingMode::Immediate, &ALL_CONDITIONS);
|
||||
registers.pc = 0;
|
||||
registers.set_16bit_mode(true);
|
||||
registers.set_decimal_mode_flag(true);
|
||||
let (bytes, cycles) = common_conditions(®isters, AddressingMode::Immediate, &ALL_CONDITIONS);
|
||||
assert_eq!(bytes, 1);
|
||||
assert_eq!(cycles, 2);
|
||||
|
||||
// Low byte of direct page register other than zero condition
|
||||
cpu.registers.pc = 0;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
cpu.registers.d = 0x0000;
|
||||
let (bytes, cycles) = cpu.common_conditions(AddressingMode::DirectPage, &ALL_CONDITIONS);
|
||||
registers.pc = 0;
|
||||
registers.set_16bit_mode(false);
|
||||
registers.set_decimal_mode_flag(false);
|
||||
registers.d = 0x0000;
|
||||
let (bytes, cycles) = common_conditions(®isters, AddressingMode::DirectPage, &ALL_CONDITIONS);
|
||||
assert_eq!(bytes, 0);
|
||||
assert_eq!(cycles, 0);
|
||||
|
||||
cpu.registers.pc = 0;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
cpu.registers.d = 0x0001;
|
||||
let (bytes, cycles) = cpu.common_conditions(AddressingMode::DirectPage, &ALL_CONDITIONS);
|
||||
registers.pc = 0;
|
||||
registers.set_16bit_mode(false);
|
||||
registers.set_decimal_mode_flag(false);
|
||||
registers.d = 0x0001;
|
||||
let (bytes, cycles) = common_conditions(®isters, AddressingMode::DirectPage, &ALL_CONDITIONS);
|
||||
assert_eq!(bytes, 0);
|
||||
assert_eq!(cycles, 1);
|
||||
|
||||
// Adding index crosses a page boundary condition
|
||||
cpu.registers.pc = 0xFE;
|
||||
cpu.registers.x = 0x0001;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
let (bytes, cycles) = cpu.common_conditions(AddressingMode::AbsoluteIndexed(IndexRegister::X), &ALL_CONDITIONS);
|
||||
registers.pc = 0xFE;
|
||||
registers.x = 0x0001;
|
||||
registers.set_16bit_mode(false);
|
||||
registers.set_decimal_mode_flag(false);
|
||||
let (bytes, cycles) = common_conditions(®isters, AddressingMode::AbsoluteIndexed(IndexRegister::X), &ALL_CONDITIONS);
|
||||
assert_eq!(bytes, 0);
|
||||
assert_eq!(cycles, 0); // Doesn't cross boundary
|
||||
|
||||
cpu.registers.pc = 0xFE;
|
||||
cpu.registers.x = 0x0010;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
let (bytes, cycles) = cpu.common_conditions(AddressingMode::AbsoluteIndexed(IndexRegister::X), &ALL_CONDITIONS);
|
||||
registers.pc = 0xFE;
|
||||
registers.x = 0x0010;
|
||||
registers.set_16bit_mode(false);
|
||||
registers.set_decimal_mode_flag(false);
|
||||
let (bytes, cycles) = common_conditions(®isters, AddressingMode::AbsoluteIndexed(IndexRegister::X), &ALL_CONDITIONS);
|
||||
assert_eq!(bytes, 0);
|
||||
assert_eq!(cycles, 1); // Crosses boundary
|
||||
|
||||
// Test common and aritmetic together
|
||||
cpu.registers.pc = 0xF5;
|
||||
cpu.registers.x = 0x0010;
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
cpu.increment_cycles_arithmetic(AddressingMode::AbsoluteIndexed(IndexRegister::X));
|
||||
assert_eq!(cpu.registers.pc, 0xF5 + 3);
|
||||
assert_eq!(cpu.cycles, 5);
|
||||
registers.pc = 0xF5;
|
||||
registers.x = 0x0010;
|
||||
registers.set_16bit_mode(false);
|
||||
registers.set_decimal_mode_flag(false);
|
||||
let (bytes, cycles) = increment_cycles_arithmetic(®isters, AddressingMode::AbsoluteIndexed(IndexRegister::X));
|
||||
assert_eq!(bytes, 3);
|
||||
assert_eq!(cycles, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::cpu::CPU;
|
||||
use crate::cpu::bus::Bus;
|
||||
use crate::cpu::dma;
|
||||
use crate::cpu::cycles;
|
||||
use crate::utils::addressing::{AddressingMode, IndexRegister};
|
||||
use crate::utils::alu;
|
||||
use crate::utils::num_trait::SnesNum;
|
||||
@@ -96,7 +97,8 @@ impl CPU {
|
||||
self.registers.set_low_a(result as u8);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_arithmetic(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_arithmetic(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn sbc(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -121,7 +123,8 @@ impl CPU {
|
||||
self.registers.set_low_a(result as u8);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_arithmetic(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_arithmetic(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn do_dec<T: SnesNum>(&mut self, target: T) -> T {
|
||||
@@ -145,7 +148,8 @@ impl CPU {
|
||||
let result = self.do_dec(value).to_u32() as u8;
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
}
|
||||
self.increment_cycles_inc_dec(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_inc_dec(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn dex(&mut self) {
|
||||
@@ -155,7 +159,8 @@ impl CPU {
|
||||
let result = self.do_dec(self.registers.x).to_u32() as u8;
|
||||
self.registers.set_low_x(result);
|
||||
}
|
||||
self.increment_cycles_inc_dec_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_inc_dec_index();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn dey(&mut self) {
|
||||
@@ -165,7 +170,8 @@ impl CPU {
|
||||
let result = self.do_dec(self.registers.y).to_u32() as u8;
|
||||
self.registers.set_low_y(result);
|
||||
}
|
||||
self.increment_cycles_inc_dec_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_inc_dec_index();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn do_inc<T: SnesNum>(&mut self, target: T) -> T {
|
||||
@@ -189,7 +195,8 @@ impl CPU {
|
||||
let result = self.do_inc(value).to_u32() as u8;
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
}
|
||||
self.increment_cycles_inc_dec(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_inc_dec(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn inx(&mut self) {
|
||||
@@ -199,7 +206,8 @@ impl CPU {
|
||||
let result = self.do_inc(self.registers.x).to_u32() as u8;
|
||||
self.registers.set_low_x(result);
|
||||
}
|
||||
self.increment_cycles_inc_dec_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_inc_dec_index();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn iny(&mut self) {
|
||||
@@ -209,7 +217,8 @@ impl CPU {
|
||||
let result = self.do_inc(self.registers.y).to_u32() as u8;
|
||||
self.registers.set_low_y(result);
|
||||
}
|
||||
self.increment_cycles_inc_dec_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_inc_dec_index();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn do_comp<T: SnesNum>(&mut self, target: T, value: T) {
|
||||
@@ -232,7 +241,8 @@ impl CPU {
|
||||
let value = self.get_8bit_from_address(bus, addressing_mode);
|
||||
self.do_comp(target as u8, value);
|
||||
}
|
||||
self.increment_cycles_arithmetic(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_arithmetic(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn cpx(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -245,7 +255,8 @@ impl CPU {
|
||||
let value = self.get_8bit_from_address(bus, addressing_mode);
|
||||
self.do_comp(target as u8, value);
|
||||
}
|
||||
self.increment_cycles_comp_index(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_comp_index(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn cpy(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -258,7 +269,8 @@ impl CPU {
|
||||
let value = self.get_8bit_from_address(bus, addressing_mode);
|
||||
self.do_comp(target as u8, value);
|
||||
}
|
||||
self.increment_cycles_comp_index(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_comp_index(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn and(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -274,7 +286,8 @@ impl CPU {
|
||||
self.registers.set_low_a(result);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_bitwise(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_bitwise(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn ora(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -290,7 +303,8 @@ impl CPU {
|
||||
self.registers.set_low_a(result);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_bitwise(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_bitwise(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn eor(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -306,7 +320,8 @@ impl CPU {
|
||||
self.registers.set_low_a(result);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_bitwise(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_bitwise(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn asl(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -326,7 +341,8 @@ impl CPU {
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_shift(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_shift(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn lsr(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -346,7 +362,8 @@ impl CPU {
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_shift(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_shift(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn do_bit<T: SnesNum>(&mut self, accumulator: T, value: T, addressing_mode: AddressingMode) {
|
||||
@@ -370,7 +387,8 @@ impl CPU {
|
||||
let value = self.get_8bit_from_address(bus, addressing_mode);
|
||||
self.do_bit(self.registers.a as u8, value, addressing_mode);
|
||||
}
|
||||
self.increment_cycles_bit(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_bit(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn do_branch(&mut self, nearlabel: u8) -> bool {
|
||||
@@ -389,63 +407,77 @@ impl CPU {
|
||||
|
||||
fn bcc(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if !self.registers.get_carry_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn bcs(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if self.registers.get_carry_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn beq(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if self.registers.get_zero_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn bne(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if !self.registers.get_zero_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn bmi(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if self.registers.get_negative_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn bpl(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if !self.registers.get_negative_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn bra(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn brl(&mut self, bus: &mut Bus) {
|
||||
@@ -458,49 +490,59 @@ impl CPU {
|
||||
} else {
|
||||
self.registers.increment_pc(label);
|
||||
}
|
||||
self.increment_cycles_branch_long();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_long();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn bvc(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if !self.registers.get_overflow_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn bvs(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
if self.registers.get_overflow_flag() {
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
let (bytes, cycles) = cycles::increment_cycles_branch_taken(page_boundary_crossed);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
fn clc(&mut self) {
|
||||
self.registers.set_carry_flag(false);
|
||||
self.increment_cycles_clear();
|
||||
let (bytes, cycles) = cycles::increment_cycles_clear();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn cld(&mut self) {
|
||||
self.registers.set_decimal_mode_flag(false);
|
||||
self.increment_cycles_clear();
|
||||
let (bytes, cycles) = cycles::increment_cycles_clear();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn cli(&mut self) {
|
||||
self.registers.set_irq_disable_flag(false);
|
||||
self.increment_cycles_clear();
|
||||
let (bytes, cycles) = cycles::increment_cycles_clear();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn clv(&mut self) {
|
||||
self.registers.set_overflow_flag(false);
|
||||
self.increment_cycles_clear();
|
||||
let (bytes, cycles) = cycles::increment_cycles_clear();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn nop(&mut self) {
|
||||
self.increment_cycles_nop();
|
||||
let (bytes, cycles) = cycles::increment_cycles_nop();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn jmp(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -514,7 +556,8 @@ impl CPU {
|
||||
if is_long {
|
||||
self.registers.pbr = (effective_address >> 16) as u8;
|
||||
}
|
||||
self.increment_cycles_jmp(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_jmp(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn do_push(&mut self, bus: &mut Bus, bytes: &[u8]) {
|
||||
@@ -531,7 +574,8 @@ impl CPU {
|
||||
self.do_push(bus, &[self.registers.p]);
|
||||
self.registers.set_decimal_mode_flag(false);
|
||||
self.registers.set_irq_disable_flag(true);
|
||||
self.increment_cycles_brk();
|
||||
let (bytes, cycles) = cycles::increment_cycles_brk(self.registers.emulation_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn cop(&mut self, bus: &mut Bus) {
|
||||
@@ -540,25 +584,29 @@ impl CPU {
|
||||
self.do_push(bus, &[self.registers.p]);
|
||||
self.registers.set_decimal_mode_flag(false);
|
||||
self.registers.set_irq_disable_flag(true);
|
||||
self.increment_cycles_brk();
|
||||
let (bytes, cycles) = cycles::increment_cycles_brk(self.registers.emulation_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn pea(&mut self, bus: &mut Bus) {
|
||||
let address = self.get_effective_address(bus, AddressingMode::Absolute);
|
||||
self.do_push(bus, &[(address >> 8) as u8, address as u8]);
|
||||
self.increment_cycles_pea();
|
||||
let (bytes, cycles) = cycles::increment_cycles_pea();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn pei(&mut self, bus: &mut Bus) {
|
||||
let address = self.get_effective_address(bus, AddressingMode::DirectPageIndirect);
|
||||
self.do_push(bus, &[(address >> 8) as u8, address as u8]);
|
||||
self.increment_cycles_pei();
|
||||
let (bytes, cycles) = cycles::increment_cycles_pei(&self.registers);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn per(&mut self, bus: &mut Bus) {
|
||||
let label = self.get_effective_address(bus, AddressingMode::Absolute) as u16;
|
||||
let is_negative = (label>> 15) == 1;
|
||||
self.increment_cycles_per();
|
||||
let (bytes, cycles) = cycles::increment_cycles_per();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let address = match is_negative {
|
||||
true => self.registers.pc.wrapping_sub(!label + 1),
|
||||
false=> self.registers.pc.wrapping_add(label),
|
||||
@@ -573,28 +621,33 @@ impl CPU {
|
||||
} else {
|
||||
self.do_push(bus, &[value as u8]);
|
||||
}
|
||||
self.increment_cycles_pha();
|
||||
let (bytes, cycles) = cycles::increment_cycles_pha(self.registers.is_16bit_mode());
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn phb(&mut self, bus: &mut Bus) {
|
||||
self.do_push(bus, &[self.registers.dbr]);
|
||||
self.increment_cycles_phb();
|
||||
let (bytes, cycles) = cycles::increment_cycles_phb();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn phd(&mut self, bus: &mut Bus) {
|
||||
let value = self.registers.d;
|
||||
self.do_push(bus, &[(value >> 8) as u8, value as u8]);
|
||||
self.increment_cycles_phd();
|
||||
let (bytes, cycles) = cycles::increment_cycles_phd();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn phk(&mut self, bus: &mut Bus) {
|
||||
self.do_push(bus, &[self.registers.pbr]);
|
||||
self.increment_cycles_phk();
|
||||
let (bytes, cycles) = cycles::increment_cycles_phk();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
pub fn php(&mut self, bus: &mut Bus) {
|
||||
self.do_push(bus, &[self.registers.p]);
|
||||
self.increment_cycles_php();
|
||||
let (bytes, cycles) = cycles::increment_cycles_php();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn phx(&mut self, bus: &mut Bus) {
|
||||
@@ -604,7 +657,8 @@ impl CPU {
|
||||
} else {
|
||||
self.do_push(bus, &[value as u8]);
|
||||
}
|
||||
self.increment_cycles_push_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_push_index(self.registers.is_16bit_index());
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn phy(&mut self, bus: &mut Bus) {
|
||||
@@ -614,7 +668,8 @@ impl CPU {
|
||||
} else {
|
||||
self.do_push(bus, &[value as u8]);
|
||||
}
|
||||
self.increment_cycles_push_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_push_index(self.registers.is_16bit_index());
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn jsr(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -625,7 +680,8 @@ impl CPU {
|
||||
_ => false,
|
||||
};
|
||||
// We need to push the *next* instruction onto the stack
|
||||
self.increment_cycles_jsr(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_jsr(addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
let value = self.registers.get_pc_address();
|
||||
if is_long {
|
||||
self.do_push(bus, &[
|
||||
@@ -662,7 +718,8 @@ impl CPU {
|
||||
self.registers.set_low_a(value);
|
||||
self.do_bit(self.registers.a as u8, value, addressing_mode);
|
||||
}
|
||||
self.increment_cycles_lda(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_lda(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn do_ld_index(&mut self, bus: &mut Bus, index: IndexRegister, addressing_mode: AddressingMode) {
|
||||
@@ -687,7 +744,8 @@ impl CPU {
|
||||
Flags::Zero(value == 0),
|
||||
]);
|
||||
}
|
||||
self.increment_cycles_ld_index(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_ld_index(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn ldx(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -726,24 +784,28 @@ impl CPU {
|
||||
let bytes = self.do_pull(bus, 1);
|
||||
self.registers.set_low_a(bytes[0]);
|
||||
}
|
||||
self.increment_cycles_pla();
|
||||
let (bytes, cycles) = cycles::increment_cycles_pla(self.registers.is_16bit_mode());
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn plb(&mut self, bus: &mut Bus) {
|
||||
self.registers.dbr = self.do_pull(bus, 1)[0];
|
||||
self.increment_cycles_plb();
|
||||
let (bytes, cycles) = cycles::increment_cycles_plb();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn pld(&mut self, bus: &mut Bus) {
|
||||
let bytes = self.do_pull(bus, 2);
|
||||
self.registers.d = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
self.increment_cycles_pld();
|
||||
let (bytes, cycles) = cycles::increment_cycles_pld();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn plp(&mut self, bus: &mut Bus) {
|
||||
let bytes = self.do_pull(bus, 1);
|
||||
self.registers.p = bytes[0];
|
||||
self.increment_cycles_plp();
|
||||
let (bytes, cycles) = cycles::increment_cycles_plp();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn plx(&mut self, bus: &mut Bus) {
|
||||
@@ -754,7 +816,8 @@ impl CPU {
|
||||
let bytes = self.do_pull(bus, 1);
|
||||
self.registers.set_low_x(bytes[0]);
|
||||
}
|
||||
self.increment_cycles_pl_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_pl_index(self.registers.is_16bit_index());
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn ply(&mut self, bus: &mut Bus) {
|
||||
@@ -765,13 +828,15 @@ impl CPU {
|
||||
let bytes = self.do_pull(bus, 1);
|
||||
self.registers.set_low_y(bytes[0]);
|
||||
}
|
||||
self.increment_cycles_pl_index();
|
||||
let (bytes, cycles) = cycles::increment_cycles_pl_index(self.registers.is_16bit_index());
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn rep(&mut self, bus: &mut Bus) {
|
||||
let byte = self.get_8bit_from_address(bus, AddressingMode::Immediate);
|
||||
self.registers.reset_rep_byte(byte);
|
||||
self.increment_cycles_rep();
|
||||
let (bytes, cycles) = cycles::increment_cycles_rep();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn rol(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -791,7 +856,8 @@ impl CPU {
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_shift(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_shift(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn ror(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -811,7 +877,8 @@ impl CPU {
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
self.registers.set_flags(&affected_flags);
|
||||
}
|
||||
self.increment_cycles_shift(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_shift(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn rtl(&mut self, bus: &mut Bus) {
|
||||
@@ -819,35 +886,41 @@ impl CPU {
|
||||
// Low byte of PC is pulled first, then high byte and then PBR
|
||||
self.registers.pc = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
self.registers.pbr = bytes[2];
|
||||
self.increment_cycles_return_subroutine();
|
||||
let (bytes, cycles) = cycles::increment_cycles_return_subroutine();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn rts(&mut self, bus: &mut Bus) {
|
||||
let bytes = self.do_pull(bus, 2);
|
||||
// Low byte of PC is pulled first, then high byte
|
||||
self.registers.pc = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
self.increment_cycles_return_subroutine();
|
||||
let (bytes, cycles) = cycles::increment_cycles_return_subroutine();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn sec(&mut self) {
|
||||
self.registers.set_carry_flag(true);
|
||||
self.increment_cycles_set_flag();
|
||||
let (bytes, cycles) = cycles::increment_cycles_set_flag();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn sed(&mut self) {
|
||||
self.registers.set_decimal_mode_flag(true);
|
||||
self.increment_cycles_set_flag();
|
||||
let (bytes, cycles) = cycles::increment_cycles_set_flag();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn sei(&mut self) {
|
||||
self.registers.set_irq_disable_flag(true);
|
||||
self.increment_cycles_set_flag();
|
||||
let (bytes, cycles) = cycles::increment_cycles_set_flag();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn sep(&mut self, bus: &mut Bus) {
|
||||
let byte = self.get_8bit_from_address(bus, AddressingMode::Immediate);
|
||||
self.registers.set_sep_byte(byte);
|
||||
self.increment_cycles_sep();
|
||||
let (bytes, cycles) = cycles::increment_cycles_sep();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn sta(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -856,7 +929,8 @@ impl CPU {
|
||||
} else {
|
||||
self.set_8bit_to_address(bus, addressing_mode, self.registers.a as u8);
|
||||
}
|
||||
self.increment_cycles_sta(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_sta(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn stx(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -865,7 +939,8 @@ impl CPU {
|
||||
} else {
|
||||
self.set_8bit_to_address(bus, addressing_mode, self.registers.x as u8);
|
||||
}
|
||||
self.increment_cycles_st_index(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_st_index(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn sty(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -874,7 +949,8 @@ impl CPU {
|
||||
} else {
|
||||
self.set_8bit_to_address(bus, addressing_mode, self.registers.y as u8);
|
||||
}
|
||||
self.increment_cycles_st_index(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_st_index(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn stz(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -883,12 +959,14 @@ impl CPU {
|
||||
} else {
|
||||
self.set_8bit_to_address(bus, addressing_mode, 0);
|
||||
}
|
||||
self.increment_cycles_st_index(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_st_index(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn stp(&mut self) {
|
||||
self.is_stopped = true;
|
||||
self.increment_cycles_stp();
|
||||
let (bytes, cycles) = cycles::increment_cycles_stp();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tax(&mut self) {
|
||||
@@ -902,7 +980,8 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tay(&mut self) {
|
||||
@@ -916,7 +995,8 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tcd(&mut self) {
|
||||
@@ -924,7 +1004,8 @@ impl CPU {
|
||||
self.registers.d = result;
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tcs(&mut self) {
|
||||
@@ -932,7 +1013,8 @@ impl CPU {
|
||||
self.registers.sp = result;
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tdc(&mut self) {
|
||||
@@ -940,7 +1022,8 @@ impl CPU {
|
||||
self.registers.a = result;
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tsc(&mut self) {
|
||||
@@ -948,7 +1031,8 @@ impl CPU {
|
||||
self.registers.a = result;
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tsx(&mut self) {
|
||||
@@ -963,7 +1047,8 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn txa(&mut self) {
|
||||
@@ -977,7 +1062,8 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn txs(&mut self) {
|
||||
@@ -991,7 +1077,8 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn txy(&mut self) {
|
||||
@@ -1005,7 +1092,8 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tya(&mut self) {
|
||||
@@ -1019,7 +1107,8 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tyx(&mut self) {
|
||||
@@ -1033,14 +1122,16 @@ impl CPU {
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_transfer();
|
||||
let (bytes, cycles) = cycles::increment_cycles_transfer();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn xba(&mut self) {
|
||||
self.registers.a = (self.registers.a << 8) | (self.registers.a >> 8);
|
||||
self.registers.set_negative_flag(((self.registers.a as u8) >> 7) == 1);
|
||||
self.registers.set_zero_flag((self.registers.a as u8) == 0);
|
||||
self.increment_cycles_xba();
|
||||
let (bytes, cycles) = cycles::increment_cycles_xba();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn do_move(&mut self, bus: &mut Bus, is_next: bool) {
|
||||
@@ -1067,7 +1158,8 @@ impl CPU {
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
self.increment_cycles_move(count);
|
||||
let (bytes, cycles) = cycles::increment_cycles_move(count);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn mvn(&mut self, bus: &mut Bus) {
|
||||
@@ -1085,7 +1177,8 @@ impl CPU {
|
||||
if !self.registers.emulation_mode {
|
||||
self.registers.pbr = self.do_pull(bus, 1)[0];
|
||||
}
|
||||
self.increment_cycles_return_interrupt();
|
||||
let (bytes, cycles) = cycles::increment_cycles_return_interrupt(self.registers.emulation_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn trb(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -1100,7 +1193,8 @@ impl CPU {
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_test(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_test(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn tsb(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
@@ -1115,23 +1209,27 @@ impl CPU {
|
||||
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
self.increment_cycles_test(addressing_mode);
|
||||
let (bytes, cycles) = cycles::increment_cycles_test(&self.registers, addressing_mode);
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn wai(&mut self) {
|
||||
self.is_waiting_interrupt = true;
|
||||
self.increment_cycles_stp();
|
||||
let (bytes, cycles) = cycles::increment_cycles_stp();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
|
||||
fn wdm(&mut self) {
|
||||
self.increment_cycles_wdm();
|
||||
let (bytes, cycles) = cycles::increment_cycles_wdm();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
|
||||
fn xce(&mut self) {
|
||||
self.registers.exchange_carry_and_emulation();
|
||||
self.increment_cycles_exchange();
|
||||
let (bytes, cycles) = cycles::increment_cycles_exchange();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
|
||||
fn check_running_state(&mut self, bus: &mut Bus) -> bool {
|
||||
@@ -1143,7 +1241,8 @@ impl CPU {
|
||||
for (src, dst) in pending_bus_writes {
|
||||
let byte = bus.read(src);
|
||||
bus.write(dst, byte);
|
||||
self.increment_cycles_while_stopped();
|
||||
let (bytes, cycles) = cycles::increment_cycles_while_stopped();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
}
|
||||
if !bus.dma.is_active() {
|
||||
bus.write(dma::MDMAEN as u32, 0x00)
|
||||
@@ -1151,12 +1250,14 @@ impl CPU {
|
||||
return false;
|
||||
}
|
||||
if self.is_stopped {
|
||||
self.increment_cycles_while_stopped();
|
||||
let (bytes, cycles) = cycles::increment_cycles_while_stopped();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
return false;
|
||||
}
|
||||
if self.is_waiting_interrupt {
|
||||
// TODO: check for interrupts here
|
||||
self.increment_cycles_while_stopped();
|
||||
let (bytes, cycles) = cycles::increment_cycles_while_stopped();
|
||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user