#[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(&self, acc: &u8, bus: &M) -> u8; } trait WInput: Input { fn write(&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(&self, acc: &u8, _bus: &M) -> u8 { *acc } } impl WInput for Accumulator { fn write(&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(&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(&self, _acc: &u8, bus: &M) -> u8 { bus.read_addr(self.addr) } } impl WInput for MemoryVal { fn write(&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(&self, _acc: &u8, bus: &M) -> u8 { bus.read_addr(self.addr) } } impl WInput for MemoryValExtra { fn write(&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 { a: u8, x: u8, y: u8, pc: u16, s: u8, p: StatusReg, bus: Bus, tick_counter: u8, } impl fmt::Debug for Cpu { 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 Cpu { pub fn new(mapper: Rc>, screen: Rc>, pattern_table: Rc>) -> 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(&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(&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(&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(&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(&mut self, input: I) -> u32 { self.branch_if(!self.p.contains(StatusReg::C), input) } fn bcs(&mut self, input: I) -> u32 { self.branch_if(self.p.contains(StatusReg::C), input) } fn beq(&mut self, input: I) -> u32 { self.branch_if(self.p.contains(StatusReg::Z), input) } fn bit(&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(&mut self, input: I) -> u32 { self.branch_if(self.p.contains(StatusReg::N), input) } fn bne(&mut self, input: I) -> u32 { self.branch_if(!self.p.contains(StatusReg::Z), input) } fn bpl(&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(&mut self, input: I) -> u32 { self.branch_if(!self.p.contains(StatusReg::V), input) } fn bvs(&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(&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(&mut self, input: I) -> u32 { self.compute_cmp(self.a, input) } fn cpx(&mut self, input: I) -> u32 { self.compute_cmp(self.x, input) } fn cpy(&mut self, input: I) -> u32 { self.compute_cmp(self.y, input) } fn dec(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&mut self, mut input: I) -> u32 { let a = self.a; input.write(&mut self.a, &mut self.bus, a); input.get_cycles() } fn stx(&mut self, mut input: I) -> u32 { let x = self.x; input.write(&mut self.a, &mut self.bus, x); input.get_cycles() } fn sty(&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 } }