nes_emulator/src/cpu.rs
Steins7 af35cfc712 Implement proper clock management
For some reason, sleep causes some issues in release in the egl crate. Maybe
some timing issue ? In debug, the program is way slower than it should be
2024-03-10 22:47:12 +01:00

1158 lines
31 KiB
Rust

#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
fmt,
rc::Rc,
cell::RefCell,
};
use bitflags::bitflags;
use crate::{
bus::Bus,
peripherals::{Peripheral, Mapper},
utils::DisplayBuffer,
};
//--------------------------------------------------------------------------------------------------
trait Input {
fn get_cycles(&self) -> u32;
}
trait RInput: Input {
fn read<M: Peripheral>(&self, acc: &u8, bus: &M) -> u8;
}
trait WInput: Input {
fn write<M: Peripheral>(&mut self, acc: &mut u8, bus: &mut M, data: u8);
}
trait RWInput: RInput + WInput {}
struct Accumulator {}
impl Input for Accumulator {
fn get_cycles(&self) -> u32 { 0 } //only used in +2 instructions
}
impl RInput for Accumulator {
fn read<M: Peripheral>(&self, acc: &u8, _bus: &M) -> u8 { *acc }
}
impl WInput for Accumulator {
fn write<M: Peripheral>(&mut self, acc: &mut u8, _bus: &mut M, data: u8) { *acc = data }
}
impl RWInput for Accumulator {}
struct Data {
data: u8,
}
impl Input for Data {
fn get_cycles(&self) -> u32 { 2 }
}
impl RInput for Data {
fn read<M: Peripheral>(&self, _acc: &u8, _bus: &M) -> u8 { self.data }
}
struct MemoryVal {
addr: u16,
cycles: u32,
}
impl Input for MemoryVal {
fn get_cycles(&self) -> u32 { self.cycles }
}
impl RInput for MemoryVal {
fn read<M: Peripheral>(&self, _acc: &u8, bus: &M) -> u8 {
bus.read_addr(self.addr)
}
}
impl WInput for MemoryVal {
fn write<M: Peripheral>(&mut self, _acc: &mut u8, bus: &mut M, data: u8) {
bus.write_addr(self.addr, data);
}
}
impl RWInput for MemoryVal {}
struct MemoryValExtra {
addr: u16,
cycles: u32,
extra_cycle: bool,
}
impl Input for MemoryValExtra {
fn get_cycles(&self) -> u32 {
match self.extra_cycle {
false => self.cycles,
true => self.cycles + 1,
}
}
}
impl RInput for MemoryValExtra {
fn read<M: Peripheral>(&self, _acc: &u8, bus: &M) -> u8 {
bus.read_addr(self.addr)
}
}
impl WInput for MemoryValExtra {
fn write<M: Peripheral>(&mut self, _acc: &mut u8, bus: &mut M, data: u8) {
bus.write_addr(self.addr, data);
self.extra_cycle = true;
}
}
impl RWInput for MemoryValExtra {}
macro_rules! parse_opcode {
($cpu:expr, $opcode:expr, $($code:expr => $inst:ident ($mode:ident)),* $(,)?) => (
match $opcode {
$(
$code => {
let input = $cpu.$mode();
$cpu.$inst(input)
}
)*
_ => panic!("unimplemented opcode: 0x{:x}", $opcode),
}
)
}
//--------------------------------------------------------------------------------------------------
bitflags! {
struct StatusReg: u8 {
const C = 0x1 << 0;
const Z = 0x1 << 1;
const I = 0x1 << 2;
const D = 0x1 << 3;
const B = 0x1 << 4;
const U = 0x1 << 5;
const V = 0x1 << 6;
const N = 0x1 << 7;
}
}
pub struct Cpu<M: Mapper> {
a: u8,
x: u8,
y: u8,
pc: u16,
s: u8,
p: StatusReg,
bus: Bus<M>,
tick_counter: u8,
}
impl<M: Mapper> fmt::Debug for Cpu<M> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Cpu")
.field("acc", &format_args!("0x{:0>2X}", self.a))
.field("x ", &format_args!("0x{:0>2X}", self.x))
.field("y ", &format_args!("0x{:0>2X}", self.y))
.field("prg_count", &format_args!("0x{:0>4X}", self.pc))
.field("stack_ptr", &format_args!("0x{:0>2X}", self.s))
.field("status", &self.p)
.field("bus", &self.bus)
.finish()
}
}
impl<M: Mapper> Cpu<M> {
pub fn new(mapper: Rc<RefCell<M>>,
screen: Rc<RefCell<DisplayBuffer>>,
pattern_table: Rc<RefCell<DisplayBuffer>>)
-> Self {
// read initial PC value from reset vector
let bus = Bus::new(mapper, screen, pattern_table);
let pc_lo = bus.read_addr(0xFFFC) as u16;
let pc_hi = bus.read_addr(0xFFFD) as u16;
Cpu {
a: 0,
x: 0,
y: 0,
pc: (pc_lo | (pc_hi << 8)) + 3,
s: 0xFD,
p: StatusReg::from_bits(0x34).unwrap(),
bus,
tick_counter: 0,
}
}
pub fn tick(&mut self) {
if self.tick_counter >= 11 {
self.tick_counter = 0;
self.execute();
} else {
self.tick_counter += 1;
}
self.bus.tick();
}
fn execute(&mut self) {
let opcode = self.read_pc_addr();
// if self.pc-1 > 0x36D0 && self.pc-1 < 0x36D8 {
// println!("{:#?}", self);
// }
// if (self.pc-1) != 0x36D8 {
// println!("0x{:0>4X}: {:0>2X}", self.pc-1, opcode);
// }
let _cycles = parse_opcode!(self, opcode,
0x69 => adc(mode_immediate),
0x65 => adc(mode_zero_page),
0x75 => adc(mode_zero_page_x),
0x6D => adc(mode_absolute),
0x7D => adc(mode_absolute_x),
0x79 => adc(mode_absolute_y),
0x61 => adc(mode_indirect_x),
0x71 => adc(mode_indirect_y),
0x29 => and(mode_immediate),
0x25 => and(mode_zero_page),
0x35 => and(mode_zero_page_x),
0x2D => and(mode_absolute),
0x3D => and(mode_absolute_x),
0x39 => and(mode_absolute_y),
0x21 => and(mode_indirect_x),
0x31 => and(mode_indirect_y),
0x0A => asl(mode_accumulator),
0x06 => asl(mode_zero_page),
0x16 => asl(mode_zero_page_x),
0x0E => asl(mode_absolute),
0x1E => asl(mode_absolute_x),
0x90 => bcc(mode_relative),
0xB0 => bcs(mode_relative),
0xF0 => beq(mode_relative),
0x24 => bit(mode_zero_page),
0x2C => bit(mode_absolute),
0x30 => bmi(mode_relative),
0xD0 => bne(mode_relative),
0x10 => bpl(mode_relative),
0x00 => brk(mode_implicit),
0x50 => bvc(mode_relative),
0x70 => bvs(mode_relative),
0x18 => clc(mode_implicit),
0xD8 => cld(mode_implicit),
0x58 => cli(mode_implicit),
0xB8 => clv(mode_implicit),
0xC9 => cmp(mode_immediate),
0xC5 => cmp(mode_zero_page),
0xD5 => cmp(mode_zero_page_x),
0xCD => cmp(mode_absolute),
0xDD => cmp(mode_absolute_x),
0xD9 => cmp(mode_absolute_y),
0xC1 => cmp(mode_indirect_x),
0xD1 => cmp(mode_indirect_y),
0xE0 => cpx(mode_immediate),
0xE4 => cpx(mode_zero_page),
0xEC => cpx(mode_absolute),
0xC0 => cpy(mode_immediate),
0xC4 => cpy(mode_zero_page),
0xCC => cpy(mode_absolute),
0xC6 => dec(mode_zero_page),
0xD6 => dec(mode_zero_page_x),
0xCE => dec(mode_absolute),
0xDE => dec(mode_absolute_x),
0xCA => dex(mode_implicit),
0x88 => dey(mode_implicit),
0x49 => eor(mode_immediate),
0x45 => eor(mode_zero_page),
0x55 => eor(mode_zero_page_x),
0x4D => eor(mode_absolute),
0x5D => eor(mode_absolute_x),
0x59 => eor(mode_absolute_y),
0x41 => eor(mode_indirect_x),
0x51 => eor(mode_indirect_y),
0xE6 => inc(mode_zero_page),
0xF6 => inc(mode_zero_page_x),
0xEE => inc(mode_absolute),
0xFE => inc(mode_absolute_x),
0xE8 => inx(mode_implicit),
0xC8 => iny(mode_implicit),
0x4C => jmp(mode_absolute),
0x6C => jmp(mode_indirect),
0x20 => jsr(mode_absolute),
0xA9 => lda(mode_immediate),
0xA5 => lda(mode_zero_page),
0xB5 => lda(mode_zero_page_x),
0xAD => lda(mode_absolute),
0xBD => lda(mode_absolute_x),
0xB9 => lda(mode_absolute_y),
0xA1 => lda(mode_indirect_x),
0xB1 => lda(mode_indirect_y),
0xA2 => ldx(mode_immediate),
0xA6 => ldx(mode_zero_page),
0xB6 => ldx(mode_zero_page_y),
0xAE => ldx(mode_absolute),
0xBE => ldx(mode_absolute_y),
0xA0 => ldy(mode_immediate),
0xA4 => ldy(mode_zero_page),
0xB4 => ldy(mode_zero_page_x),
0xAC => ldy(mode_absolute),
0xBC => ldy(mode_absolute_x),
0x4A => lsr(mode_accumulator),
0x46 => lsr(mode_zero_page),
0x56 => lsr(mode_zero_page_x),
0x4E => lsr(mode_absolute),
0x5E => lsr(mode_absolute_x),
0xEA => nop(mode_implicit),
0x09 => ora(mode_immediate),
0x05 => ora(mode_zero_page),
0x15 => ora(mode_zero_page_x),
0x0D => ora(mode_absolute),
0x1D => ora(mode_absolute_x),
0x19 => ora(mode_absolute_y),
0x01 => ora(mode_indirect_x),
0x11 => ora(mode_indirect_y),
0x48 => pha(mode_implicit),
0x08 => php(mode_implicit),
0x68 => pla(mode_implicit),
0x28 => plp(mode_implicit),
0x2A => rol(mode_accumulator),
0x26 => rol(mode_zero_page),
0x36 => rol(mode_zero_page_x),
0x2E => rol(mode_absolute),
0x3E => rol(mode_absolute_x),
0x6A => ror(mode_accumulator),
0x66 => ror(mode_zero_page),
0x76 => ror(mode_zero_page_x),
0x6E => ror(mode_absolute),
0x7E => ror(mode_absolute_x),
0x40 => rti(mode_implicit),
0x60 => rts(mode_implicit),
0xE9 => sbc(mode_immediate),
0xE5 => sbc(mode_zero_page),
0xF5 => sbc(mode_zero_page_x),
0xED => sbc(mode_absolute),
0xFD => sbc(mode_absolute_x),
0xF9 => sbc(mode_absolute_y),
0xE1 => sbc(mode_indirect_x),
0xF1 => sbc(mode_indirect_y),
0x38 => sec(mode_implicit),
0xF8 => sed(mode_implicit),
0x78 => sei(mode_implicit),
0x85 => sta(mode_zero_page),
0x95 => sta(mode_zero_page_x),
0x8D => sta(mode_absolute),
0x9D => sta(mode_absolute_x),
0x99 => sta(mode_absolute_y),
0x81 => sta(mode_indirect_x),
0x91 => sta(mode_indirect_y),
0x86 => stx(mode_zero_page),
0x96 => stx(mode_zero_page_y),
0x8E => stx(mode_absolute),
0x84 => sty(mode_zero_page),
0x94 => sty(mode_zero_page_x),
0x8C => sty(mode_absolute),
0xAA => tax(mode_implicit),
0xA8 => tay(mode_implicit),
0xBA => tsx(mode_implicit),
0x8A => txa(mode_implicit),
0x9A => txs(mode_implicit),
0x98 => tya(mode_implicit),
);
}
/// Implicit mode
/// instructions that use implied mode don't need inputs
fn mode_implicit(&self) -> () {}
/// Immediate mode "#v":
/// use 8bit operand as input
fn mode_immediate(&mut self) -> Data {
Data {
data: self.read_pc_addr(),
}
}
/// Immediate mode "#v":
/// use 8bit operand as signed offset for PC
fn mode_relative(&mut self) -> Data {
self.mode_immediate()
}
/// Zero-page mode "d":
/// Fetch value from the zero page (8bit adresses)
/// val = PEEK(arg & 0xFF)
fn mode_zero_page(&mut self) -> MemoryVal {
MemoryVal {
addr: self.read_pc_addr() as u16,
cycles: 3,
}
}
/// Zero-page indexed mode "d,x":
/// Fetch value from the zero page (8bit adresses), indexed on X register
/// val = PEEK((arg + X) & 0xFF)
fn mode_zero_page_x(&mut self) -> MemoryVal {
MemoryVal {
addr: (self.read_pc_addr().wrapping_add(self.x)) as u16 & 0x00FF,
cycles: 4,
}
}
/// Zero-page indexed mode "d,y":
/// Fetch value from the zero page (8bit adresses), indexed on Y register
/// val = PEEK((arg + Y) & 0xFF)
fn mode_zero_page_y(&mut self) -> MemoryVal {
MemoryVal {
addr: (self.read_pc_addr().wrapping_add(self.y)) as u16 & 0x00FF,
cycles: 4,
}
}
/// Absolute mode "a"
/// Fetch value from anywhere in memory
/// val = PEEK(arg)
fn mode_absolute(&mut self) -> MemoryVal {
// compute full address
let addr_lo = self.read_pc_addr() as u16;
let addr_hi = self.read_pc_addr() as u16;
let addr = addr_lo | (addr_hi << 8);
MemoryVal {
addr,
cycles: 4,
}
}
/// Absolute mode "a.x"
/// Fetch value from anywhere in memory, indexed on X register
/// val = PEEK(arg + X)
fn mode_absolute_x(&mut self) -> MemoryValExtra {
// compute full address
let addr_lo = self.read_pc_addr() as u16;
let addr_hi = self.read_pc_addr() as u16;
let mut addr = addr_lo | (addr_hi << 8);
// compute index
let extra_cycle = (addr_lo + (self.x as u16)) & 0xFF00 != 0;
addr += self.x as u16;
MemoryValExtra {
addr,
cycles: 4,
extra_cycle,
}
}
/// Absolute mode "a.Y"
/// Fetch value from anywhere in memory, indexed on Y register
/// val = PEEK(arg + Y)
fn mode_absolute_y(&mut self) -> MemoryValExtra {
// compute full address
let addr_lo = self.read_pc_addr() as u16;
let addr_hi = self.read_pc_addr() as u16;
let mut addr = addr_lo | (addr_hi << 8);
// compute index
let extra_cycle = (addr_lo + (self.y as u16)) & 0xFF00 != 0;
addr += self.y as u16;
MemoryValExtra {
addr,
cycles: 4,
extra_cycle,
}
}
/// Indirect mode "(a)"
/// Fetch 16bit address from anywhere in memory, only used by JMP. This instruction behaves
/// uncorrectly on page boundary on the original 6502 (emulated here)
/// addr = PEEK(arg) + PEEK(arg + 1) << 8
fn mode_indirect(&mut self) -> MemoryVal {
// compute full address
let addr_ind_lo = self.read_pc_addr() as u16;
let addr_ind_hi = self.read_pc_addr() as u16;
let addr_ind = addr_ind_lo | (addr_ind_hi << 8);
// fetch indirect addr to jump to
let addr_lo = self.bus.read_addr(addr_ind) as u16;
//note: bug of the 6502, the carry isn't applied when incrementing the indirect address
let addr_hi = self.bus.read_addr(((addr_ind + 1) & 0xFF) | (addr_ind_hi << 8)) as u16;
let addr = addr_lo | (addr_hi << 8);
MemoryVal {
addr,
cycles: 6, //only used by JMP that uses cycles - 1
}
}
/// Indirect mode "(d.x)"
/// Fetch value from anywhere in memory using an address table built by the user and stored in
/// zero page, indexed on X
/// val = PEEK(PEEK((arg + X) & 0xFF) + PEEK((arg + X + 1) & 0xFF) << 8)
fn mode_indirect_x(&mut self) -> MemoryVal {
let addr_ind = self.read_pc_addr() as u16 + self.x as u16;
// fetch indirect addr to jump to
let addr_lo = self.bus.read_addr(addr_ind & 0xFF) as u16;
let addr_hi = self.bus.read_addr((addr_ind + 1) & 0xFF) as u16;
let addr = addr_lo | (addr_hi << 8);
MemoryVal {
addr,
cycles: 6,
}
}
/// Indirect mode "(d).y"
/// Fetch value from anywhere in memory using a stored address, indexed on Y
/// val = PEEK(PEEK(arg) + PEEK((arg + 1) & 0xFF) << 8 + Y)
fn mode_indirect_y(&mut self) -> MemoryValExtra {
let addr_ind = self.read_pc_addr() as u16;
// fetch indirect addr to jump to
let addr_lo = self.bus.read_addr(addr_ind) as u16;
let addr_hi = self.bus.read_addr((addr_ind + 1) & 0xFF) as u16;
let mut addr = addr_lo | (addr_hi << 8) ;
// compute index
let extra_cycle = (addr_lo + (self.y as u16)) & 0xFF00 != 0;
addr += self.y as u16;
MemoryValExtra {
addr,
cycles: 5,
extra_cycle,
}
}
/// Accumulator mode "A"
/// Directly use the accumulator as input and/or output
fn mode_accumulator(&self) -> Accumulator {
Accumulator {}
}
/// Increment PC, then read corresponding value in memory
fn read_pc_addr(&mut self) -> u8 {
let val = self.bus.read_addr(self.pc);
self.pc += 1;
val
}
/// Write data, then decrement stack pointer. The stack is stored between 0x01FF and 0x0100
fn push_stack(&mut self, data: u8) {
self.bus.write_addr(self.s as u16 | 0x0100, data);
self.s = self.s.wrapping_sub(1);
}
/// Read data, then increment stack pointer
fn pop_stack(&mut self) -> u8 {
self.s = self.s.wrapping_add(1);
let data = self.bus.read_addr(self.s as u16 | 0x0100);
data
}
fn adc<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// add acc and value
let prev_a = self.a as u16;
let mut a = self.a as u16;
if self.p.contains(StatusReg::C) {
a = a.wrapping_add(1);
}
a = a.wrapping_add((val & 0xFF) as u16);
// handle status bits
self.p.set(StatusReg::C, a & 0xFF00 != 0);
self.p.set(StatusReg::Z, a & 0xFF == 0);
if ((prev_a & 0x80) !=0 && (val & 0x80) != 0 && (a & 0x80) == 0)
|| ((prev_a & 0x80) == 0 && (val & 0x80) == 0 && (a & 0x80) != 0) {
self.p.set(StatusReg::V, true);
} else {
self.p.set(StatusReg::V, false);
}
self.p.set(StatusReg::N, a & 0x80 != 0);
// truncate accumulator to 8 bits
self.a = a as u8;
input.get_cycles()
}
fn and<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// logical AND between acc and value
self.a &= val;
// handle status bits
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, self.a & 0x80 != 0);
input.get_cycles()
}
fn asl<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut target = input.read(&self.a, &self.bus) as u16;
// shift target one bit left
target = target << 1;
// handle status bits
self.p.set(StatusReg::C, target & 0xFF00 != 0);
self.p.set(StatusReg::Z, target & 0xFF == 0);
self.p.set(StatusReg::N, target & 0x80 != 0);
// store result
input.write(&mut self.a, &mut self.bus, target as u8);
input.get_cycles() + 2
}
fn branch_if<I: RInput>(&mut self, cond: bool, input: I) -> u32 {
let offset = input.read(&self.a, &self.bus) as i8;
match cond {
false => input.get_cycles(),
true => {
let old_pc = self.pc;
self.pc = self.pc.wrapping_add(offset as u16);
match old_pc & 0xFF00 == self.pc & 0xFF00 {
true => input.get_cycles() + 1,
false => input.get_cycles() + 2,
}
}
}
}
fn bcc<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(!self.p.contains(StatusReg::C), input)
}
fn bcs<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(self.p.contains(StatusReg::C), input)
}
fn beq<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(self.p.contains(StatusReg::Z), input)
}
fn bit<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// logical AND between acc and value
let and = self.a & val;
// handle status bits
self.p.set(StatusReg::Z, and == 0);
self.p.set(StatusReg::V, (val & 0x1 << 6) != 0);
self.p.set(StatusReg::N, (val & 0x1 << 7) != 0);
input.get_cycles()
}
fn bmi<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(self.p.contains(StatusReg::N), input)
}
fn bne<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(!self.p.contains(StatusReg::Z), input)
}
fn bpl<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(!self.p.contains(StatusReg::N), input)
}
fn brk(&mut self, _: ()) -> u32 {
// store PC on stack
let pc = self.pc.wrapping_add(1);
self.push_stack((pc >> 8) as u8);
self.push_stack(pc as u8);
// store status register
self.p.set(StatusReg::B | StatusReg::U, true);
self.push_stack(self.p.bits() as u8);
// load interrupt vector
let pc_lo = self.bus.read_addr(0xFFFE) as u16;
let pc_hi = self.bus.read_addr(0xFFFF) as u16;
self.pc = pc_lo | (pc_hi << 8);
// inhibit further interrupts
self.p.set(StatusReg::I, true);
7
}
fn bvc<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(!self.p.contains(StatusReg::V), input)
}
fn bvs<I: RInput>(&mut self, input: I) -> u32 {
self.branch_if(self.p.contains(StatusReg::V), input)
}
fn clc(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::C, false);
2
}
fn cld(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::D, false);
2
}
fn cli(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::I, false);
2
}
fn clv(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::V, false);
2
}
fn compute_cmp<I: RInput>(&mut self, reg: u8, input: I) -> u32 {
let val = input.read(&self.a, &self.bus) as u8;
self.p.set(StatusReg::C, reg >= val);
self.p.set(StatusReg::Z, reg == val);
self.p.set(StatusReg::N, ((reg.wrapping_sub(val)) & (0x1 << 7)) != 0);
input.get_cycles()
}
fn cmp<I: RInput>(&mut self, input: I) -> u32 {
self.compute_cmp(self.a, input)
}
fn cpx<I: RInput>(&mut self, input: I) -> u32 {
self.compute_cmp(self.x, input)
}
fn cpy<I: RInput>(&mut self, input: I) -> u32 {
self.compute_cmp(self.y, input)
}
fn dec<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut val = input.read(&self.a, &self.bus);
// compute
val = val.wrapping_sub(1);
self.p.set(StatusReg::Z, val == 0);
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
// store result
input.write(&mut self.a, &mut self.bus, val);
input.get_cycles() + 2
}
fn dex(&mut self, _: ()) -> u32 {
// compute
self.x = self.x.wrapping_sub(1);
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
2
}
fn dey(&mut self, _: ()) -> u32 {
// compute
self.y = self.y.wrapping_sub(1);
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
2
}
fn eor<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// compute
self.a = (!self.a & val) | (self.a & !val);
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
input.get_cycles()
}
fn inc<I:RWInput>(&mut self, mut input: I) -> u32 {
let mut val = input.read(&self.a, &self.bus);
// compute
val = val.wrapping_add(1);
self.p.set(StatusReg::Z, val == 0);
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
// store result
input.write(&mut self.a, &mut self.bus, val);
input.get_cycles() + 2
}
fn inx(&mut self, _: ()) -> u32 {
// compute
self.x = self.x.wrapping_add(1);
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
2
}
fn iny(&mut self, _: ()) -> u32 {
// compute
self.y = self.y.wrapping_add(1);
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
2
}
fn jmp(&mut self, input: MemoryVal) -> u32 {
self.pc = input.addr;
input.get_cycles() - 1
}
fn jsr(&mut self, input: MemoryVal) -> u32 {
// store return point
let pc = self.pc.wrapping_sub(1);
self.push_stack((pc >> 8) as u8);
self.push_stack(pc as u8);
// load target address
self.pc = input.addr;
return input.get_cycles() + 2
}
fn lda<I: RInput>(&mut self, input: I) -> u32 {
// store value and compute flags
self.a = input.read(&self.a, &self.bus);
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
input.get_cycles()
}
fn ldx<I: RInput>(&mut self, input: I) -> u32 {
// store value and compute flags
self.x = input.read(&self.a, &self.bus);
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
input.get_cycles()
}
fn ldy<I: RInput>(&mut self, input: I) -> u32 {
// store value and compute flags
self.y = input.read(&self.a, &self.bus);
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
input.get_cycles()
}
fn lsr<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut target = input.read(&self.a, &self.bus);
// set carry bit
self.p.set(StatusReg::C, (target & 0x1) != 0);
// shift value
target = target >> 1;
// set zero and negative bits
self.p.set(StatusReg::Z, target == 0);
self.p.set(StatusReg::N, false); //bit 7 is always 0
// store value
input.write(&mut self.a, &mut self.bus, target);
input.get_cycles() + 2
}
fn nop(&self, _: ()) -> u32 {
// do nothing
2
}
fn ora<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// compute
self.a = self.a | val;
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
input.get_cycles()
}
fn pha(&mut self, _: ()) -> u32 {
self.push_stack(self.a);
3
}
fn php(&mut self, _: ()) -> u32 {
let mut p = self.p;
p.set(StatusReg::B | StatusReg::U, true);
self.push_stack(p.bits() as u8);
3
}
fn pla(&mut self, _: ()) -> u32 {
self.a = self.pop_stack();
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
4
}
fn plp(&mut self, _: ()) -> u32 {
self.p = StatusReg::from_bits_truncate(self.pop_stack());
self.p.remove(StatusReg::B | StatusReg::U);
4
}
fn rol<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut val = input.read(&self.a, &self.bus);
// store bit 7 and compute
let carry = val & (0x1 << 7) != 0;
val = val << 1;
// update bit 0 and carry bit
if self.p.contains(StatusReg::C) {
val |= 0x1 << 0;
}
self.p.set(StatusReg::C, carry);
// update status bits
self.p.set(StatusReg::Z, val == 0);
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
// store value
input.write(&mut self.a, &mut self.bus, val);
input.get_cycles() + 2
}
fn ror<I: RWInput>(&mut self, mut input: I) -> u32 {
let mut val = input.read(&self.a, &self.bus);
// store bit 0 and compute
let carry = val & (0x1 << 0) != 0;
val = val >> 1;
// update bit 7 and carry bit
if self.p.contains(StatusReg::C) {
val |= 0x1 << 7;
}
self.p.set(StatusReg::C, carry);
// update status bits
self.p.set(StatusReg::Z, val == 0);
self.p.set(StatusReg::N, (val & (0x1 << 7)) != 0);
// store value
input.write(&mut self.a, &mut self.bus, val);
input.get_cycles() + 2
}
fn rti(&mut self, _: ()) -> u32 {
// load status register (B is cleared and I overrided)
self.p = StatusReg::from_bits_truncate(self.pop_stack());
self.p.set(StatusReg::B | StatusReg::U, false);
// load pc
let pc_lo = self.pop_stack() as u16;
let pc_hi = self.pop_stack() as u16;
self.pc = pc_lo | (pc_hi << 8);
6
}
fn rts(&mut self, _: ()) -> u32 {
// load pc
let pc_lo = self.pop_stack() as u16;
let pc_hi = self.pop_stack() as u16;
self.pc = pc_lo | (pc_hi << 8);
self.pc = self.pc.wrapping_add(1);
6
}
fn sbc<I: RInput>(&mut self, input: I) -> u32 {
let val = input.read(&self.a, &self.bus);
// sub acc and value
let prev_a = self.a as u16;
let mut a = self.a as u16;
if !self.p.contains(StatusReg::C) {
a = a.wrapping_sub(1);
}
a = a.wrapping_sub((val & 0xFF) as u16);
// handle status bits
self.p.set(StatusReg::C, a & 0xFF00 == 0);
self.p.set(StatusReg::Z, a & 0xFF == 0);
if ((prev_a & 0x80) !=0 && (val & 0x80) != 0 && (a & 0x80) == 0)
|| ((prev_a & 0x80) == 0 && (val & 0x80) == 0 && (a & 0x80) != 0) {
self.p.set(StatusReg::V, true);
} else {
self.p.set(StatusReg::V, false);
}
self.p.set(StatusReg::N, a & 0x80 != 0);
// truncate accumulator to 8 bits
self.a = a as u8;
input.get_cycles()
}
fn sec(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::C, true);
2
}
fn sed(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::D, true);
2
}
fn sei(&mut self, _: ()) -> u32 {
self.p.set(StatusReg::I, true);
2
}
fn sta<I: RWInput>(&mut self, mut input: I) -> u32 {
let a = self.a;
input.write(&mut self.a, &mut self.bus, a);
input.get_cycles()
}
fn stx<I: RWInput>(&mut self, mut input: I) -> u32 {
let x = self.x;
input.write(&mut self.a, &mut self.bus, x);
input.get_cycles()
}
fn sty<I: RWInput>(&mut self, mut input: I) -> u32 {
let y = self.y;
input.write(&mut self.a, &mut self.bus, y);
input.get_cycles()
}
fn tax(&mut self, _: ()) -> u32 {
self.x = self.a;
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
2
}
fn tay(&mut self, _: ()) -> u32 {
self.y = self.a;
self.p.set(StatusReg::Z, self.y == 0);
self.p.set(StatusReg::N, (self.y & (0x1 << 7)) != 0);
2
}
fn tsx(&mut self, _: ()) -> u32 {
self.x = self.s;
self.p.set(StatusReg::Z, self.x == 0);
self.p.set(StatusReg::N, (self.x & (0x1 << 7)) != 0);
2
}
fn txa(&mut self, _: ()) -> u32 {
self.a = self.x;
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
2
}
fn txs(&mut self, _: ()) -> u32 {
self.s = self.x;
2
}
fn tya(&mut self, _: ()) -> u32 {
self.a = self.y;
self.p.set(StatusReg::Z, self.a == 0);
self.p.set(StatusReg::N, (self.a & (0x1 << 7)) != 0);
2
}
}