Base byte and cycles calculation based on addressing mode

This commit is contained in:
2022-11-20 17:07:21 -05:00
parent 6178e223ba
commit 794cbef477
4 changed files with 150 additions and 0 deletions
+107
View File
@@ -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
View File
@@ -1,3 +1,4 @@
pub mod cpu;
pub mod registers;
pub mod instructions;
pub mod cycles;
+41
View File
@@ -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();
+1
View File
@@ -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),