mirror of
https://github.com/FranLMSP/snes.git
synced 2026-08-03 08:30:01 -04:00
Base byte and cycles calculation based on addressing mode
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
use super::cpu::CPU;
|
||||
use crate::utils::addressing::{AddressingMode};
|
||||
|
||||
|
||||
impl CPU {
|
||||
pub fn increment_cycles_adc_sbc(&mut self, addressing_mode: AddressingMode) {
|
||||
type A = AddressingMode;
|
||||
let (mut bytes, mut cycles) = 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),
|
||||
};
|
||||
// condition 1: Add 1 byte and 1 cycle if m = 0 (16-bit memory/accumulator)
|
||||
if !self.registers.get_memory_select_flag() {
|
||||
bytes += 1;
|
||||
cycles += 1;
|
||||
}
|
||||
|
||||
// condition 2: Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)
|
||||
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;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
|
||||
// condition 3: Add 1 cycle if adding index crosses a page boundary
|
||||
match addressing_mode {
|
||||
A::AbsoluteIndexed(_) | A::DirectPageIndirectIndexed(_) => {
|
||||
todo!("Check if index crosses a page boundary")
|
||||
}
|
||||
_ => {},
|
||||
};
|
||||
|
||||
// condition 4: Add 1 cycle if 65C02 and d = 1 (decimal mode, 65C02)
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
cycles += 1;
|
||||
}
|
||||
|
||||
self.registers.increment_pc(bytes);
|
||||
self.cycles += cycles;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod cpu_instructions_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_increment_cycles_adc_sbc() {
|
||||
let mut cpu = CPU::new();
|
||||
cpu.registers.pc = 0;
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.increment_cycles_adc_sbc(AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.pc, 2);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
|
||||
cpu.registers.pc = 0;
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_16bit_mode(true);
|
||||
cpu.increment_cycles_adc_sbc(AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.pc, 3);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
|
||||
cpu.registers.pc = 0;
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_16bit_mode(true);
|
||||
cpu.registers.set_decimal_mode_flag(true);
|
||||
cpu.increment_cycles_adc_sbc(AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.pc, 3);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
|
||||
cpu.registers.pc = 0;
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
cpu.increment_cycles_adc_sbc(AddressingMode::DirectPage);
|
||||
assert_eq!(cpu.registers.pc, 2);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
|
||||
cpu.registers.pc = 0;
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_decimal_mode_flag(false);
|
||||
cpu.registers.d = 0x0001;
|
||||
cpu.increment_cycles_adc_sbc(AddressingMode::DirectPage);
|
||||
assert_eq!(cpu.registers.pc, 2);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod cpu;
|
||||
pub mod registers;
|
||||
pub mod instructions;
|
||||
pub mod cycles;
|
||||
|
||||
@@ -115,12 +115,46 @@ impl Registers {
|
||||
pub fn get_pc_address(&self) -> u32 {
|
||||
((self.pbr as u32) << 16) | (self.pc as u32)
|
||||
}
|
||||
|
||||
pub fn is_16bit_mode(&self) -> bool {
|
||||
!self.get_memory_select_flag()
|
||||
}
|
||||
|
||||
pub fn set_16bit_mode(&mut self, val: bool) {
|
||||
self.set_memory_select_flag(!val);
|
||||
}
|
||||
|
||||
pub fn increment_pc(&mut self, bytes: u16) {
|
||||
self.pc = self.pc.wrapping_add(bytes);
|
||||
}
|
||||
|
||||
pub fn direct_page_low(&self) -> u8 {
|
||||
self.d as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod registers_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_16bit_mode() {
|
||||
let mut registers = Registers::new();
|
||||
registers.set_memory_select_flag(false);
|
||||
assert!(registers.is_16bit_mode());
|
||||
registers.set_memory_select_flag(true);
|
||||
assert!(!registers.is_16bit_mode());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_16bit_mode() {
|
||||
let mut registers = Registers::new();
|
||||
registers.set_16bit_mode(true);
|
||||
assert!(registers.is_16bit_mode());
|
||||
registers.set_16bit_mode(false);
|
||||
assert!(!registers.is_16bit_mode());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_low_a() {
|
||||
let mut registers = Registers::new();
|
||||
@@ -129,6 +163,13 @@ mod registers_tests {
|
||||
assert_eq!(registers.a, 0xA1FF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_direct_page_log() {
|
||||
let mut registers = Registers::new();
|
||||
registers.d = 0xA1A1;
|
||||
assert_eq!(registers.direct_page_low(), 0xA1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_pc_address() {
|
||||
let mut registers = Registers::new();
|
||||
|
||||
@@ -112,6 +112,7 @@ pub enum AddressingMode {
|
||||
impl AddressingMode {
|
||||
pub fn effective_address(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u32 {
|
||||
use IndexRegister::X as X;
|
||||
// TODO: maybe use impl Immediate {pub fn effective_address} to prevent this match statement?
|
||||
match self {
|
||||
Self::Immediate => immediate(pc_addr),
|
||||
Self::Absolute => absolute(bus, pc_addr),
|
||||
|
||||
Reference in New Issue
Block a user