use crate::core::bus::Bus;
#[allow(dead_code)]
const NMI_VECTOR: u16 = 0xFFFA;
const RESET_VECTOR: u16 = 0xFFFC;
const IRQ_VECTOR: u16 = 0xFFFE;
#[allow(clippy::upper_case_acronyms)]
pub struct CPU {
a: u8, x: u8, y: u8, sp: u8, pc: u16, sr: u8, opcode: u8, bus: Bus, }
impl CPU {
pub fn new(bus: Bus) -> Self {
CPU {
a: 0x00,
x: 0x00,
y: 0x00,
sp: 0xFF,
pc: 0x0000,
sr: 0x00,
opcode: 0x00,
bus,
}
}
pub fn write(&mut self, addr: u16, data: u8) {
self.bus.write(addr, data);
}
pub fn read(&mut self, addr: u16) -> u8 {
self.bus.read(addr)
}
pub fn write_u16(&mut self, addr: u16, data: u16) {
self.bus.write_u16(addr, data);
}
pub fn read_u16(&mut self, addr: u16) -> u16 {
self.bus.read_u16(addr)
}
pub fn push(&mut self, data: u8) {
self.sp -= 0x01;
self.write(0x0100 + (self.sp as u16), data);
}
pub fn push_u16(&mut self, data: u16) {
let lo = data as u8;
let hi = (data >> 8) as u8;
self.push(lo);
self.push(hi);
}
pub fn pop(&mut self) -> u8 {
let data = self.read(0x0100 + (self.sp as u16));
self.sp += 1;
data
}
pub fn pop_u16(&mut self) -> u16 {
let lo = self.pop() as u16;
let hi = self.pop() as u16;
(hi << 8) | lo
}
pub fn get_flag(&mut self, f: Flags) -> bool {
self.sr & (f as u8) != 0
}
pub fn set_flag(&mut self, f: Flags, v: bool) {
if v {
self.sr |= f as u8;
} else {
self.sr &= !(f as u8);
}
}
pub fn set_zero_negative_flags(&mut self, value: u8) {
self.set_flag(Flags::Z, value == 0x00);
self.set_flag(Flags::N, (value & 0x80) == 0x80);
}
pub fn reset(&mut self) {
self.pc = RESET_VECTOR;
self.a = 0;
self.x = 0;
self.y = 0;
self.sp = 0xFF;
self.sr = 0;
self.opcode = 0;
}
pub fn clock(&mut self) {
if self.pc == RESET_VECTOR {
let program_start: u16 = self.read_u16(self.pc);
self.pc = program_start;
}
loop {
self.opcode = self.read(self.pc);
self.pc += 1;
if self.opcode == 0x00 { break }
match self.opcode {
0x00 => self.BRK(AddressingMode::IMP), 0x01 => self.ORA(AddressingMode::ZPX), 0x05 => self.ORA(AddressingMode::ZP0), 0x06 => self.ASL(AddressingMode::ZP0), 0x08 => self.PHP(AddressingMode::IMP), 0x09 => self.ORA(AddressingMode::IMM), 0x0A => self.ASL(AddressingMode::ACC), 0x0D => self.ORA(AddressingMode::ABS), 0x0E => self.ASL(AddressingMode::ABS),
0x10 => self.BPL(AddressingMode::REL), 0x11 => self.ORA(AddressingMode::ZPY), 0x15 => self.ORA(AddressingMode::ZPX), 0x16 => self.ASL(AddressingMode::ZPX), 0x18 => self.CLC(AddressingMode::IMP), 0x1D => self.ORA(AddressingMode::ABX), 0x1E => self.ASL(AddressingMode::ABX),
0x20 => self.JSR(AddressingMode::ABS), 0x21 => self.AND(AddressingMode::ZPX), 0x24 => self.BIT(AddressingMode::ZP0), 0x25 => self.AND(AddressingMode::ZP0), 0x26 => self.ROL(AddressingMode::ZP0), 0x28 => self.PLP(AddressingMode::IMP), 0x29 => self.AND(AddressingMode::IMM), 0x2A => self.ROL(AddressingMode::ACC), 0x2C => self.BIT(AddressingMode::ABS), 0x2D => self.AND(AddressingMode::ABS), 0x2E => self.ROL(AddressingMode::ABS),
0x30 => self.BMI(AddressingMode::REL), 0x31 => self.AND(AddressingMode::ZPX), 0x35 => self.AND(AddressingMode::ZPX), 0x36 => self.ROL(AddressingMode::ZPX), 0x38 => self.SEC(AddressingMode::IMP), 0x39 => self.AND(AddressingMode::ABY), 0x3D => self.AND(AddressingMode::ABX), 0x3E => self.ROL(AddressingMode::ABX),
0x40 => self.RTI(AddressingMode::IMP), 0x41 => self.EOR(AddressingMode::ZPX), 0x45 => self.EOR(AddressingMode::ZP0), 0x46 => self.LSR(AddressingMode::ZP0), 0x48 => self.PHA(AddressingMode::IMP), 0x49 => self.EOR(AddressingMode::IMM), 0x4A => self.LSR(AddressingMode::ACC), 0x4C => self.JMP(AddressingMode::ABS), 0x4D => self.EOR(AddressingMode::ABS), 0x4E => self.LSR(AddressingMode::ABS),
0x50 => self.BVC(AddressingMode::REL), 0x51 => self.EOR(AddressingMode::ZPY), 0x55 => self.EOR(AddressingMode::ZPY), 0x56 => self.LSR(AddressingMode::ZPX), 0x58 => self.CLI(AddressingMode::IMP), 0x59 => self.EOR(AddressingMode::ABY), 0x5D => self.EOR(AddressingMode::ABX), 0x5E => self.LSR(AddressingMode::ABX),
0x60 => self.RTS(AddressingMode::IMP), 0x61 => self.ADC(AddressingMode::ZPX), 0x65 => self.ADC(AddressingMode::ZP0), 0x66 => self.ROR(AddressingMode::ZP0), 0x68 => self.PLA(AddressingMode::IMP), 0x69 => self.ADC(AddressingMode::IMM), 0x6A => self.ROR(AddressingMode::ACC), 0x6C => self.JMP(AddressingMode::IND), 0x6D => self.ADC(AddressingMode::ABS), 0x6E => self.ROR(AddressingMode::ABS),
0x70 => self.BVS(AddressingMode::REL), 0x71 => self.ADC(AddressingMode::ZPY), 0x75 => self.ADC(AddressingMode::ZPX), 0x78 => self.SEI(AddressingMode::IMP), 0x79 => self.ADC(AddressingMode::ABY), 0x7D => self.ADC(AddressingMode::ABX), 0x7E => self.ROR(AddressingMode::ABX),
0x80 => self.NOP(AddressingMode::IMM), 0x81 => self.STA(AddressingMode::ZPX), 0x84 => self.STY(AddressingMode::ZP0), 0x85 => self.STA(AddressingMode::ZP0), 0x86 => self.STX(AddressingMode::ZP0), 0x88 => self.DEY(AddressingMode::IMP), 0x8A => self.TXA(AddressingMode::IMP), 0x8C => self.STY(AddressingMode::ABS), 0x8D => self.STA(AddressingMode::ABS), 0x8E => self.STX(AddressingMode::ABS),
0x90 => self.BCC(AddressingMode::REL), 0x91 => self.STA(AddressingMode::IDY), 0x94 => self.STY(AddressingMode::ZPX), 0x95 => self.STA(AddressingMode::ZPX), 0x96 => self.STX(AddressingMode::ZPY), 0x98 => self.TYA(AddressingMode::IMP), 0x99 => self.STA(AddressingMode::ABY), 0x9A => self.TXS(AddressingMode::IMP), 0x9D => self.STA(AddressingMode::ABX),
0xA0 => self.LDY(AddressingMode::IMM), 0xA1 => self.LDA(AddressingMode::ZPX), 0xA2 => self.LDX(AddressingMode::IMM), 0xA4 => self.LDY(AddressingMode::ZP0), 0xA5 => self.LDA(AddressingMode::ZP0), 0xA6 => self.LDX(AddressingMode::ZP0), 0xA8 => self.TAY(AddressingMode::IMP), 0xA9 => self.LDA(AddressingMode::IMM), 0xAA => self.TAX(AddressingMode::IMP), 0xAC => self.LDY(AddressingMode::ABS), 0xAD => self.LDA(AddressingMode::ABS), 0xAE => self.LDX(AddressingMode::ABS),
0xB0 => self.BCS(AddressingMode::REL), 0xB1 => self.LDA(AddressingMode::ZPY), 0xB4 => self.LDY(AddressingMode::ZPX), 0xB5 => self.LDA(AddressingMode::ZPX), 0xB6 => self.LDX(AddressingMode::ZPY), 0xB8 => self.CLV(AddressingMode::IMP), 0xB9 => self.LDA(AddressingMode::ABY), 0xBA => self.TSX(AddressingMode::IMP), 0xBC => self.LDY(AddressingMode::ABX), 0xBD => self.LDA(AddressingMode::ABX), 0xBE => self.LDX(AddressingMode::ABY),
0xC0 => self.CPY(AddressingMode::IMM), 0xC1 => self.CMP(AddressingMode::ZPX), 0xC4 => self.CPY(AddressingMode::ZP0), 0xC5 => self.CMP(AddressingMode::ZP0), 0xC6 => self.DEC(AddressingMode::ZP0), 0xC8 => self.CLV(AddressingMode::IMP), 0xC9 => self.CMP(AddressingMode::IMM), 0xCA => self.DEX(AddressingMode::IMP), 0xCC => self.CPY(AddressingMode::ABS), 0xCD => self.CMP(AddressingMode::ABS), 0xCE => self.DEC(AddressingMode::ABS),
0xD0 => self.BNE(AddressingMode::REL), 0xD1 => self.CMP(AddressingMode::ZPY), 0xD5 => self.CMP(AddressingMode::ZPX), 0xD6 => self.DEC(AddressingMode::ZPX), 0xD8 => self.CLD(AddressingMode::IMP), 0xD9 => self.CMP(AddressingMode::ABY), 0xDD => self.CMP(AddressingMode::ABX), 0xDE => self.DEC(AddressingMode::ABX),
0xE0 => self.CPX(AddressingMode::IMM), 0xE1 => self.SBC(AddressingMode::ZPX), 0xE4 => self.CPX(AddressingMode::ZP0), 0xE5 => self.SBC(AddressingMode::ZP0), 0xE6 => self.INC(AddressingMode::ZP0), 0xE8 => self.INX(AddressingMode::IMP), 0xE9 => self.SBC(AddressingMode::IMM), 0xEA => self.NOP(AddressingMode::IMP), 0xEC => self.CPX(AddressingMode::ABS), 0xED => self.SBC(AddressingMode::ABS), 0xEE => self.INC(AddressingMode::ABS),
0xF0 => self.BEQ(AddressingMode::REL), 0xF1 => self.SBC(AddressingMode::ZPY), 0xF5 => self.SBC(AddressingMode::ZPX), 0xF6 => self.INC(AddressingMode::ZPX), 0xF8 => self.SED(AddressingMode::IMP), 0xF9 => self.SBC(AddressingMode::ABY), 0xFD => self.SBC(AddressingMode::ABX), 0xFE => self.INC(AddressingMode::ABX),
_ => self.XXX(AddressingMode::IMP),
}
}
}
pub fn advance(&mut self) {
if self.pc == RESET_VECTOR {
let program_start: u16 = self.read_u16(self.pc);
self.pc = program_start;
} else {
self.opcode = self.read(self.pc);
self.pc += 1;
if self.opcode == 0x00 {
return
}
match self.opcode {
0x00 => self.BRK(AddressingMode::IMP), 0x01 => self.ORA(AddressingMode::ZPX), 0x05 => self.ORA(AddressingMode::ZP0), 0x06 => self.ASL(AddressingMode::ZP0), 0x08 => self.PHP(AddressingMode::IMP), 0x09 => self.ORA(AddressingMode::IMM), 0x0A => self.ASL(AddressingMode::ACC), 0x0D => self.ORA(AddressingMode::ABS), 0x0E => self.ASL(AddressingMode::ABS),
0x10 => self.BPL(AddressingMode::REL), 0x11 => self.ORA(AddressingMode::ZPY), 0x15 => self.ORA(AddressingMode::ZPX), 0x16 => self.ASL(AddressingMode::ZPX), 0x18 => self.CLC(AddressingMode::IMP), 0x1D => self.ORA(AddressingMode::ABX), 0x1E => self.ASL(AddressingMode::ABX),
0x20 => self.JSR(AddressingMode::ABS), 0x21 => self.AND(AddressingMode::ZPX), 0x24 => self.BIT(AddressingMode::ZP0), 0x25 => self.AND(AddressingMode::ZP0), 0x26 => self.ROL(AddressingMode::ZP0), 0x28 => self.PLP(AddressingMode::IMP), 0x29 => self.AND(AddressingMode::IMM), 0x2A => self.ROL(AddressingMode::ACC), 0x2C => self.BIT(AddressingMode::ABS), 0x2D => self.AND(AddressingMode::ABS), 0x2E => self.ROL(AddressingMode::ABS),
0x30 => self.BMI(AddressingMode::REL), 0x31 => self.AND(AddressingMode::ZPX), 0x35 => self.AND(AddressingMode::ZPX), 0x36 => self.ROL(AddressingMode::ZPX), 0x38 => self.SEC(AddressingMode::IMP), 0x39 => self.AND(AddressingMode::ABY), 0x3D => self.AND(AddressingMode::ABX), 0x3E => self.ROL(AddressingMode::ABX),
0x40 => self.RTI(AddressingMode::IMP), 0x41 => self.EOR(AddressingMode::ZPX), 0x45 => self.EOR(AddressingMode::ZP0), 0x46 => self.LSR(AddressingMode::ZP0), 0x48 => self.PHA(AddressingMode::IMP), 0x49 => self.EOR(AddressingMode::IMM), 0x4A => self.LSR(AddressingMode::ACC), 0x4C => self.JMP(AddressingMode::ABS), 0x4D => self.EOR(AddressingMode::ABS), 0x4E => self.LSR(AddressingMode::ABS),
0x50 => self.BVC(AddressingMode::REL), 0x51 => self.EOR(AddressingMode::ZPY), 0x55 => self.EOR(AddressingMode::ZPY), 0x56 => self.LSR(AddressingMode::ZPX), 0x58 => self.CLI(AddressingMode::IMP), 0x59 => self.EOR(AddressingMode::ABY), 0x5D => self.EOR(AddressingMode::ABX), 0x5E => self.LSR(AddressingMode::ABX),
0x60 => self.RTS(AddressingMode::IMP), 0x61 => self.ADC(AddressingMode::ZPX), 0x65 => self.ADC(AddressingMode::ZP0), 0x66 => self.ROR(AddressingMode::ZP0), 0x68 => self.PLA(AddressingMode::IMP), 0x69 => self.ADC(AddressingMode::IMM), 0x6A => self.ROR(AddressingMode::ACC), 0x6C => self.JMP(AddressingMode::IND), 0x6D => self.ADC(AddressingMode::ABS), 0x6E => self.ROR(AddressingMode::ABS),
0x70 => self.BVS(AddressingMode::REL), 0x71 => self.ADC(AddressingMode::ZPY), 0x75 => self.ADC(AddressingMode::ZPX), 0x78 => self.SEI(AddressingMode::IMP), 0x79 => self.ADC(AddressingMode::ABY), 0x7D => self.ADC(AddressingMode::ABX), 0x7E => self.ROR(AddressingMode::ABX),
0x80 => self.NOP(AddressingMode::IMM), 0x81 => self.STA(AddressingMode::ZPX), 0x84 => self.STY(AddressingMode::ZP0), 0x85 => self.STA(AddressingMode::ZP0), 0x86 => self.STX(AddressingMode::ZP0), 0x88 => self.DEY(AddressingMode::IMP), 0x8A => self.TXA(AddressingMode::IMP), 0x8C => self.STY(AddressingMode::ABS), 0x8D => self.STA(AddressingMode::ABS), 0x8E => self.STX(AddressingMode::ABS),
0x90 => self.BCC(AddressingMode::REL), 0x91 => self.STA(AddressingMode::IDY), 0x94 => self.STY(AddressingMode::ZPX), 0x95 => self.STA(AddressingMode::ZPX), 0x96 => self.STX(AddressingMode::ZPY), 0x98 => self.TYA(AddressingMode::IMP), 0x99 => self.STA(AddressingMode::ABY), 0x9A => self.TXS(AddressingMode::IMP), 0x9D => self.STA(AddressingMode::ABX),
0xA0 => self.LDY(AddressingMode::IMM), 0xA1 => self.LDA(AddressingMode::ZPX), 0xA2 => self.LDX(AddressingMode::IMM), 0xA4 => self.LDY(AddressingMode::ZP0), 0xA5 => self.LDA(AddressingMode::ZP0), 0xA6 => self.LDX(AddressingMode::ZP0), 0xA8 => self.TAY(AddressingMode::IMP), 0xA9 => self.LDA(AddressingMode::IMM), 0xAA => self.TAX(AddressingMode::IMP), 0xAC => self.LDY(AddressingMode::ABS), 0xAD => self.LDA(AddressingMode::ABS), 0xAE => self.LDX(AddressingMode::ABS),
0xB0 => self.BCS(AddressingMode::REL), 0xB1 => self.LDA(AddressingMode::ZPY), 0xB4 => self.LDY(AddressingMode::ZPX), 0xB5 => self.LDA(AddressingMode::ZPX), 0xB6 => self.LDX(AddressingMode::ZPY), 0xB8 => self.CLV(AddressingMode::IMP), 0xB9 => self.LDA(AddressingMode::ABY), 0xBA => self.TSX(AddressingMode::IMP), 0xBC => self.LDY(AddressingMode::ABX), 0xBD => self.LDA(AddressingMode::ABX), 0xBE => self.LDX(AddressingMode::ABY),
0xC0 => self.CPY(AddressingMode::IMM), 0xC1 => self.CMP(AddressingMode::ZPX), 0xC4 => self.CPY(AddressingMode::ZP0), 0xC5 => self.CMP(AddressingMode::ZP0), 0xC6 => self.DEC(AddressingMode::ZP0), 0xC8 => self.CLV(AddressingMode::IMP), 0xC9 => self.CMP(AddressingMode::IMM), 0xCA => self.DEX(AddressingMode::IMP), 0xCC => self.CPY(AddressingMode::ABS), 0xCD => self.CMP(AddressingMode::ABS), 0xCE => self.DEC(AddressingMode::ABS),
0xD0 => self.BNE(AddressingMode::REL), 0xD1 => self.CMP(AddressingMode::ZPY), 0xD5 => self.CMP(AddressingMode::ZPX), 0xD6 => self.DEC(AddressingMode::ZPX), 0xD8 => self.CLD(AddressingMode::IMP), 0xD9 => self.CMP(AddressingMode::ABY), 0xDD => self.CMP(AddressingMode::ABX), 0xDE => self.DEC(AddressingMode::ABX),
0xE0 => self.CPX(AddressingMode::IMM), 0xE1 => self.SBC(AddressingMode::ZPX), 0xE4 => self.CPX(AddressingMode::ZP0), 0xE5 => self.SBC(AddressingMode::ZP0), 0xE6 => self.INC(AddressingMode::ZP0), 0xE8 => self.INX(AddressingMode::IMP), 0xE9 => self.SBC(AddressingMode::IMM), 0xEA => self.NOP(AddressingMode::IMP), 0xEC => self.CPX(AddressingMode::ABS), 0xED => self.SBC(AddressingMode::ABS), 0xEE => self.INC(AddressingMode::ABS),
0xF0 => self.BEQ(AddressingMode::REL), 0xF1 => self.SBC(AddressingMode::ZPY), 0xF5 => self.SBC(AddressingMode::ZPX), 0xF6 => self.INC(AddressingMode::ZPX), 0xF8 => self.SED(AddressingMode::IMP), 0xF9 => self.SBC(AddressingMode::ABY), 0xFD => self.SBC(AddressingMode::ABX), 0xFE => self.INC(AddressingMode::ABX),
_ => self.XXX(AddressingMode::IMP),
}
}
}
#[allow(unused)]
fn irq(&mut self) {
if !self.get_flag(Flags::I) {
self.push_u16(self.pc);
self.push(self.sr);
self.pc = self.read_u16(IRQ_VECTOR)
}
}
#[allow(unused)]
fn nmi(&mut self) {
todo!();
}
}
#[derive(PartialEq)]
#[allow(clippy::upper_case_acronyms, dead_code)]
pub enum AddressingMode {
IMM,
IMP,
ZP0,
ZPX,
ZPY,
ABS,
ABX,
ABY,
IND,
IDX,
IDY,
REL,
ACC,
}
impl CPU {
pub fn get_address(&mut self, mode: AddressingMode) -> u16 {
match mode {
AddressingMode::IMM => {
let addr = self.pc;
self.pc += 1;
addr
},
AddressingMode::IMP => {
panic!("not supported");
},
AddressingMode::ZP0 => {
let addr = self.read(self.pc) as u16;
self.pc += 1;
addr
},
AddressingMode::ZPX => {
let addr = self.read(self.pc).wrapping_add(self.x) as u16;
self.pc += 1;
addr
},
AddressingMode::ZPY => {
let addr = self.read(self.pc).wrapping_add(self.y) as u16;
self.pc += 1;
addr
},
AddressingMode::ABS => {
let addr = self.read_u16(self.pc);
self.pc += 2;
addr
},
AddressingMode::ABX => {
let addr = self.read_u16(self.pc).wrapping_add(self.x as u16);
self.pc += 2;
addr
},
AddressingMode::ABY => {
let addr = self.read_u16(self.pc).wrapping_add(self.y as u16);
self.pc += 2;
addr
},
AddressingMode::IND => {
let addr = self.read_u16(self.pc);
self.pc += 2;
let ptr = self.read_u16(addr);
self.pc += 2;
ptr
},
AddressingMode::IDX => {
let base = self.read(self.pc);
let ptr = base + self.x;
let lo = self.read(ptr as u16);
let hi = self.read((ptr + 1) as u16);
self.pc += 2;
(hi as u16) << 8 | (lo as u16)
},
AddressingMode::IDY => {
let zp_addr = self.read(self.pc);
let base = self.read(zp_addr as u16);
let ptr = base + self.y;
let lo = self.read(ptr as u16);
self.pc += 2;
lo as u16
},
AddressingMode::REL => todo!(),
AddressingMode::ACC => todo!(),
}
}
}
#[allow(non_snake_case)]
#[allow(unused)]
impl CPU {
fn ADC(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
let operand: u8 = self.read(addr);
let result_u16: u16 = self.a as u16 + operand as u16 + (self.sr & 0x01) as u16;
let result_u8: u8 = result_u16 as u8;
self.set_flag(Flags::C, result_u16 > 0xFF);
self.set_flag(Flags::V, self.a & 0x80 == operand & 0x80 && self.a & 0x80 != result_u8 & 0x80);
self.a = result_u8;
self.set_zero_negative_flags(self.a);
}
fn AND(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
let value: u8 = self.read(addr);
self.a &= value;
self.set_zero_negative_flags(self.a);
}
fn ASL(&mut self, mode: AddressingMode) {
println!("ASL");
if mode == AddressingMode::ACC {
self.set_flag(Flags::C, self.a & 0x80 == 0x80);
self.a <<= 1;
self.set_zero_negative_flags(self.a);
} else {
let addr: u16 = self.get_address(mode);
let value: u8 = self.read(addr);
self.set_flag(Flags::C, value & 0x80 == 0x80);
let result = value << 1;
self.write(addr, result);
self.set_zero_negative_flags(result);
}
}
fn BCC(&mut self, mode: AddressingMode) {
if !self.get_flag(Flags::C) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn BCS(&mut self, mode: AddressingMode) {
if self.get_flag(Flags::C) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn BEQ(&mut self, mode: AddressingMode) {
if self.get_flag(Flags::Z) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn BIT(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
let value: u8 = self.read(addr);
let result = self.a & value;
self.set_flag(Flags::Z, result == 0x00);
self.set_flag(Flags::V, (value & 0x40) == 0x40);
self.set_flag(Flags::N, (value & 0x80) == 0x80);
}
fn BMI(&mut self, mode: AddressingMode) {
if self.get_flag(Flags::N) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn BNE(&mut self, mode: AddressingMode) {
if !self.get_flag(Flags::Z) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn BPL(&mut self, mode: AddressingMode) {
if !self.get_flag(Flags::N) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn BRK(&mut self, mode: AddressingMode) {
self.push_u16(self.pc);
self.set_flag(Flags::B, true);
self.push(self.sr);
self.pc = self.read_u16(IRQ_VECTOR);
self.set_flag(Flags::I, true);
}
fn BVC(&mut self, mode: AddressingMode) {
if !self.get_flag(Flags::V) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn BVS(&mut self, mode: AddressingMode) {
if self.get_flag(Flags::V) {
let offset = self.read(self.pc);
if offset >= 128 {
self.pc -= ((!offset) + 1) as u16;
} else {
self.pc += offset as u16;
}
}
}
fn CLC(&mut self, mode: AddressingMode) {
self.set_flag(Flags::C, false);
}
fn CLD(&mut self, mode: AddressingMode) {
self.set_flag(Flags::D, false);
}
fn CLI(&mut self, mode: AddressingMode) {
self.set_flag(Flags::I, false);
}
fn CLV(&mut self, mode: AddressingMode) {
self.set_flag(Flags::V, false);
}
fn CMP(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
let value = self.read(addr);
let result = self.a - value;
self.set_zero_negative_flags(result);
self.set_flag(Flags::C, self.a >= value);
self.a = result;
}
fn CPX(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
let value = self.read(addr);
let result = self.x - value;
self.set_zero_negative_flags(result);
self.set_flag(Flags::C, self.x >= value);
self.x = result;
}
fn CPY(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
let value = self.read(addr);
let result = self.y - value;
self.set_zero_negative_flags(result);
self.set_flag(Flags::C, self.y >= value);
self.y = result;
}
fn DEC(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
let mut value: u8 = self.read(addr);
value -= 1;
self.write(addr, value);
self.set_zero_negative_flags(value);
}
fn DEX(&mut self, mode: AddressingMode) {
self.x -= 1;
self.set_zero_negative_flags(self.x);
}
fn DEY(&mut self, mode: AddressingMode) {
self.y -= 1;
self.set_zero_negative_flags(self.y);
}
fn EOR(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
let value: u8 = self.read(addr);
self.a ^= value;
self.set_zero_negative_flags(self.a);
}
fn INC(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
let mut value: u8 = self.read(addr);
value += 1;
self.write(addr, value);
self.set_zero_negative_flags(value);
}
fn INX(&mut self, mode: AddressingMode) {
self.x += 1;
self.set_zero_negative_flags(self.x);
}
fn INY(&mut self, mode: AddressingMode) {
self.y += 1;
self.set_zero_negative_flags(self.y);
}
fn JMP(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
self.pc = addr;
}
fn JSR(&mut self, mode: AddressingMode) {
self.push_u16(self.pc - 1);
let addr = self.get_address(mode);
self.pc = addr;
}
fn LDA(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
self.a = self.read(addr);
self.set_zero_negative_flags(self.a);
}
fn LDX(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
self.x = self.read(addr);
self.set_zero_negative_flags(self.x);
}
fn LDY(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
self.y = self.read(addr);
self.set_zero_negative_flags(self.y);
}
fn LSR(&mut self, mode: AddressingMode) {
println!("LSR");
if mode == AddressingMode::ACC {
self.set_flag(Flags::C, self.a & 0x01 == 0x01);
self.a >>= 1;
self.set_zero_negative_flags(self.a);
} else {
let addr = self.get_address(mode);
let value = self.read(addr);
self.set_flag(Flags::C, value & 0x01 == 0x01);
let result = value >> 1;
self.write(addr, result);
self.set_zero_negative_flags(result);
}
}
fn NOP(&mut self, mode: AddressingMode) {}
fn ORA(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
let value: u8 = self.read(addr);
self.a |= value;
self.set_zero_negative_flags(self.a);
}
fn PHA(&mut self, mode: AddressingMode) {
self.push(self.a);
}
fn PHP(&mut self, mode: AddressingMode) {
self.push(self.sr);
}
fn PLA(&mut self, mode: AddressingMode) {
self.a = self.pop();
self.set_zero_negative_flags(self.a);
}
fn PLP(&mut self, mode: AddressingMode) {
self.sr = self.pop();
}
fn ROL(&mut self, mode: AddressingMode) {
if mode == AddressingMode::ACC {
let bit_seven: bool = self.a & 0x80 == 0x80;
let mut result = self.a << 1;
result |= self.sr & 0x01;
self.a = result;
self.set_flag(Flags::C, bit_seven);
self.set_zero_negative_flags(self.a);
} else {
let addr = self.get_address(mode);
let value = self.read(addr);
let bit_seven: bool = value & 0x80 == 0x80;
let mut result = value << 1;
result |= self.sr & 0x01;
self.write(addr, result);
self.set_flag(Flags::C, bit_seven);
self.set_zero_negative_flags(result);
}
}
fn ROR(&mut self, mode: AddressingMode) {
if mode == AddressingMode::ACC {
let bit_zero: bool = self.a & 0x01 == 0x01;
let mut result = self.a >> 1;
result |= (self.sr & 0x01) << 7;
self.a = result;
self.set_flag(Flags::C, bit_zero);
self.set_zero_negative_flags(self.a);
} else {
let addr = self.get_address(mode);
let value = self.read(addr);
let bit_zero: bool = value & 0x01 == 0x01;
let mut result = value << 1;
result |= (self.sr & 0x01) << 7;
self.write(addr, result);
self.set_flag(Flags::C, bit_zero);
self.set_zero_negative_flags(result);
}
}
fn RTI(&mut self, mode: AddressingMode) {
self.sr = self.pop();
self.pc = self.pop_u16();
}
fn RTS(&mut self, mode: AddressingMode) {
self.pc = self.pop_u16();
}
fn SBC(&mut self, mode: AddressingMode) {
let addr = self.get_address(mode);
let operand = self.read(addr);
let result_i16: i16 = self.a as i16 - operand as i16 - (self.sr & 0x01) as i16;
let result_u8: u8 = result_i16 as u8;
self.set_flag(Flags::C, result_i16 < 0xFF);
self.set_flag(Flags::V, self.a & 0x80 != operand & 0x80 && operand & 0x80 == result_u8 & 0x80);
self.a = result_u8;
self.set_zero_negative_flags(self.a);
}
fn SEC(&mut self, mode: AddressingMode) {
self.set_flag(Flags::C, true);
}
fn SED(&mut self, mode: AddressingMode) {
self.set_flag(Flags::D, true);
}
fn SEI(&mut self, mode: AddressingMode) {
self.set_flag(Flags::I, true);
}
fn STA(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
self.write(addr, self.a);
}
fn STX(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
self.write(addr, self.x);
}
fn STY(&mut self, mode: AddressingMode) {
let addr: u16 = self.get_address(mode);
self.write(addr, self.y);
}
fn TAX(&mut self, mode: AddressingMode) {
self.x = self.a;
self.set_zero_negative_flags(self.x);
}
fn TAY(&mut self, mode: AddressingMode) {
self.y = self.a;
self.set_zero_negative_flags(self.y);
}
fn TSX(&mut self, mode: AddressingMode) {
self.x = self.sp;
self.set_zero_negative_flags(self.x);
}
fn TXA(&mut self, mode: AddressingMode) {
self.a = self.x;
self.set_zero_negative_flags(self.a);
}
fn TXS(&mut self, mode: AddressingMode) {
self.sp = self.x;
}
fn TYA(&mut self, mode: AddressingMode) {
self.a = self.y;
self.set_zero_negative_flags(self.a);
}
fn XXX(&mut self, mode: AddressingMode) {
panic!("Illegal operation!");
}
}
#[allow(unused)]
pub enum Flags {
C = 0b0000_0001,
Z = 0b0000_0010,
I = 0b0000_0100,
D = 0b0000_1000,
B = 0b0001_0000,
U = 0b0010_0000,
V = 0b0100_0000,
N = 0b1000_0000,
}
impl Flags {
pub fn byte_from_str(string: &str) -> u8 {
match string {
"C" => 0b0000_0001,
"Z" => 0b0000_0010,
"I" => 0b0000_0100,
"D" => 0b0000_1000,
"B" => 0b0001_0000,
"U" => 0b0010_0000,
"V" => 0b0100_0000,
"N" => 0b1000_0000,
_ => 0,
}
}
}
impl CPU {
pub fn load_program(&mut self, program: Vec<u8>) {
self.write_u16(0xFFFC, 0x0600);
#[allow(clippy::needless_range_loop)]
for i in 0..program.len() {
self.write(0x0600 + (i as u16), program[i]);
}
}
#[allow(unused)]
pub fn quick_start(&mut self, program: Vec<u8>) {
self.load_program(program);
self.reset();
self.clock();
}
pub fn get_pc(&self) -> u16 { self.pc }
pub fn get_sp(&self) -> u8 { self.sp }
pub fn get_sr(&self) -> u8 { self.sr }
pub fn get_a(&self) -> u8 { self.a }
pub fn get_x(&self) -> u8 { self.x }
pub fn get_y(&self) -> u8 { self.y }
pub fn get_opcode(&self) -> u8 { self.opcode }
pub fn get_state(&self) -> Vec<u16> {
vec![
self.get_a() as u16,
self.get_x() as u16,
self.get_y() as u16,
self.get_sp() as u16,
self.get_pc(),
self.get_sr() as u16,
self.get_opcode() as u16,
]
}
pub fn get_memory(&self) -> [u8; 64 * 1024] {
self.bus.get_ram()
}
#[allow(clippy::too_many_arguments, unused)]
pub fn custom(a: u8, x: u8, y: u8, sp: u8, pc: u16, sr: u8, opcode: u8, bus: Bus,) -> Self {
CPU {
a,
x,
y,
sp,
pc,
sr,
opcode,
bus,
}
}
}