diff --git a/Cargo.lock b/Cargo.lock index ac17e97..cb5347f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -642,6 +642,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.169" @@ -908,6 +914,7 @@ dependencies = [ "bitflags", "env_logger", "futures", + "lazy_static", "log", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index f303c98..95ecda5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bitflags = "2.8.0" env_logger = "0.11.6" futures = "0.3.31" +lazy_static = "1.5.0" log = "0.4.25" serde = "1.0.217" serde_json = "1.0.135" diff --git a/cpu.rs b/cpu.rs index 5a692c2..f5df986 100644 --- a/cpu.rs +++ b/cpu.rs @@ -1,6 +1,10 @@ +use std::collections::HashMap; + // This is all new to me so it's heavily commented so we can understand what is happening. use bitflags::{bitflags, Flags}; +use crate::opcodes; + bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct CpuFlags: u8 { @@ -457,6 +461,20 @@ impl CPU { self.stack_pointer = self.stack_pointer.wrapping_sub(1) } + fn stack_push_u16(&mut self, data: u16) { + let hi = (data >> 8) as u8; + let lo = (data & 0xff) as u8; + self.stack_push(hi); + self.stack_push(lo); + } + + fn stack_pop_u16(&mut self) -> u16 { + let lo = self.stack_pop() as u16; + let hi = self.stack_pop() as u16; + + hi << 8 | lo + } + fn asl_accumulator(&mut self) { let mut data = self.register_a; if data >> 6 == 1 { @@ -468,6 +486,17 @@ impl CPU { self.set_register_a(data); } + fn lsr_accumulator(&mut self) { + let mut data = self.register_a; + if data & 1 == 1 { + self.set_carry_flag(); + } else { + self.clear_carry_flag(); + } + data = data >> 1; + self.set_register_a(data) + } + fn asl(&mut self, mode: &AddressingMode) -> u8 { let addr = self.get_operand_address(mode); let mut data = self.mem_read(addr); @@ -644,6 +673,30 @@ impl CPU { self.status.set(CpuFlags::OVERFLOW, data & 0b01000000 > 0); } + fn compare(&mut self, mode: &AddressingMode, compare_with: u8) { + let addr = self.get_operand_address(mode); + let data = self.mem_read(addr); + if data <= compare_with { + self.status.insert(CpuFlags::CARRY); + } else { + self.status.remove(CpuFlags::CARRY); + } + + self.update_zero_and_negative_flags(compare_with.wrapping_sub(data)); + } + + fn branch(&mut self, condition: bool) { + if condition { + let jump: i8 = self.mem_read(self.program_counter) as i8; + let jump_addr = self + .program_counter + .wrapping_add(1) + .wrapping_add(jump as u16); + + self.program_counter = jump_addr + } + } + /// INX stands for Increment Index Register X - increase the value of the X register /// by one and update specific processor flags based on the result. fn inx(&mut self) { @@ -655,6 +708,10 @@ impl CPU { self.register_y = self.register_y.wrapping_add(1); self.update_zero_and_negative_flags(self.register_y); } + + pub fn run(&mut self) { + self.run_with_callback(|_| {}); + } // The interpret method takes in mutalbe reference to self as we know we will need to modify // register_a during execution @@ -663,31 +720,121 @@ impl CPU { // - Decode instruction // - Execute the instruction // - Repeat - pub fn run(&mut self) { - // We need an infinite loop to continuously fetch instructions from the program array. We - // use the program_counter to keep track fo the current instruction. + pub fn run_with_callback(&mut self, mut callback: F) + where + F: FnMut(&mut CPU), + { + let ref opcodes: HashMap = *opcodes::OPCODES_MAP; + loop { - // set the opscode to the current byte in the program at the address indicated by - // program counter - let opscode = self.mem_read(self.program_counter); - // we increment program counterto point to the next byte + let code = self.mem_read(self.program_counter); self.program_counter += 1; + let opcode = opcodes.get(&code).unwrap(); - match opscode { - // This will implement LDA (0xA9) opcode. 0xA9 is the LDA Immediate instruction in - // the 6502 CPU. - // - // 0x42 tells the CPU to execute a specific operation: LDA Immediate. An opscode is - // a command for the CPU, instructing it what to do next. Essentially, this means - // "Load the immediate value from the next memory location into the accumulator" - // - // Immediate value refers to the constant value that is directly embedded in the - // instruction itself, rather than being fetched from memory or calculated - // directly. + match code { 0xA9 | 0xa5 | 0xb4 | 0xad | 0xbd | 0xb9 | 0xa1 | 0xb1 => { self.lda(&AddressingMode::Immediate); self.program_counter += 1; } + 0xAA => self.tax(), + 0xe8 => self.inx(), + 0x00 => return, + 0xd8 => self.status.remove(CpuFlags::DECIMAL_MODE), + 0x58 => self.status.remove(CpuFlags::INTERRUPT_DISABLE), + 0xb8 => self.status.remove(CpuFlags::OVERFLOW), + 0x18 => self.clear_carry_flag(), + 0x38 => self.set_carry_flag(), + 0x78 => self.status.insert(CpuFlags::INTERRUPT_DISABLE), + 0xf8 => self.status.insert(CpuFlags::DECIMAL_MODE), + 0x48 => self.stack_push(self.register_a), + 0x68 => { + self.pla(); + } + 0x08 => { + self.php(); + } + 0x28 => { + self.plp(); + } + 0x69 | 0x65 | 0x75 | 0x6d | 0x7d | 0x79 | 0x61 | 0x71 => { + self.adc(&opcode.mod); + } + 0xe9 | 0xe5 | 0xf5 | 0xed | 0xfd | 0xf9 | 0xe1 | 0xf1 => { + self.adc(&opcode.mode); + } + 0x29 | 0x25 | 0x35 | 0x2d | 0x3d | 0x39 | 0x21 | 0x31 => { + self.and(&opcode.mode); + } + 0x49 | 0x45 | 0x55 | 0x4d | 0x5d | 0x41 | 0x51 => { + self.eor(&opcode.mode); + } + 0x09 | 0x05 | 0x15 | 0x0d | 0x1d | 0x19 | 0x01 | 0x11 => { + self.ora(&opcode.mode); + } + 0x4a => self.lsr_accumulator(), + 0x46 | 0x56 | 0x4e | 0x5e => { + self.lsr(&opcode.mode) + } + 0x0a => self.asl_accumulator(), + 0x06 | 0x16 | 0x0e | 0x1e => { + self.asl(&opcode.mode); + } + 0x2a => self.rol_accumulator(), + 0x26 | 0x36 | 0x23 | 0x3e => { + self.rol(&opcode.mode); + } + 0x6a => self.ror_accumulator(), + 0x66 | 0x76 | 0x6e | 0x7e => { + self.ror(&opcode.mode); + } + 0xe6 | 0xf6 | 0xee | 0xfe => { + self.inc(&opcode.mode); + } + 0xc8 => self.iny(), + + 0xc6 | 0xd6 | 0xce | 0xde => { + self.dec(&opcode.mode); + } + 0xca => self.dex(), + 0x88 => self.dey, + 0xc9 | 0xc5 | 0xd5 | 0xcd | 0xdd | 0xd9 | 0xc1 | 0xd1 => { + self.compare(&opcode.mode, self.register_a); + } + 0xc0 | 0xc4 | 0xcc => { + self.compare(&opcode.mode, self.register_y); + } + 0xe0 | 0xe4 | 0xec => self.compare(&opcode, self.register_x), + 0x4c => { + let mem_address = self.mem_read_u16(self.program_counter); + self.program_counter = mem_address; + } + 0x6c => { + let mem_address = self.mem_read_u16(self.program_counter); + let indirect_ref = if mem_address & 0x00FF == 0x00FF { + let lo = self.mem_read(mem_address); + let hi = self.mem_read(mem_address & 0xFF00); + } else { + self.mem_read_u16(mem_address) + }; + + self.program_counter = indirect_ref; + } + 0x20 => { + self.stack_push_u16(self.program_counter + 2 - 1); + let target_address = self.mem_read_u16(self.program_counter); + self.program_counter = target_address + } + 0x60 => { + self.program_counter = self.stack_pop_u16() + 1; + } + 0x40 => { + self.status.bits = self.stack_pop(); + self.status.remove(CpuFlags::BREAK); + self.status.insert(CpuFlags::BREAK2); + + self.program_counter = self.stack_pop_u16(); + } + // come back here 0xA5 => { self.lda(&AddressingMode::ZeroPage); self.program_counter += 1; @@ -710,7 +857,6 @@ impl CPU { // INX stands for Increment Index Register X - increase the value of the X register // by one and update specific processor flags based on the result. 0xe8 => self.inx(), - 0x00 => return, _ => todo!(), } } diff --git a/main.rs b/main.rs index e101b81..2beb823 100644 --- a/main.rs +++ b/main.rs @@ -5,6 +5,7 @@ use std::net::SocketAddr; use tokio::net::{TcpListener, TcpStream}; use tokio_tungstenite::{accept_async, tungstenite::protocol::Message}; mod cpu; +mod opcodes; // this file is overly commented because I'm learning Rust while I program. I want just want to // thnk aloud. #[tokio::main] diff --git a/opcodes.rs b/opcodes.rs new file mode 100644 index 0000000..4af6d66 --- /dev/null +++ b/opcodes.rs @@ -0,0 +1,231 @@ +use crate::cpu::AddressingMode; +use lazy_static::lazy_static; +use std::collections::HashMap; + +pub struct OpCode { + pub code: u8, + pub mnemonic: &'static str, + pub len: u8, + pub cycles: u8, + pub mode: AddressingMode, +} + +impl OpCode { + fn new(code: u8, mnemonic: &'static str, len: u8, cycles: u8, mode: AddressingMode) -> Self { + OpCode { + code, + mnemonic, + len, + cycles, + mode, + } + } +} + +lazy_static! { + pub static ref CPU_OPS_CODES: Vec = vec![ + OpCode::new(0x00, "BRK", 1, 7, AddressingMode::NoneAddressing), + OpCode::new(0xea, "NOP", 1, 2, AddressingMode::NoneAddressing), + + /* Arithmetic */ + OpCode::new(0x69, "ADC", 2, 2, AddressingMode::Immediate), + OpCode::new(0x65, "ADC", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x75, "ADC", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0x6d, "ADC", 3, 4, AddressingMode::Absolute), + OpCode::new(0x7d, "ADC", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + OpCode::new(0x79, "ADC", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + OpCode::new(0x61, "ADC", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0x71, "ADC", 2, 5/*+1 if page crossed*/, AddressingMode::Indirect_Y), + + OpCode::new(0xe9, "SBC", 2, 2, AddressingMode::Immediate), + OpCode::new(0xe5, "SBC", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0xf5, "SBC", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0xed, "SBC", 3, 4, AddressingMode::Absolute), + OpCode::new(0xfd, "SBC", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + OpCode::new(0xf9, "SBC", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + OpCode::new(0xe1, "SBC", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0xf1, "SBC", 2, 5/*+1 if page crossed*/, AddressingMode::Indirect_Y), + + OpCode::new(0x29, "AND", 2, 2, AddressingMode::Immediate), + OpCode::new(0x25, "AND", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x35, "AND", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0x2d, "AND", 3, 4, AddressingMode::Absolute), + OpCode::new(0x3d, "AND", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + OpCode::new(0x39, "AND", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + OpCode::new(0x21, "AND", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0x31, "AND", 2, 5/*+1 if page crossed*/, AddressingMode::Indirect_Y), + + OpCode::new(0x49, "EOR", 2, 2, AddressingMode::Immediate), + OpCode::new(0x45, "EOR", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x55, "EOR", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0x4d, "EOR", 3, 4, AddressingMode::Absolute), + OpCode::new(0x5d, "EOR", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + OpCode::new(0x59, "EOR", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + OpCode::new(0x41, "EOR", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0x51, "EOR", 2, 5/*+1 if page crossed*/, AddressingMode::Indirect_Y), + + OpCode::new(0x09, "ORA", 2, 2, AddressingMode::Immediate), + OpCode::new(0x05, "ORA", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x15, "ORA", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0x0d, "ORA", 3, 4, AddressingMode::Absolute), + OpCode::new(0x1d, "ORA", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + OpCode::new(0x19, "ORA", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + OpCode::new(0x01, "ORA", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0x11, "ORA", 2, 5/*+1 if page crossed*/, AddressingMode::Indirect_Y), + + /* Shifts */ + OpCode::new(0x0a, "ASL", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x06, "ASL", 2, 5, AddressingMode::ZeroPage), + OpCode::new(0x16, "ASL", 2, 6, AddressingMode::ZeroPage_X), + OpCode::new(0x0e, "ASL", 3, 6, AddressingMode::Absolute), + OpCode::new(0x1e, "ASL", 3, 7, AddressingMode::Absolute_X), + + OpCode::new(0x4a, "LSR", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x46, "LSR", 2, 5, AddressingMode::ZeroPage), + OpCode::new(0x56, "LSR", 2, 6, AddressingMode::ZeroPage_X), + OpCode::new(0x4e, "LSR", 3, 6, AddressingMode::Absolute), + OpCode::new(0x5e, "LSR", 3, 7, AddressingMode::Absolute_X), + + OpCode::new(0x2a, "ROL", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x26, "ROL", 2, 5, AddressingMode::ZeroPage), + OpCode::new(0x36, "ROL", 2, 6, AddressingMode::ZeroPage_X), + OpCode::new(0x2e, "ROL", 3, 6, AddressingMode::Absolute), + OpCode::new(0x3e, "ROL", 3, 7, AddressingMode::Absolute_X), + + OpCode::new(0x6a, "ROR", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x66, "ROR", 2, 5, AddressingMode::ZeroPage), + OpCode::new(0x76, "ROR", 2, 6, AddressingMode::ZeroPage_X), + OpCode::new(0x6e, "ROR", 3, 6, AddressingMode::Absolute), + OpCode::new(0x7e, "ROR", 3, 7, AddressingMode::Absolute_X), + + OpCode::new(0xe6, "INC", 2, 5, AddressingMode::ZeroPage), + OpCode::new(0xf6, "INC", 2, 6, AddressingMode::ZeroPage_X), + OpCode::new(0xee, "INC", 3, 6, AddressingMode::Absolute), + OpCode::new(0xfe, "INC", 3, 7, AddressingMode::Absolute_X), + + OpCode::new(0xe8, "INX", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0xc8, "INY", 1, 2, AddressingMode::NoneAddressing), + + OpCode::new(0xc6, "DEC", 2, 5, AddressingMode::ZeroPage), + OpCode::new(0xd6, "DEC", 2, 6, AddressingMode::ZeroPage_X), + OpCode::new(0xce, "DEC", 3, 6, AddressingMode::Absolute), + OpCode::new(0xde, "DEC", 3, 7, AddressingMode::Absolute_X), + + OpCode::new(0xca, "DEX", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x88, "DEY", 1, 2, AddressingMode::NoneAddressing), + + OpCode::new(0xc9, "CMP", 2, 2, AddressingMode::Immediate), + OpCode::new(0xc5, "CMP", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0xd5, "CMP", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0xcd, "CMP", 3, 4, AddressingMode::Absolute), + OpCode::new(0xdd, "CMP", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + OpCode::new(0xd9, "CMP", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + OpCode::new(0xc1, "CMP", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0xd1, "CMP", 2, 5/*+1 if page crossed*/, AddressingMode::Indirect_Y), + + OpCode::new(0xc0, "CPY", 2, 2, AddressingMode::Immediate), + OpCode::new(0xc4, "CPY", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0xcc, "CPY", 3, 4, AddressingMode::Absolute), + + OpCode::new(0xe0, "CPX", 2, 2, AddressingMode::Immediate), + OpCode::new(0xe4, "CPX", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0xec, "CPX", 3, 4, AddressingMode::Absolute), + + + /* Branching */ + + OpCode::new(0x4c, "JMP", 3, 3, AddressingMode::NoneAddressing), //AddressingMode that acts as Immidiate + OpCode::new(0x6c, "JMP", 3, 5, AddressingMode::NoneAddressing), //AddressingMode:Indirect with 6502 bug + + OpCode::new(0x20, "JSR", 3, 6, AddressingMode::NoneAddressing), + OpCode::new(0x60, "RTS", 1, 6, AddressingMode::NoneAddressing), + + OpCode::new(0x40, "RTI", 1, 6, AddressingMode::NoneAddressing), + + OpCode::new(0xd0, "BNE", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + OpCode::new(0x70, "BVS", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + OpCode::new(0x50, "BVC", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + OpCode::new(0x30, "BMI", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + OpCode::new(0xf0, "BEQ", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + OpCode::new(0xb0, "BCS", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + OpCode::new(0x90, "BCC", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + OpCode::new(0x10, "BPL", 2, 2 /*(+1 if branch succeeds +2 if to a new page)*/, AddressingMode::NoneAddressing), + + OpCode::new(0x24, "BIT", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x2c, "BIT", 3, 4, AddressingMode::Absolute), + + + /* Stores, Loads */ + OpCode::new(0xa9, "LDA", 2, 2, AddressingMode::Immediate), + OpCode::new(0xa5, "LDA", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0xb5, "LDA", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0xad, "LDA", 3, 4, AddressingMode::Absolute), + OpCode::new(0xbd, "LDA", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + OpCode::new(0xb9, "LDA", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + OpCode::new(0xa1, "LDA", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0xb1, "LDA", 2, 5/*+1 if page crossed*/, AddressingMode::Indirect_Y), + + OpCode::new(0xa2, "LDX", 2, 2, AddressingMode::Immediate), + OpCode::new(0xa6, "LDX", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0xb6, "LDX", 2, 4, AddressingMode::ZeroPage_Y), + OpCode::new(0xae, "LDX", 3, 4, AddressingMode::Absolute), + OpCode::new(0xbe, "LDX", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_Y), + + OpCode::new(0xa0, "LDY", 2, 2, AddressingMode::Immediate), + OpCode::new(0xa4, "LDY", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0xb4, "LDY", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0xac, "LDY", 3, 4, AddressingMode::Absolute), + OpCode::new(0xbc, "LDY", 3, 4/*+1 if page crossed*/, AddressingMode::Absolute_X), + + + OpCode::new(0x85, "STA", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x95, "STA", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0x8d, "STA", 3, 4, AddressingMode::Absolute), + OpCode::new(0x9d, "STA", 3, 5, AddressingMode::Absolute_X), + OpCode::new(0x99, "STA", 3, 5, AddressingMode::Absolute_Y), + OpCode::new(0x81, "STA", 2, 6, AddressingMode::Indirect_X), + OpCode::new(0x91, "STA", 2, 6, AddressingMode::Indirect_Y), + + OpCode::new(0x86, "STX", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x96, "STX", 2, 4, AddressingMode::ZeroPage_Y), + OpCode::new(0x8e, "STX", 3, 4, AddressingMode::Absolute), + + OpCode::new(0x84, "STY", 2, 3, AddressingMode::ZeroPage), + OpCode::new(0x94, "STY", 2, 4, AddressingMode::ZeroPage_X), + OpCode::new(0x8c, "STY", 3, 4, AddressingMode::Absolute), + + + /* Flags clear */ + + OpCode::new(0xD8, "CLD", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x58, "CLI", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0xb8, "CLV", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x18, "CLC", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x38, "SEC", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x78, "SEI", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0xf8, "SED", 1, 2, AddressingMode::NoneAddressing), + + OpCode::new(0xaa, "TAX", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0xa8, "TAY", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0xba, "TSX", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x8a, "TXA", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x9a, "TXS", 1, 2, AddressingMode::NoneAddressing), + OpCode::new(0x98, "TYA", 1, 2, AddressingMode::NoneAddressing), + + /* Stack */ + OpCode::new(0x48, "PHA", 1, 3, AddressingMode::NoneAddressing), + OpCode::new(0x68, "PLA", 1, 4, AddressingMode::NoneAddressing), + OpCode::new(0x08, "PHP", 1, 3, AddressingMode::NoneAddressing), + OpCode::new(0x28, "PLP", 1, 4, AddressingMode::NoneAddressing), + + ]; + + + pub static ref OPCODES_MAP: HashMap = { + let mut map = HashMap::new(); + for cpuop in &*CPU_OPS_CODES { + map.insert(cpuop.code, cpuop); + } + map + }; +}