From 2e4dd7b15ceb85e490e2e0be482b5e7e1b005f3a Mon Sep 17 00:00:00 2001 From: Franco Date: Mon, 25 Dec 2023 22:42:07 -0500 Subject: [PATCH] decouple cycle increment logic from cpu struct (#1) --- snes-core/src/cpu/cycles.rs | 829 ++++++++++++++++-------------- snes-core/src/cpu/instructions.rs | 301 +++++++---- 2 files changed, 634 insertions(+), 496 deletions(-) diff --git a/snes-core/src/cpu/cycles.rs b/snes-core/src/cpu/cycles.rs index 72a39c3..fa74727 100644 --- a/snes-core/src/cpu/cycles.rs +++ b/snes-core/src/cpu/cycles.rs @@ -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 = 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 = 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); } -} \ No newline at end of file +} diff --git a/snes-core/src/cpu/instructions.rs b/snes-core/src/cpu/instructions.rs index faa2a15..a56a307 100644 --- a/snes-core/src/cpu/instructions.rs +++ b/snes-core/src/cpu/instructions.rs @@ -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(&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(&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(&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(&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;