#![allow(clippy::needless_return)]
mod address_modes;
mod opcodes;
#[cfg(test)]
mod test_utilities;
#[macro_use]
extern crate log;
use address_modes::*;
type AddressModeFunction = fn(&mut MOS6502, &mut dyn Interface6502) -> AddressModeValue;
type OpcodeFunction = fn(&mut MOS6502, &mut dyn Interface6502, AddressModeValue);
const STACK_PAGE: u16 = 0x0100;
const NMI_ADDRESS_LOCATION: u16 = 0xfffa;
const RESET_ADDRESS_LOCATION: u16 = 0xfffc;
const IRQ_ADDRESS_LOCATION: u16 = 0xfffe;
#[derive(Debug, PartialEq, Clone)]
pub struct MOS6502 {
accumulator: u8,
x_register: u8,
y_register: u8,
program_counter: u16,
stack_pointer: u8,
status_register: u8,
remaining_cycles: u8,
total_cycles: u64,
pending_nmi: bool,
pending_irq: bool,
}
impl MOS6502 {
pub fn new() -> Self {
MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0400,
stack_pointer: 0xFD,
status_register: 0x24,
remaining_cycles: 0,
total_cycles: 0,
pending_nmi: false,
pending_irq: false,
}
}
pub fn new_start(start: u16) -> Self {
return MOS6502 {
program_counter: start,
..MOS6502::new()
};
}
pub fn new_reset_position(interface: &mut (dyn Interface6502)) -> Self {
return MOS6502 {
program_counter: read_16(interface, RESET_ADDRESS_LOCATION),
..MOS6502::new()
};
}
pub fn set_program_counter(&mut self, program_counter: u16) {
self.program_counter = program_counter
}
#[cfg(feature = "implementation_transparency")]
pub fn get_program_counter(&self) -> u16 {
self.program_counter
}
#[cfg(feature = "implementation_transparency")]
pub fn get_accumulator(&self) -> u8 {
self.accumulator
}
#[cfg(feature = "implementation_transparency")]
pub fn set_accumulator(&mut self, value: u8) {
self.accumulator = value
}
#[cfg(feature = "implementation_transparency")]
pub fn get_x_register(&self) -> u8 {
self.x_register
}
#[cfg(feature = "implementation_transparency")]
pub fn set_x_register(&mut self, value: u8) {
self.x_register = value
}
#[cfg(feature = "implementation_transparency")]
pub fn get_y_register(&self) -> u8 {
self.y_register
}
#[cfg(feature = "implementation_transparency")]
pub fn set_y_register(&mut self, value: u8) {
self.y_register = value
}
#[cfg(feature = "implementation_transparency")]
pub fn get_stack_pointer(&self) -> u8 {
self.stack_pointer
}
#[cfg(feature = "implementation_transparency")]
pub fn set_stack_pointer(&mut self, value: u8) {
self.stack_pointer = value
}
#[cfg(feature = "implementation_transparency")]
pub fn get_status_register(&self) -> u8 {
self.status_register
}
#[cfg(feature = "implementation_transparency")]
pub fn set_status_register(&mut self, value: u8) {
self.status_register = value
}
#[cfg(feature = "implementation_transparency")]
pub fn get_remaining_cycles(&self) -> u8 {
self.remaining_cycles
}
pub fn cycle(&mut self, interface: &mut (dyn Interface6502)) {
if self.remaining_cycles == 0 {
if self.pending_nmi || (self.pending_irq && !self.get_flag(StatusFlag::InterruptDisable)) {
self.push_stack_16(interface, self.program_counter);
self.set_flag(StatusFlag::BreakIrq, true);
self.push_stack(interface, self.status_register);
self.set_flag(StatusFlag::InterruptDisable, true);
if self.pending_nmi {
self.program_counter = read_16(interface, NMI_ADDRESS_LOCATION);
self.remaining_cycles = 8;
} else {
self.program_counter = read_16(interface, IRQ_ADDRESS_LOCATION);
self.remaining_cycles = 7;
}
self.pending_nmi = false;
self.pending_irq = false;
} else {
let instruction = opcodes::OPCODE_TABLE[interface.read(self.program_counter) as usize];
let log_program_counter = self.program_counter;
self.program_counter += 1;
let address_mode_value = instruction.find_address(self, interface);
trace!(
"0x{:04X} {} {:?} A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X} CYC:{}",
log_program_counter,
instruction.get_name(),
address_mode_value,
self.accumulator,
self.x_register,
self.y_register,
self.status_register,
self.stack_pointer,
self.total_cycles + 7,
);
instruction.execute_instruction(self, interface, address_mode_value);
self.remaining_cycles += instruction.get_cycles();
}
}
self.remaining_cycles -= 1;
self.total_cycles += 1;
}
pub fn execute_instruction(&mut self, interface: &mut (dyn Interface6502)) {
self.cycle(interface); while self.remaining_cycles != 0 {
self.cycle(interface)
}
}
fn push_stack(&mut self, interface: &mut dyn Interface6502, data: u8) {
interface.write(STACK_PAGE + u16::from(self.stack_pointer), data);
self.stack_pointer = self.stack_pointer.wrapping_sub(1);
}
fn push_stack_16(&mut self, interface: &mut dyn Interface6502, data: u16) {
self.push_stack(interface, (data >> 8) as u8);
self.push_stack(interface, data as u8);
}
fn pop_stack(&mut self, interface: &mut dyn Interface6502) -> u8 {
self.stack_pointer = self.stack_pointer.wrapping_add(1);
interface.read(STACK_PAGE + u16::from(self.stack_pointer))
}
fn pop_stack_16(&mut self, interface: &mut dyn Interface6502) -> u16 {
let lo = u16::from(self.pop_stack(interface));
let hi = u16::from(self.pop_stack(interface));
return (hi << 8) | lo;
}
fn set_flag(&mut self, flag: StatusFlag, value: bool) {
self.status_register &= !(flag as u8);
if value {
self.status_register |= flag as u8
}
}
fn get_flag(&self, flag: StatusFlag) -> bool {
return (self.status_register & flag as u8) > 0;
}
pub fn interrupt_request(&mut self) {
self.pending_irq = true;
}
pub fn non_maskable_interrupt_request(&mut self) {
self.pending_nmi = true;
}
pub fn reset(&mut self, interface: &mut dyn Interface6502) {
self.program_counter = read_16(interface, RESET_ADDRESS_LOCATION);
self.accumulator = 0x00;
self.x_register = 0x00;
self.y_register = 0x00;
self.stack_pointer = 0xFD;
self.status_register = 0x34;
self.remaining_cycles = 8;
}
}
fn read_16(bus: &mut dyn Interface6502, address: u16) -> u16 {
let lo = u16::from(bus.read(address));
let hi = u16::from(bus.read(address + 1));
return (hi << 8) | lo;
}
pub trait Interface6502 {
fn read(&mut self, address: u16) -> u8;
fn write(&mut self, address: u16, data: u8);
}
#[derive(Debug, Copy, Clone)]
enum StatusFlag {
Carry = 0b0000_0001,
Zero = 0b0000_0010,
InterruptDisable = 0b0000_0100,
Decimal = 0b0000_1000,
Break = 0b0011_0000,
BreakIrq = 0b0010_0000,
Overflow = 0b0100_0000,
Negative = 0b1000_0000,
}
impl Default for MOS6502 {
fn default() -> Self {
MOS6502::new()
}
}