decouple cycle increment logic from cpu struct (#1)

This commit is contained in:
2023-12-25 22:42:07 -05:00
committed by GitHub
parent 1642d582cb
commit 2e4dd7b15c
2 changed files with 634 additions and 496 deletions

View File

@@ -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(&registers, 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(&registers, 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(&registers, 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(&registers, 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(&registers, 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(&registers, 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(&registers, 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(&registers, AddressingMode::AbsoluteIndexed(IndexRegister::X));
assert_eq!(bytes, 3);
assert_eq!(cycles, 5);
}
}
}

View File

@@ -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;