use super::{Interface6502, MOS6502};
use std::fmt;
pub(crate) fn absolute(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address: u16 = super::read_16(bus, cpu.program_counter);
cpu.program_counter += 2;
return AddressModeValue::AbsoluteAddress(address);
}
pub(crate) fn absolute_x(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address: u16 = super::read_16(bus, cpu.program_counter);
let offset_address: u16 = address + u16::from(cpu.x_register);
cpu.remaining_cycles += if (offset_address) & 0xff00 != address & 0xff00 {
1
} else {
0
};
cpu.program_counter += 2;
return AddressModeValue::AbsoluteAddress(offset_address);
}
pub(crate) fn absolute_x_const(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address: u16 = super::read_16(bus, cpu.program_counter);
let offset_address: u16 = address + u16::from(cpu.x_register);
cpu.program_counter += 2;
return AddressModeValue::AbsoluteAddress(offset_address);
}
pub(crate) fn absolute_y(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address: u16 = super::read_16(bus, cpu.program_counter);
let offset_address: u16 = address.wrapping_add(u16::from(cpu.y_register));
cpu.remaining_cycles += if (offset_address) & 0xff00 != address & 0xff00 {
1
} else {
0
};
cpu.program_counter += 2;
return AddressModeValue::AbsoluteAddress(offset_address);
}
pub(crate) fn absolute_y_const(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address: u16 = super::read_16(bus, cpu.program_counter);
let offset_address: u16 = address.wrapping_add(u16::from(cpu.y_register));
cpu.program_counter += 2;
return AddressModeValue::AbsoluteAddress(offset_address);
}
pub(crate) fn immediate(cpu: &mut MOS6502, _bus: &mut dyn Interface6502) -> AddressModeValue {
let address = cpu.program_counter;
cpu.program_counter += 1;
return AddressModeValue::AbsoluteAddress(address);
}
pub(crate) fn implied(_cpu: &mut MOS6502, _bus: &mut dyn Interface6502) -> AddressModeValue {
return AddressModeValue::Implied;
}
pub(crate) fn indirect(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let indirect_address = super::read_16(bus, cpu.program_counter);
let page = indirect_address & 0xff00;
let address = (u16::from(bus.read(page | ((indirect_address + 1) & 0xff))) << 8) | u16::from(bus.read(indirect_address));
cpu.program_counter += 2;
return AddressModeValue::AbsoluteAddress(address);
}
pub(crate) fn indirect_x(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let indirect_address = bus.read(cpu.program_counter);
let address = ((bus.read(indirect_address.wrapping_add(cpu.x_register).wrapping_add(1) as u16) as u16) << 8)
| bus.read(indirect_address.wrapping_add(cpu.x_register) as u16) as u16;
cpu.program_counter += 1;
return AddressModeValue::AbsoluteAddress(address);
}
pub(crate) fn indirect_y(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let indirect_address = bus.read(cpu.program_counter);
let address = ((bus.read(indirect_address.wrapping_add(1) as u16) as u16) << 8) | bus.read(indirect_address as u16) as u16;
let offset_address = address.wrapping_add(u16::from(cpu.y_register));
cpu.remaining_cycles += if (offset_address) & 0xff00 != address & 0xff00 {
1
} else {
0
};
cpu.program_counter += 1;
return AddressModeValue::AbsoluteAddress(offset_address);
}
pub(crate) fn indirect_y_const(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let indirect_address = bus.read(cpu.program_counter);
let address = ((bus.read(indirect_address.wrapping_add(1) as u16) as u16) << 8) | bus.read(indirect_address as u16) as u16;
let offset_address = address.wrapping_add(u16::from(cpu.y_register));
cpu.program_counter += 1;
return AddressModeValue::AbsoluteAddress(offset_address);
}
pub(crate) fn relative(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let relative_address = bus.read(cpu.program_counter);
cpu.program_counter += 1;
return AddressModeValue::RelativeAddress(relative_address);
}
pub(crate) fn zero_page(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address = u16::from(bus.read(cpu.program_counter));
cpu.program_counter += 1;
return AddressModeValue::AbsoluteAddress(address);
}
pub(crate) fn zero_page_x(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address = bus.read(cpu.program_counter).wrapping_add(cpu.x_register);
cpu.program_counter += 1;
return AddressModeValue::AbsoluteAddress(u16::from(address));
}
pub(crate) fn zero_page_y(cpu: &mut MOS6502, bus: &mut dyn Interface6502) -> AddressModeValue {
let address = bus.read(cpu.program_counter).wrapping_add(cpu.y_register);
cpu.program_counter += 1;
return AddressModeValue::AbsoluteAddress(u16::from(address));
}
#[derive(PartialEq, Clone, Copy)]
pub(crate) enum AddressModeValue {
Implied,
RelativeAddress(u8),
AbsoluteAddress(u16),
}
impl fmt::Debug for AddressModeValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AddressModeValue::Implied => write!(f, "Implied"),
AddressModeValue::RelativeAddress(address) => write!(f, "Relative Address: {:02X}", address),
AddressModeValue::AbsoluteAddress(address) => write!(f, "Absolute Address: {:04X}", address),
}
}
}
#[cfg(test)]
mod test {
#![allow(unused_variables, unused_mut)] use super::*;
use crate::test_utilities::StubInterface6502;
#[test]
fn test_absolute() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0xff,
|address, data, write_count| panic!("Write function was called"),
);
let expected_program_counter = cpu.program_counter + 2;
let address_mode_value = absolute(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xffff));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_absolute_x() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x00,
|address, data, write_count| panic!("Write function was called"),
);
cpu.x_register = 2;
let expected_program_counter = cpu.program_counter + 2;
let address_mode_value = absolute_x(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0x0002));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_absolute_x_extra_cycle() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x10,
|address, data, write_count| panic!("Write function was called"),
);
cpu.x_register = 255;
let expected_program_counter = cpu.program_counter + 2;
let address_mode_value = absolute_x(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0x110f));
assert_eq!(cpu.remaining_cycles, 1);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_absolute_y() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x00,
|address, data, write_count| panic!("Write function was called"),
);
cpu.y_register = 2;
let expected_program_counter = cpu.program_counter + 2;
let address_mode_value = absolute_y(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0x0002));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_absolute_y_extra_cycle() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x10,
|address, data, write_count| panic!("Write function was called"),
);
cpu.y_register = 255;
let expected_program_counter = cpu.program_counter + 2;
let address_mode_value = absolute_y(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0x110f));
assert_eq!(cpu.remaining_cycles, 1);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_immediate() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| panic!("Read function was called"),
|address, data, write_count| panic!("Write function was called"),
);
let prior_program_counter = cpu.program_counter;
let address_mode_value = immediate(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(prior_program_counter));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(prior_program_counter + 1, cpu.program_counter)
}
#[test]
fn test_implied() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| panic!("Read function was called"),
|address, data, write_count| panic!("Write function was called"),
);
let expected_program_counter = cpu.program_counter;
let address_mode_value = implied(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::Implied);
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_indirect() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| match address {
0x0000 => 0x11,
0x0001 => 0x10,
0x1011 => 0x01,
0x1012 => 0xff,
_ => 0x00,
},
|address, data, write_count| panic!("Write function was called"),
);
let expected_program_counter = cpu.program_counter + 2;
let address_mode_value = indirect(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xff01));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_indirect_page_edge() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| match address {
0x0000 => 0xff,
0x0001 => 0x10,
0x10ff => 0x01,
0x1000 => 0xa7,
_ => 0x00,
},
|address, data, write_count| panic!("Write function was called"),
);
let expected_program_counter = cpu.program_counter + 2;
let address_mode_value = indirect(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xa701));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_indirect_x() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| match address {
0x0000 => 0x25,
0x0035 => 0x01,
0x0036 => 0xa7,
_ => 0x00,
},
|address, data, write_count| panic!("Write function was called"),
);
cpu.x_register = 0x10;
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = indirect_x(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xa701));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_indirect_x_page_edge() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| match address {
0x0000 => 0xfe,
0x00ff => 0x01,
_ => 0x00,
},
|address, data, write_count| panic!("Write function was called"),
);
cpu.x_register = 0x1;
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = indirect_x(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xfe01));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_indirect_y() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| match address {
0x0000 => 0x25,
0x0025 => 0x01,
0x0026 => 0xa7,
_ => 0x00,
},
|address, data, write_count| panic!("Write function was called"),
);
cpu.y_register = 0x10;
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = indirect_y(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xa711));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_indirect_y_extra_cycle() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| match address {
0x0000 => 0x25,
0x0025 => 0xff,
0x0026 => 0xa7,
_ => 0x00,
},
|address, data, write_count| panic!("Write function was called"),
);
cpu.y_register = 0x10;
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = indirect_y(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xa80f));
assert_eq!(cpu.remaining_cycles, 1);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_indirect_y_page_edge() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| match address {
0x0000 => 0xff,
0x00ff => 0x0a,
0x0026 => 0xa7,
_ => 0x00,
},
|address, data, write_count| panic!("Write function was called"),
);
cpu.y_register = 0x10;
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = indirect_y(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0xff1a));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_relative() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x10,
|address, data, write_count| panic!("Write function was called"),
);
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = relative(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::RelativeAddress(0x10));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_zero_page() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x10,
|address, data, write_count| panic!("Write function was called"),
);
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = zero_page(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0x0010));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_zero_page_x() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x10,
|address, data, write_count| panic!("Write function was called"),
);
cpu.x_register = 0x10;
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = zero_page_x(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0x0020));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
#[test]
fn test_zero_page_y() {
let mut cpu = MOS6502::new_start(0x0000);
let mut bus = StubInterface6502::new(
|address, read_count| 0x10,
|address, data, write_count| panic!("Write function was called"),
);
cpu.y_register = 0x10;
let expected_program_counter = cpu.program_counter + 1;
let address_mode_value = zero_page_y(&mut cpu, &mut bus);
assert_eq!(address_mode_value, AddressModeValue::AbsoluteAddress(0x0020));
assert_eq!(cpu.remaining_cycles, 0);
assert_eq!(expected_program_counter, cpu.program_counter)
}
}