From a550fe40b9a1ed57226c6f81bb95fa5c3d89b277 Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Sun, 22 Jun 2025 16:26:10 -0400 Subject: [PATCH] some decode. some encode. some to_string --- Cargo.lock | 125 ++- cli/Cargo.toml | 1 + cli/src/bin/decode.rs | 12 + cli/src/bin/disasm.rs | 2 +- core/Cargo.toml | 2 + core/src/address_mode.rs | 15 + core/src/constants.rs | 207 ++++ core/src/instruction.rs | 1730 +++++++++++++++++++++++++++++++ core/src/isa/decoder.rs | 74 ++ core/src/isa/encode.rs | 129 +++ core/src/isa/microcode_steps.rs | 18 + core/src/isa/mod.rs | 4 + core/src/lib.rs | 6 + core/src/mos6502cpu.rs | 72 ++ core/src/mos6502flags.rs | 98 ++ 15 files changed, 2470 insertions(+), 25 deletions(-) create mode 100644 cli/src/bin/decode.rs create mode 100644 core/src/address_mode.rs create mode 100644 core/src/constants.rs create mode 100644 core/src/instruction.rs create mode 100644 core/src/isa/decoder.rs create mode 100644 core/src/isa/encode.rs create mode 100644 core/src/isa/microcode_steps.rs create mode 100644 core/src/isa/mod.rs create mode 100644 core/src/mos6502cpu.rs create mode 100644 core/src/mos6502flags.rs diff --git a/Cargo.lock b/Cargo.lock index 0d30748..080cf31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,7 +53,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -64,7 +64,7 @@ checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -124,6 +124,7 @@ name = "cli" version = "0.1.0" dependencies = [ "clap", + "core", "log", "pretty_env_logger", "trevors_utilities", @@ -138,6 +139,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "core" version = "0.1.0" +dependencies = [ + "log", +] [[package]] name = "crc32fast" @@ -163,12 +167,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.60.2", ] [[package]] @@ -225,7 +229,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -236,9 +240,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "libc" -version = "0.2.173" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "linux-raw-sys" @@ -313,9 +317,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "regex" @@ -356,7 +360,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -367,9 +371,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.103" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -386,7 +390,7 @@ dependencies = [ "getrandom", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -435,7 +439,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -444,7 +448,16 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", ] [[package]] @@ -453,14 +466,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -469,48 +498,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "wit-bindgen-rt" version = "0.39.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 9ba4812..46bd255 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -8,3 +8,4 @@ pretty_env_logger.workspace = true log.workspace = true clap.workspace = true trevors_utilities.workspace = true +core = { path = "../core" } diff --git a/cli/src/bin/decode.rs b/cli/src/bin/decode.rs new file mode 100644 index 0000000..3bde970 --- /dev/null +++ b/cli/src/bin/decode.rs @@ -0,0 +1,12 @@ +use core::instruction::Instruction; +use core::address_mode::AddressMode; +use core::isa::decoder::Decoder; + +fn main() { + println!("Taxation is Theft"); + + Decoder::decode(vec![0b11100011]); + + let instruction = Instruction::ADC(AddressMode::Immediate(0x45)); + println!("Instruction = {:?}", instruction.to_string()); +} diff --git a/cli/src/bin/disasm.rs b/cli/src/bin/disasm.rs index c4e156b..0616903 100644 --- a/cli/src/bin/disasm.rs +++ b/cli/src/bin/disasm.rs @@ -2,4 +2,4 @@ fn main() { println!("Taxation is theft."); println!("TODO:"); println!(" Load specified binary and parse it out to ASM"); -} \ No newline at end of file +} diff --git a/core/Cargo.toml b/core/Cargo.toml index ec978b2..7fe5433 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -2,3 +2,5 @@ name = "core" version = "0.1.0" edition = "2024" +[dependencies] +log = "0.4.26" \ No newline at end of file diff --git a/core/src/address_mode.rs b/core/src/address_mode.rs new file mode 100644 index 0000000..9ce121c --- /dev/null +++ b/core/src/address_mode.rs @@ -0,0 +1,15 @@ +use std::ops::Add; +use crate::mos6502cpu::Mos6502Cpu; + +#[derive(PartialEq, Debug)] +pub enum AddressMode { + Accumulator, + Immediate(u8), + ZeroPage(u8), + ZeroPageX(u8), + Absolute(u16), + AbsoluteX(u16), + AbsoluteY(u16), + IndirectX(u8), + IndirectY(u8), +} diff --git a/core/src/constants.rs b/core/src/constants.rs new file mode 100644 index 0000000..cc4b14a --- /dev/null +++ b/core/src/constants.rs @@ -0,0 +1,207 @@ +// Instruction OP Codes + +/// ADC +pub const ISA_OP_ADC_I: u8 = 0x69; +pub const ISA_OP_ADC_Z: u8 = 0x65; +pub const ISA_OP_ADC_ZX: u8 = 0x75; +pub const ISA_OP_ADC_ABS: u8 = 0x6d; +pub const ISA_OP_ADC_ABSX: u8 = 0x7d; +pub const ISA_OP_ADC_ABSY: u8 = 0x79; +pub const ISA_OP_ADC_INDX: u8 = 0x61; +pub const ISA_OP_ADC_INDY: u8 = 0x71; +/// AND +pub const ISA_OP_AND_I: u8 = 0x29; +pub const ISA_OP_AND_Z: u8 = 0x25; +pub const ISA_OP_AND_ZX: u8 = 0x35; +pub const ISA_OP_AND_ABS: u8 = 0x2d; +pub const ISA_OP_AND_ABSX: u8 = 0x3d; +pub const ISA_OP_AND_ABSY: u8 = 0x39; +pub const ISA_OP_AND_INDX: u8 = 0x21; +pub const ISA_OP_AND_INDY: u8 = 0x31; + +/// ASL +pub const ISA_OP_ASL_A: u8 = 0x0a; +pub const ISA_OP_ASL_Z: u8 = 0x06; +pub const ISA_OP_ASL_ZX: u8 = 0x16; +pub const ISA_OP_ASL_ABS: u8 = 0x0e; +pub const ISA_OP_ASL_ABSX: u8 = 0x1e; + +/// BCC +pub const ISA_OP_BCC: u8 = 0x90; + +/// BCS +pub const ISA_OP_BCS: u8 = 0xb0; + +/// BEQ +pub const ISA_OP_BEQ: u8 = 0xf0; +/// BIT + +pub const ISA_OP_BIT_ZP: u8 = 0x24; +pub const ISA_OP_BIT_ABS: u8 = 0x2c; + +/// BMI +pub const ISA_OP_BMI: u8 = 0x30; + +/// BNE +pub const ISA_OP_BNE: u8 = 0xd0; + +/// BPL +pub const ISA_OP_BPL: u8 = 0x10; + +/// BRK +pub const ISA_OP_BRK: u8 = 0x00; +/// BVC + +pub const ISA_OP_BVC: u8 = 0x50; + +/// BVS +pub const ISA_OP_BVS: u8 = 0x70; + +pub const ISA_OP_CLC: u8 = 0x18; + +pub const ISA_OP_CLD: u8 = 0xd8; + +pub const ISA_OP_CLI: u8 = 0x58; + +pub const ISA_OP_CLV: u8 = 0xb8; + +pub const ISA_OP_CMP_I: u8 = 0xc9; +pub const ISA_OP_CMP_ZP: u8 = 0xc5; +pub const ISA_OP_CMP_ZPX: u8 = 0xd5; +pub const ISA_OP_CMP_ABS: u8 = 0xcd; +pub const ISA_OP_CMP_ABSX: u8 = 0xdd; +pub const ISA_OP_CMP_INDX: u8 = 0xc1; +pub const ISA_OP_CMP_INDY: u8 = 0xd1; + +pub const ISA_OP_CPX_I: u8 = 0xe0; +pub const ISA_OP_CPX_ZP: u8 = 0xe4; +pub const ISA_OP_CPX_ABS: u8 = 0xec; + +pub const ISA_OP_CPY_I: u8 = 0xc0; +pub const ISA_OP_CPY_ZP: u8 = 0xc4; +pub const ISA_OP_CPY_ABS: u8 = 0xcc; + +pub const ISA_OP_DEC_ZP: u8 = 0xc6; +pub const ISA_OP_DEC_ZPX: u8 = 0xd6; +pub const ISA_OP_DEC_ABS: u8 = 0xce; +pub const ISA_OP_DEC_ABSX: u8 = 0xde; + +pub const ISA_OP_DEX: u8 = 0xca; + +pub const ISA_OP_DEY: u8 = 0x88; + +pub const ISA_OP_EOR_I: u8 = 0x49; +pub const ISA_OP_EOR_ZP: u8 = 0x45; +pub const ISA_OP_EOR_ZPX: u8 = 0x55; +pub const ISA_OP_EOR_ABS: u8 = 0x4d; +pub const ISA_OP_EOR_ABSX: u8 = 0x5d; +pub const ISA_OP_EOR_ABSY: u8 = 0x59; +pub const ISA_OP_EOR_INDX: u8 = 0x41; +pub const ISA_OP_EOR_INDY: u8 = 0x51; + +pub const ISA_OP_INC_ZP: u8 = 0xe6; +pub const ISA_OP_INC_ZPX: u8 = 0xf6; +pub const ISA_OP_INC_ABS: u8 = 0xee; +pub const ISA_OP_INC_ABSX: u8 = 0xfe; + + +pub const ISA_OP_INX: u8 = 0xe8; + +pub const ISA_OP_INY: u8 = 0xc8; + +pub const ISA_OP_JMP_ABS: u8 = 0x4c; +pub const ISA_OP_JMP_IND: u8 = 0x6c; + +pub const ISA_OP_JSR: u8 = 0x20; + +pub const ISA_OP_LDA_I: u8 = 0xA9; +pub const ISA_OP_LDA_Z: u8 = 0xA5; +pub const ISA_OP_LDA_ZX: u8 = 0xB5; +pub const ISA_OP_LDA_ABS: u8 = 0xAD; +pub const IAS_OP_LDA_ABSX: u8 = 0xBD; +pub const ISA_OP_LDA_ABSY: u8 = 0xB9; +pub const ISA_OP_LDA_INDX: u8 = 0xA1; +pub const ISA_OP_LDA_INDY: u8 = 0xB1; + +pub const ISA_OP_LDX_I: u8 = 0xa2; +pub const ISA_OP_LDX_ZP: u8 = 0xa6; +pub const ISA_OP_LDX_ZPY: u8 = 0x86; +pub const ISA_OP_LDX_ABS: u8 = 0xae; +pub const ISA_OP_LDX_ABSY: u8 = 0xbe; + +pub const ISA_OP_LDY_I: u8 = 0xa0; +pub const ISA_OP_LDY_ZP: u8 = 0xa4; +pub const ISA_OP_LDY_ZPX: u8 = 0xb4; +pub const ISA_OP_LDY_ABS: u8 = 0xac; +pub const ISA_OP_LDY_ABSX: u8 = 0xac; +pub const ISA_OP_LSR_A: u8 = 0x4a; +pub const ISA_OP_LSR_ZP: u8 = 0x46; +pub const ISA_OP_LSR_ZPX: u8 = 0x56; +pub const ISA_OP_LSR_ABS: u8 = 0x4e; +pub const ISA_OP_LSR_ABSX: u8 = 0x5e; + +pub const ISA_OP_NOP: u8 = 0xEA; + +pub const ISA_OP_ORA_I: u8 = 0x09; +pub const ISA_OP_ORA_ZP: u8 = 0x05; +pub const ISA_OP_ORA_ZPX: u8 = 0x15; +pub const ISA_OP_ORA_ABS: u8 = 0x0d; +pub const ISA_OP_ORA_ABSX: u8 = 0x1d; +pub const ISA_OP_ORA_ABSY: u8 = 0x19; +pub const ISA_OP_ORA_INDX: u8 = 0x01; +pub const ISA_OP_ORA_INDY: u8 = 0x11; + +pub const ISA_OP_PHA: u8 = 0x48; + +pub const ISA_OP_PHP: u8 = 0x08; +/// +pub const ISA_OP_PLA: u8 = 0x68; +/// +pub const ISA_OP_PLP: u8 = 0x28; + +/// +/// +pub const ISA_OP_ROL_A: u8 = 0x2a; +pub const ISA_OP_ROL_ZP: u8 = 0x26; +pub const ISA_OP_ROL_ZPX: u8 = 0x36; +pub const ISA_OP_ROL_ABS: u8 = 0x2e; +pub const ISA_OP_ROL_ABSX: u8 = 0x3e; + +/// +pub const ISA_OP_ROR_A: u8 = 0x6a; +pub const ISA_OP_ROR_ZP: u8 = 0x66; +pub const ISA_OP_ROR_ZPX: u8 = 0x76; +pub const ISA_OP_ROR_ABS: u8 = 0x6e; +pub const ISA_OP_ROR_ABSX: u8 = 0x7e; +pub const ISA_OP_RTI: u8 = 0x40; +pub const ISA_OP_RTS: u8 = 0x60; +pub const ISA_OP_SBC_I: u8 = 0xe9; +pub const ISA_OP_SBC_ZP: u8 = 0xe5; +pub const ISA_OP_SBC_ZPX: u8 = 0xf5; +pub const ISA_OP_SBC_ABS: u8 = 0xed; +pub const ISA_OP_SBC_ABSX: u8 = 0xfd; +pub const ISA_OP_SBC_ABSY: u8 = 0xf9; +pub const ISA_OP_SBC_INDX: u8 = 0xe1; +pub const ISA_OP_SBC_INDY: u8 = 0xf1; +pub const ISA_OP_SEC: u8 = 0x38; +pub const ISA_OP_SED: u8 = 0xf8; +pub const ISA_OP_SEI: u8 = 0x78; +pub const ISA_OP_STA_ZP: u8 = 0x85; +pub const ISA_OP_STA_ZPX: u8 = 0x95; +pub const ISA_OP_STA_ABS: u8 = 0x8d; +pub const ISA_OP_STA_ABSX: u8 = 0x9d; +pub const ISA_OP_STA_ABSY: u8 = 0x99; +pub const ISA_OP_STA_INDX: u8 = 0x81; +pub const ISA_OP_STA_INDY: u8 = 0x91; +pub const ISA_OP_STX_ZP: u8 = 0x86; +pub const ISA_OP_STX_ZPX: u8 = 0x96; +pub const ISA_OP_STX_ABS: u8 = 0x8e; +pub const ISA_OP_STY_ZP: u8 = 0x84; +pub const ISA_OP_STY_ZPX: u8 = 0x94; +pub const ISA_OP_STY_ABS: u8 = 0x8c; +pub const ISA_OP_TAX: u8 = 0xaa; +pub const ISA_OP_TAY: u8 = 0xa8; +pub const ISA_OP_TSX: u8 = 0xba; +pub const ISA_OP_TXA: u8 = 0x8a; +pub const ISA_OP_TXS: u8 = 0x9a; +pub const ISA_OP_TYA: u8 = 0x98; diff --git a/core/src/instruction.rs b/core/src/instruction.rs new file mode 100644 index 0000000..c3b52af --- /dev/null +++ b/core/src/instruction.rs @@ -0,0 +1,1730 @@ +use log::debug; +use crate::address_mode::AddressMode; +use crate::address_mode::AddressMode::*; +use crate::constants::*; +use crate::instruction::Instruction::*; +use crate::isa::microcode_steps::MicrocodeStep; +use crate::isa::microcode_steps::MicrocodeStep::{ALUAddC, ReadRegisterA}; +use crate::mos6502cpu::Mos6502Cpu; +use crate::mos6502flags::Mos6502Flag::*; + +#[derive(PartialEq, Debug)] +pub enum Instruction { + /// ADC – Add with Carry + /// A,Z,C,N = A+M+C + /// + /// This instruction adds the contents of a memory location to the accumulator together with the carry bit. If overflow occurs the carry bit is set, this enables multiple byte addition to be performed. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set if overflow in bit 7 + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Set if sign bit is incorrect + /// N Negative Flag Set if bit 7 set + /// + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $69 2 2 + /// Zero Page $65 2 3 + /// Zero Page,X $75 2 4 + /// Absolute $6D 3 4 + /// Absolute,X $7D 3 4 (+1 if page crossed) + /// Absolute,Y $79 3 4 (+1 if page crossed) + /// (Indirect,X) $61 2 6 + /// (Indirect),Y $71 2 5 (+1 if page crossed) + ADC(AddressMode), + /// AND + /// A,Z,N = A&M + /// + /// A logical AND is performed, bit by bit, on the accumulator contents using the contents of a byte of memory. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 set + /// + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $29 2 2 + /// ZeroPage $25 2 3 + /// ZeroPage,X $35 2 4 + /// Absolute $2D 3 4 + /// Absolute,X $3D 3 4 (+1 if page crossed) + /// Absolute,Y $39 3 4 (+1 if page crossed) + /// (Indirect,X) $21 2 6 + /// (Indirect),Y $31 2 5 (+1 if page crossed) + /// + AND(AddressMode), + /// ASL + /// A,Z,C,N = M*2 or M,Z,C,N = M*2 + /// + /// This operation shifts all the bits of the accumulator or memory contents one bit left. Bit 0 is set to 0 and bit 7 is placed in the carry flag. The effect of this operation is to multiply the memory contents by 2 (ignoring 2’s complement considerations), setting the carry if the result will not fit in 8 bits. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set to contents of old bit 7 + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// + /// Addressing Mode Opcode Bytes Cycles + /// Accumulator $0A 1 2 + /// ZeroPage $06 2 5 + /// ZeroPage,X $16 2 6 + /// Absolute $0E 3 6 + /// Absolute,X $1E 3 7 + ASL(AddressMode), + /// BCC – Branch if Carry Clear + /// If the carry flag is clear then add the relative displacement to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Relative $90 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BCC(AddressMode), + /// BCS – Branch if Carry Set + /// If the carry flag is set then add the relative displacement to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// + /// Addressing Mode Opcode Bytes Cycles + /// Relative $B0 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BCS(AddressMode), + /// BEQ – Branch if Equal + /// If the zero flag is set then add the relative displacement to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Relative $F0 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BEQ(AddressMode), + /// BIT – Bit Test + /// A & M, N = M7, V = M6 + /// + /// This instructions is used to test if one or more bits are set in a target memory location. The mask pattern in A is ANDed with the value in memory to set or clear the zero flag, but the result is not kept. Bits 7 and 6 of the value from memory are copied into the N and V flags. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if the result if the AND is zero + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Set to bit 6 of the memory value + /// N Negative Flag Set to bit 7 of the memory value + /// Addressing Mode Opcode Bytes Cycles + /// ZeroPage $24 2 3 + /// Absolute $2C 3 4 + BIT(AddressMode), + /// BMI – Branch if Minus + /// If the negative flag is set then add the relative displacement to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Relative $30 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BMI(AddressMode), + /// BNE – Branch if Not Equal + /// If the zero flag is clear then add the relative displacement to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Relative $D0 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BNE(AddressMode), + /// BPL – Branch if Positive + /// If the negative flag is clear then add the relative displacement to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Relative $10 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BPL(AddressMode), + /// BRK – Force Interrupt + /// The BRK instruction forces the generation of an interrupt request. The program counter and processor status are pushed on the stack then the IRQ interrupt vector at $FFFE/F is loaded into the PC and the break flag in the status set to one. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Set to 1 + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $00 1 7 + BRK, + /// BVC – Branch if Overflow Clear + /// If the overflow flag is clear then add the relative displacement + /// to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Relative $50 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BVC(AddressMode), + /// BVS – Branch if Overflow Set + /// If the overflow flag is set then add the relative displacement to the program counter to cause a branch to a new location. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Relative $70 2 2 (+1 if branch succeeds + /// + /// +2 if to a new page) + BVS(AddressMode), + /// CLC – Clear Carry Flag + /// C = 0 + /// + /// Set the carry flag to zero. + /// + /// C Carry Flag Set to 0 + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $18 1 2 + CLC, + /// CLD – Clear Decimal Mode + /// D = 0 + /// + /// Sets the decimal mode flag to zero. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Set to 0 + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $D8 1 2 + CLD, + /// CLI – Clear Interrupt Disable + /// I = 0 + /// + /// Clears the interrupt disable flag allowing normal interrupt + /// requests to be serviced. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Set to 0 + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $58 1 2 + CLI, + /// CLV – Clear Overflow Flag + /// V = 0 + /// + /// Clears the overflow flag. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Set to 0 + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $B8 1 2 + CLV, + /// CMP – Compare + /// Z,C,N = A-M + /// + /// This instruction compares the contents of the accumulator with another memory held value and sets the zero and carry flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set if A >= M + /// Z Zero Flag Set if A = M + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $C9 2 2 + /// Zero Page $C5 2 3 + /// Zero Page,X $D5 2 4 + /// Absolute $CD 3 4 + /// Absolute,X $DD 3 4 (+1 if page crossed) + /// Absolute,Y $D9 3 4 (+1 if page crossed) + /// (Indirect,X) $C1 2 6 + /// (Indirect),Y $D1 2 5 (+1 if page crossed) + CMP(AddressMode), + /// CPX – Compare X Register + /// Z,C,N = X-M + /// + /// This instruction compares the contents of the X register with another memory held value and sets the zero and carry flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set if X >= M + /// Z Zero Flag Set if X = M + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $E0 2 2 + /// Zero Page $E4 2 3 + /// Absolute $EC 3 4 + CPX(AddressMode), + /// CPY – Compare Y Register + /// Z,C,N = Y-M + /// + /// This instruction compares the contents of the Y register with another memory held value and sets the zero and carry flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set if Y >= M + /// Z Zero Flag Set if Y = M + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $C0 2 2 + /// Zero Page $C4 2 3 + /// Absolute $CC 3 4 + CPY(AddressMode), + /// DEC – Decrement Memory + /// M,Z,N = M-1 + /// + /// Subtracts one from the value held at a specified memory location setting the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if result is zero + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Zero Page $C6 2 5 + /// Zero Page,X $D6 2 6 + /// Absolute $CE 3 6 + /// Absolute,X $DE 3 7 + DEC(AddressMode), + /// DEX – Decrement X Register + /// X,Z,N = X-1 + /// + /// Subtracts one from the X register setting the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if X is zero + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of X is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $CA 1 2 + DEX, + /// DEY – Decrement Y Register + /// Y,Z,N = Y-1 + /// + /// Subtracts one from the Y register setting the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if Y is zero + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of Y is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $88 1 2 + DEY, + /// EOR – Exclusive OR + /// A,Z,N = A^M + /// + /// An exclusive OR is performed, bit by bit, on the accumulator contents using the contents of a byte of memory. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $49 2 2 + /// ZeroPage $45 2 3 + /// ZeroPage,X $55 2 4 + /// Absolute $4D 3 4 + /// Absolute,X $5D 3 4 (+1 if page crossed) + /// Absolute,Y $59 3 4 (+1 if page crossed) + /// (Indirect,X) $41 2 6 + /// (Indirect),Y $51 2 5 (+1 if page crossed) + EOR(AddressMode), + /// INC – Increment Memory + /// M,Z,N = M+1 + /// + /// Adds one to the value held at a specified memory location setting the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if result is zero + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Zero Page $E6 2 5 + /// Zero Page,X $F6 2 6 + /// Absolute $EE 3 6 + /// Absolute,X $FE 3 7 + INC(AddressMode), + /// INX – Increment X Register + /// X,Z,N = X+1 + /// + /// Adds one to the X register setting the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if X is zero + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of X is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $E8 1 2 + INX, + /// INY – Increment Y Register + /// Y,Z,N = Y+1 + /// + /// Adds one to the Y register setting the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if Y is zero + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of Y is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $C8 1 2 + INY, + /// JMP – Jump + /// Sets the program counter to the address specified by the operand. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Absolute $4C 3 3 + /// Indirect $6C 3 5 + JMP(AddressMode), + /// JSR – Jump to Subroutine + /// The JSR instruction pushes the address (minus one) of the return point on to the stack and then sets the program counter to the target memory address. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Absolute $20 3 6 + JSR(AddressMode), + /// LDA – Load Accumulator + /// A,Z,N = M + /// + /// Loads a byte of memory into the accumulator setting the zero and negative flags as appropriate. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of A is set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $A9 2 2 + /// Zero Page $A5 2 3 + /// Zero Page,X $B5 2 4 + /// Absolute $AD 3 4 + /// Absolute,X $BD 3 4 (+1 if page crossed) + /// Absolute,Y $B9 3 4 (+1 if page crossed) + /// (Indirect,X) $A1 2 6 + /// (Indirect),Y $B1 2 5 (+1 if page crossed) + LDA(AddressMode), + /// LDX – Load X Register + /// X,Z,N = M + /// + /// Loads a byte of memory into the X register setting the zero and negative flags as appropriate. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if X = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of X is set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $A2 2 2 + /// Zero Page $A6 2 3 + /// Zero Page,Y $B6 2 4 + /// Absolute $AE 3 4 + /// Absolute,Y $BE 3 4 (+1 if page crossed) + LDX(AddressMode), + /// LDY – Load Y Register + /// Y,Z,N = M + /// + /// Loads a byte of memory into the Y register setting the zero and negative flags as appropriate. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if Y = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of Y is set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $A0 2 2 + /// Zero Page $A4 2 3 + /// Zero Page,X $B4 2 4 + /// Absolute $AC 3 4 + /// Absolute,X $BC 3 4 (+1 if page crossed) + LDY(AddressMode), + /// LSR – Logical Shift Right + /// A,C,Z,N = A/2 or M,C,Z,N = M/2 + /// + /// Each of the bits in A or M is shift one place to the right. The bit that was in bit 0 is shifted into the carry flag. Bit 7 is set to zero. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set to contents of old bit 0 + /// Z Zero Flag Set if result = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Accumulator $4A 1 2 + /// ZeroPage $46 2 5 + /// ZeroPage,X $56 2 6 + /// Absolute $4E 3 6 + /// Absolute,X $5E 3 7 + LSR(AddressMode), + /// NOP – No Operation + /// The NOP instruction causes no changes to the processor other than the normal incrementing of the program counter to the next instruction. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $EA 1 2 + NOP, + /// ORA – Logical Inclusive OR + /// A,Z,N = A|M + /// + /// An inclusive OR is performed, bit by bit, on the accumulator contents using the contents of a byte of memory. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $09 2 2 + /// Zero Page $05 2 3 + /// Zero Page,X $15 2 4 + /// Absolute $0D 3 4 + /// Absolute,X $1D 3 4 (+1 if page crossed) + /// Absolute,Y $19 3 4 (+1 if page crossed) + /// (Indirect,X) $01 2 6 + /// (Indirect),Y $11 2 5 (+1 if page crossed) + ORA(AddressMode), + /// PHA – Push Accumulator + /// Pushes a copy of the accumulator on to the stack. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $48 1 3 + PHA, + /// PHP – Push Processor Status + /// Pushes a copy of the status flags on to the stack. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $08 1 3 + PHP, + /// PLA – Pull Accumulator + /// Pulls an 8 bit value from the stack and into the accumulator. The zero and negative flags are set as appropriate. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of A is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $68 1 4 + PLA, + /// PLP – Pull Processor Status + /// Pulls an 8 bit value from the stack and into the processor flags. The flags will take on new states as determined by the value pulled. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set from stack + /// Z Zero Flag Set from stack + /// I Interrupt Disable Set from stack + /// D Decimal Mode Flag Set from stack + /// B Break Command Set from stack + /// V Overflow Flag Set from stack + /// N Negative Flag Set from stack + /// Addressing Mode Opcode Bytes Cycles + /// Implied $28 1 4 + PLP, + /// ROL – Rotate Left + /// Move each of the bits in either A or M one place to the left. Bit 0 is filled with the current value of the carry flag while the old bit 7 becomes the new carry flag value. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set to contents of old bit 7 + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Accumulator $2A 1 2 + /// ZeroPage $26 2 5 + /// ZeroPage,X $36 2 6 + /// Absolute $2E 3 6 + /// Absolute,X $3E 3 7 + ROL(AddressMode), + /// ROR – Rotate Right + /// Move each of the bits in either A or M one place to the right. Bit 7 is filled with the current value of the carry flag while the old bit 0 becomes the new carry flag value. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set to contents of old bit 0 + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of the result is set + /// Addressing Mode Opcode Bytes Cycles + /// Accumulator $6A 1 2 + /// ZeroPage $66 2 5 + /// ZeroPage,X $76 2 6 + /// Absolute $6E 3 6 + /// Absolute,X $7E 3 7 + ROR(AddressMode), + /// RTI – Return from Interrupt + /// The RTI instruction is used at the end of an interrupt processing routine. It pulls the processor flags from the stack followed by the program counter. + /// + /// Processor Status after use: + /// + /// C Carry Flag Set from stack + /// Z Zero Flag Set from stack + /// I Interrupt Disable Set from stack + /// D Decimal Mode Flag Set from stack + /// B Break Command Set from stack + /// V Overflow Flag Set from stack + /// N Negative Flag Set from stack + /// Addressing Mode Opcode Bytes Cycles + /// Implied $40 1 6 + RTI, + /// RTS – Return from Subroutine + /// The RTS instruction is used at the end of a subroutine to return to the calling routine. It pulls the program counter (minus one) from the stack. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $60 1 6 + RTS, + /// SBC – Subtract with Carry + /// A,Z,C,N = A-M-(1-C) + /// + /// This instruction subtracts the contents of a memory location to the accumulator together with the not of the carry bit. If overflow occurs the carry bit is clear, this enables multiple byte subtraction to be performed. + /// + /// Processor Status after use: + /// + /// C Carry Flag Clear if overflow in bit 7 + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Set if sign bit is incorrect + /// N Negative Flag Set if bit 7 set + /// Addressing Mode Opcode Bytes Cycles + /// Immediate $E9 2 2 + /// Zero Page $E5 2 3 + /// Zero Page,X $F5 2 4 + /// Absolute $ED 3 4 + /// Absolute,X $FD 3 4 (+1 if page crossed) + /// Absolute,Y $F9 3 4 (+1 if page crossed) + /// (Indirect,X) $E1 2 6 + /// (Indirect),Y $F1 2 5 (+1 if page crossed) + SBC(AddressMode), + /// SEC – Set Carry Flag + /// C = 1 + /// + /// Set the carry flag to one. + /// + /// C Carry Flag Set to 1 + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $38 1 2 + SEC, + /// SED – Set Decimal Flag + /// D = 1 + /// + /// Set the decimal mode flag to one. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Set to 1 + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $F8 1 2 + SED, + /// SEI – Set Interrupt Disable + /// I = 1 + /// + /// Set the interrupt disable flag to one. + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Set to 1 + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $78 1 2 + SEI, + /// STA – Store Accumulator + /// M = A + /// + /// Stores the contents of the accumulator into memory. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Zero Page $85 2 3 + /// Zero Page,X $95 2 4 + /// Absolute $8D 3 4 + /// Absolute,X $9D 3 5 + /// Absolute,Y $99 3 5 + /// (Indirect,X) $81 2 6 + /// (Indirect),Y $91 2 6 + STA(AddressMode), + /// STX – Store X Register + /// M = X + /// + /// Stores the contents of the X register into memory. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Zero Page $86 2 3 + /// Zero Page,Y $96 2 4 + /// Absolute $8E 3 4 + STX(AddressMode), + /// STY – Store Y Register + /// M = Y + /// + /// Stores the contents of the Y register into memory. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Zero Page $84 2 3 + /// Zero Page,X $94 2 4 + /// Absolute $8C 3 4 + STY(AddressMode), + /// TAX – Transfer Accumulator to X + /// X = A + /// + /// Copies the current contents of the accumulator into the X register and sets the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if X = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of X is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $AA 1 2 + TAX, + /// TAY – Transfer Accumulator to Y + /// Y = A + /// + /// Copies the current contents of the accumulator into the Y register and sets the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if Y = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of Y is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $A8 1 2 + TAY, + /// TSX – Transfer Stack Pointer to X + /// X = S + /// + /// Copies the current contents of the stack register into the X register and sets the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if X = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of X is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $BA 1 2 + TSX, + /// TXA – Transfer X to Accumulator + /// A = X + /// + /// Copies the current contents of the X register into the accumulator and sets the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of A is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $8A 1 + TXA, + /// TXS – Transfer X to Stack Pointer + /// S = X + /// + /// Copies the current contents of the X register into the stack register. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Not affected + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Not affected + /// Addressing Mode Opcode Bytes Cycles + /// Implied $9A 1 2 + TXS, + /// TYA – Transfer Y to Accumulator + /// A = Y + /// + /// Copies the current contents of the Y register into the accumulator and sets the zero and negative flags as appropriate. + /// + /// Processor Status after use: + /// + /// C Carry Flag Not affected + /// Z Zero Flag Set if A = 0 + /// I Interrupt Disable Not affected + /// D Decimal Mode Flag Not affected + /// B Break Command Not affected + /// V Overflow Flag Not affected + /// N Negative Flag Set if bit 7 of A is set + /// Addressing Mode Opcode Bytes Cycles + /// Implied $98 1 2 + TYA, +} + +impl Instruction { + pub fn from_bytes(decode_from: Vec) -> Instruction { + let id_byte = decode_from[0]; + + match id_byte { + /// ADC + ISA_OP_ADC_I..=ISA_OP_ADC_I => { + if decode_from.len() == 2 { + ADC(Immediate(decode_from[1])) + } else { + NOP + } + } + ISA_OP_ADC_Z..=ISA_OP_ADC_Z => { + ADC(ZeroPage(decode_from[1])) + } + ISA_OP_ADC_ZX..=ISA_OP_ADC_ZX => { + ADC(ZeroPageX(decode_from[1])) + } + ISA_OP_ADC_ABS..=ISA_OP_ADC_ABS => { + // build the u16 from the u8[1] and u8[2] + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + ADC(Absolute(word)) + } + ISA_OP_ADC_ABSX..=ISA_OP_ADC_ABSX => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + ADC(AbsoluteX(word)) + } + ISA_OP_ADC_ABSY..=ISA_OP_ADC_ABSY => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + ADC(AbsoluteY(word)) + } + ISA_OP_ADC_INDX..=ISA_OP_ADC_INDX => { + ADC(IndirectX(decode_from[1])) + } + ISA_OP_ADC_INDY..=ISA_OP_ADC_INDY => { + ADC(IndirectY(decode_from[1])) + } + /// AND + ISA_OP_AND_I..=ISA_OP_AND_I => { + AND(Immediate(decode_from[1])) + } + ISA_OP_AND_Z..=ISA_OP_AND_Z => { + AND(ZeroPage(decode_from[1])) + } + ISA_OP_AND_ZX..=ISA_OP_AND_ZX => { + AND(ZeroPageX(decode_from[1])) + } + ISA_OP_AND_ABS..=ISA_OP_AND_ABS => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + AND(Absolute(word)) + } + ISA_OP_AND_ABSX..=ISA_OP_AND_ABSX => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + AND(AbsoluteX(word)) + } + ISA_OP_AND_ABSY..=ISA_OP_AND_ABSY => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + AND(AbsoluteY(word)) + } + ISA_OP_AND_INDX..=ISA_OP_AND_INDX => { + AND(IndirectX(decode_from[1])) + } + ISA_OP_AND_INDY..=ISA_OP_AND_INDY => { + AND(IndirectY(decode_from[1])) + } + ISA_OP_ASL_A..=ISA_OP_ASL_A => { + ASL(Accumulator) + } + ISA_OP_ASL_Z..=ISA_OP_ASL_Z => { + ASL(ZeroPage(decode_from[1])) + } + ISA_OP_ASL_ZX..=ISA_OP_ASL_ZX => { + ASL(ZeroPageX(decode_from[1])) + } + ISA_OP_ASL_ABS..=ISA_OP_ASL_ABS => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + ASL(Absolute(word)) + } + ISA_OP_ASL_ABSX..=ISA_OP_ASL_ABSX => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + ASL(AbsoluteX(word)) + } + ISA_OP_BCC..=ISA_OP_BCC => { + BCC(Immediate(decode_from[1])) + } + ISA_OP_BCS..=ISA_OP_BCS => { + BCS(Immediate(decode_from[1])) + } + ISA_OP_BEQ..=ISA_OP_BEQ => { + BEQ(Immediate(decode_from[1])) + } + ISA_OP_BIT_ZP..=ISA_OP_BIT_ZP => { + BIT(ZeroPage(decode_from[1])) + } + ISA_OP_BIT_ABS..=ISA_OP_BIT_ABS => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + BIT(Absolute(word)) + } + ISA_OP_BMI..=ISA_OP_BMI => { + BMI(Immediate(decode_from[1])) + } + ISA_OP_BNE..=ISA_OP_BNE => { + BNE(Immediate(decode_from[1])) + } + ISA_OP_BPL..=ISA_OP_BPL => { + BPL(Immediate(decode_from[1])) + } + ISA_OP_BRK..=ISA_OP_BRK => { + BRK + } + ISA_OP_BVC..=ISA_OP_BVC => { + BVC(AddressMode::Immediate(decode_from[1])) + } + ISA_OP_BVS..=ISA_OP_BVS => { + BVS(Immediate(decode_from[1])) + } + ISA_OP_CLC..=ISA_OP_CLC => { + CLC + } + ISA_OP_CLD..=ISA_OP_CLD => { + CLD + } + ISA_OP_CLI..=ISA_OP_CLI => { + CLI + } + ISA_OP_CLV..=ISA_OP_CLV => { + CLV + } + ISA_OP_CMP_I..=ISA_OP_CMP_I => { + CMP(Immediate(decode_from[1])) + } + ISA_OP_CMP_ZP..=ISA_OP_CMP_ZP => { + CMP(ZeroPage(decode_from[1])) + } + ISA_OP_CMP_ZPX..=ISA_OP_CMP_ZPX => { + CMP(ZeroPageX(decode_from[1])) + } + ISA_OP_CMP_ABS..=ISA_OP_CMP_ABS => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + CMP(Absolute(word)) + } + ISA_OP_CMP_ABSX..=ISA_OP_CMP_ABSX => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + CMP(AbsoluteX(word)) + } + ISA_OP_CMP_INDX..=ISA_OP_CMP_INDX => { + CMP(IndirectX(decode_from[1])) + } + ISA_OP_CMP_INDY..=ISA_OP_CMP_INDY => { + CMP(IndirectY(decode_from[1])) + } + ISA_OP_CPX_I..=ISA_OP_CPX_I => { + CPX(Immediate(decode_from[1])) + } + ISA_OP_CPX_ZP..=ISA_OP_CPX_ZP => { + CPX(ZeroPage(decode_from[1])) + } + ISA_OP_CPX_ABS..=ISA_OP_CPX_ABS => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + CPX(Absolute(word)) + } + ISA_OP_CPY_I..=ISA_OP_CPY_I => { + CPY(Immediate(decode_from[1])) + } + ISA_OP_CPY_ZP..=ISA_OP_CPY_ZP => { + CPY(ZeroPage(decode_from[1])) + } + ISA_OP_CPY_ABS..=ISA_OP_CPY_ABS => { + let word = ((decode_from[2] as u16) << 8 | decode_from[1] as u16) as u16; + CPY(Absolute(word)) + } + ISA_OP_DEC_ZP..=ISA_OP_DEC_ZP => { + DEC(ZeroPage(decode_from[1])) + } + ISA_OP_DEC_ZPX..=ISA_OP_DEC_ZPX => { + DEC(ZeroPageX(decode_from[1])) + } + _ => NOP + } + } + + pub fn to_bytes(&self) -> Vec { + match self { + ADC(mode) => { + match mode { + Immediate(value) => + vec![ISA_OP_ADC_I, *value], + + ZeroPage(offset) => + vec![ISA_OP_ADC_Z, *offset], + + ZeroPageX(value) => + vec![ISA_OP_ADC_ZX, *value], + + Absolute(offset) => { + let high = ((offset & 0xff00) >> 8) as u8; + let low = (offset & 0x00ff) as u8; + vec![ISA_OP_ADC_ABS, low, high] + } + AbsoluteX(offset) => { + let high = ((offset & 0xff00) >> 8) as u8; + let low = (offset & 0x00ff) as u8; + vec![ISA_OP_ADC_ABSX, low, high] + } + AbsoluteY(offset) => { + let high = ((offset & 0xff00) >> 8) as u8; + let low = (offset & 0x00ff) as u8; + vec![ISA_OP_ADC_ABSY, low, high] + } + IndirectX(offset) => + vec![ISA_OP_ADC_INDX, *offset], + IndirectY(offset) => + vec![ISA_OP_ADC_INDY, *offset], + _ => { vec![] } + } + } + AND(mode) => { + match mode { + Immediate(value) => vec![ISA_OP_AND_I, *value], + ZeroPage(value) => vec![ISA_OP_AND_Z, *value], + ZeroPageX(value) => vec![ISA_OP_AND_ZX, *value], + Absolute(offset) => { + let high = ((offset & 0xff00) >> 8) as u8; + let low = (offset & 0x00ff) as u8; + vec![ISA_OP_AND_ABS, low, high] + } + AbsoluteX(offset) => { + let high = ((offset & 0xff00) >> 8) as u8; + let low = (offset & 0x00ff) as u8; + vec![ISA_OP_AND_ABSX, low, high] + } + AbsoluteY(offset) => { + let high = ((offset & 0xff00) >> 8) as u8; + let low = (offset & 0x00ff) as u8; + vec![ISA_OP_AND_ABSY, low, high] + } + IndirectX(value) => vec![ISA_OP_AND_INDX, *value], + IndirectY(value) => vec![ISA_OP_AND_INDY, *value], + _ => vec![] + } + } + // ASL(_) => {} + // BCC(_) => {} + // BCS(_) => {} + // BEQ(_) => {} + // BIT(_) => {} + // BMI(_) => {} + // BNE(_) => {} + // BPL(_) => {} + // BRK => {} + // BVC(_) => {} + // BVS(_) => {} + // CLC => {} + // CLD => {} + // CLI => {} + // CLV => {} + // CMP(_) => {} + // CPX(_) => {} + // CPY(_) => {} + // DEC(_) => {} + // DEX => {} + // DEY => {} + // EOR(_) => {} + // INC(_) => {} + // INX => {} + // INY => {} + // JMP(_) => {} + // JSR(_) => {} + // LDA(_) => {} + // LDX(_) => {} + // LDY(_) => {} + // LSR(_) => {} + // NOP => {} + // ORA(_) => {} + // PHA => {} + // PHP => {} + // PLA => {} + // PLP => {} + // ROL(_) => {} + // ROR(_) => {} + // RTI => {} + // RTS => {} + // SBC(_) => {} + // SEC => {} + // SED => {} + // SEI => {} + // STA(_) => {} + // STX(_) => {} + // STY(_) => {} + // TAX => {} + // TAY => {} + // TSX => {} + // TXA => {} + // TXS => {} + // TYA => {} + _ => { vec![] } + } + } + + pub fn to_string(&self) -> String { + match self { + Instruction::ADC(mode) => { + match mode { + AddressMode::Immediate(value) => { + String::from(format!("ADC #${value:02x}")) + } + AddressMode::ZeroPage(address) => { + String::from(format!("ADC ${address:02x}")) + } + AddressMode::ZeroPageX(address) => { + String::from(format!("ADC ${address:02x},X")) + } + AddressMode::Absolute(address) => { + String::from("TBD") + } + AddressMode::AbsoluteX(_) => { + String::from("TBD") + } + AddressMode::AbsoluteY(_) => { + String::from("TBD") + } + AddressMode::IndirectX(_) => { + String::from("TBD") + } + AddressMode::IndirectY(_) => { + String::from("TBD") + } + _ => String::from("Invalid instruction") + } + } + Instruction::AND(mode) => { + match mode { + AddressMode::Immediate(_) => { + String::from("TBD") + } + AddressMode::ZeroPage(_) => { + String::from("TBD") + } + AddressMode::ZeroPageX(_) => { + String::from("TBD") + } + AddressMode::Absolute(_) => { + String::from("TBD") + } + AddressMode::AbsoluteX(_) => { + String::from("TBD") + } + AddressMode::AbsoluteY(_) => { + String::from("TBD") + } + AddressMode::IndirectX(_) => { + String::from("TBD") + } + AddressMode::IndirectY(_) => { + String::from("TBD") + } + _ => { String::from("invalid Instruction") } + } + } + Instruction::ASL(_) => { + String::from("TBD") + } + Instruction::BCC(_) => { + String::from("TBD") + } + Instruction::BCS(_) => { + String::from("TBD") + } + Instruction::BEQ(_) => { + String::from("TBD") + } + Instruction::BIT(_) => { + String::from("TBD") + } + Instruction::BMI(_) => { + String::from("TBD") + } + Instruction::BNE(_) => { + String::from("TBD") + } + Instruction::BPL(_) => { + String::from("TBD") + } + Instruction::BRK => { + String::from("TBD") + } + Instruction::BVC(_) => { + String::from("TBD") + } + Instruction::BVS(_) => { + String::from("TBD") + } + Instruction::CLC => { + String::from("CLC") + } + Instruction::CLD => { + String::from("CLD") + } + _ => { + String::from("TBD") + } + } + } + fn execute(&self, mut system: Mos6502Cpu) { + match self { + // ADC – Add with Carry + // A,Z,C,N = A+M+C + // + // This instruction adds the contents of a memory location to the accumulator together with the carry bit. If overflow occurs the carry bit is set, this enables multiple byte addition to be performed. + // + // Processor Status after use: + // + // C Carry Flag Set if overflow in bit 7 + // Z Zero Flag Set if A = 0 + // I Interrupt Disable Not affected + // D Decimal Mode Flag Not affected + // B Break Command Not affected + // V Overflow Flag Set if sign bit is incorrect + // N Negative Flag Set if bit 7 set + Instruction::ADC(mode) => { + match mode { + AddressMode::Immediate(_) => {} + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + AddressMode::AbsoluteY(_) => {} + AddressMode::IndirectX(_) => {} + AddressMode::IndirectY(_) => {} + _ => {} + } + } + Instruction::AND(address) => { + match address { + AddressMode::Immediate(_) => {} + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + AddressMode::AbsoluteY(_) => {} + AddressMode::IndirectX(_) => {} + AddressMode::IndirectY(_) => {} + _ => { + // NOOP + } + } + } + Instruction::ASL(mode) => { + match mode { + // ISA_OP_ASL_A + AddressMode::Accumulator => {} + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + _ => {} + } + } + Instruction::BCC(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::BCS(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::BEQ(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::BIT(mode) => { + match mode { + AddressMode::ZeroPage(value) => {} + AddressMode::Absolute(value) => {} + _ => {} + } + } + Instruction::BMI(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::BNE(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::BPL(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::BRK => {} + Instruction::BVC(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::BVS(mode) => { + match mode { + AddressMode::Immediate(value) => {} + _ => {} + } + } + Instruction::CLC => { + system.poke_flag(Carry, false) + } + Instruction::CLD => { + system.poke_flag(Decimal, false) + } + Instruction::CLI => { + system.poke_flag(Interrupt, false) + } + Instruction::CLV => { + system.poke_flag(Overflow, false) + } + Instruction::CMP(mode) => { + match mode { + AddressMode::Immediate(_) => {} + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + AddressMode::AbsoluteY(_) => {} + AddressMode::IndirectX(_) => {} + AddressMode::IndirectY(_) => {} + _ => {} + } + } + Instruction::CPX(mode) => { + match mode { + AddressMode::Immediate(_) => {} + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + AddressMode::AbsoluteY(_) => {} + AddressMode::IndirectX(_) => {} + AddressMode::IndirectY(_) => {} + _ => {} + } + } + Instruction::CPY(mode) => { + match mode { + AddressMode::Immediate(_) => {} + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + AddressMode::AbsoluteY(_) => {} + AddressMode::IndirectX(_) => {} + AddressMode::IndirectY(_) => {} + _ => {} + } + } + Instruction::DEC(mode) => { + match mode { + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + _ => {} + } + } + Instruction::DEX => { + let mut x = system.peek_x(); + x -= 1; + system.poke_x(x); + } + Instruction::DEY => { + let mut y = system.peek_y(); + y -= 1; + system.poke_y(y); + } + Instruction::EOR(mode) => { + match mode { + AddressMode::Immediate(_) => {} + AddressMode::ZeroPage(_) => {} + AddressMode::ZeroPageX(_) => {} + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + AddressMode::AbsoluteY(_) => {} + AddressMode::IndirectX(_) => {} + AddressMode::IndirectY(_) => {} + _ => {} + } + } + Instruction::INC(mode) => { + match mode { + AddressMode::ZeroPage(value) => {} + AddressMode::ZeroPageX(value) => {} + AddressMode::Absolute(value) => {} + AddressMode::AbsoluteX(value) => {} + _ => {} + } + } + Instruction::INX => { + let mut x = system.peek_x(); + x += 1; + system.poke_x(x); + } + Instruction::INY => { + let mut y = system.peek_y(); + y += 1; + system.poke_y(y); + } + Instruction::JMP(mode) => { + match mode { + AddressMode::Absolute(_) => {} + AddressMode::IndirectX(_) => {} + _ => {} + } + } + Instruction::JSR(mode) => { + match mode { + AddressMode::Absolute(address) => {} + _ => {} + } + } + Instruction::LDA(mode) => { + match mode { + AddressMode::Immediate(value) => { + system.poke_a(*value) + } + AddressMode::ZeroPage(offset) => { + let value_to_write = system.peek(*offset as u16); + system.poke_a(value_to_write); + } + AddressMode::ZeroPageX(_) => { + let current_x = system.peek_x(); + } + AddressMode::Absolute(_) => {} + AddressMode::AbsoluteX(_) => {} + AddressMode::AbsoluteY(_) => {} + AddressMode::IndirectX(_) => {} + AddressMode::IndirectY(_) => {} + _ => { + debug!("Invalid LDA instruction"); + } + }; + } + Instruction::LDX(_) => {} + Instruction::LDY(_) => {} + Instruction::LSR(_) => {} + Instruction::NOP => {} + Instruction::ORA(_) => {} + Instruction::PHA => {} + Instruction::PHP => {} + Instruction::PLA => {} + Instruction::PLP => {} + Instruction::ROL(_) => {} + Instruction::ROR(_) => {} + Instruction::RTI => {} + Instruction::RTS => {} + Instruction::SBC(_) => {} + Instruction::SEC => {} + Instruction::SED => {} + Instruction::SEI => {} + Instruction::STA(_) => {} + Instruction::STX(_) => {} + Instruction::STY(_) => {} + Instruction::TAX => {} + Instruction::TAY => {} + Instruction::TSX => {} + Instruction::TXA => {} + Instruction::TXS => {} + Instruction::TYA => {} + }; + } +} + +#[cfg(test)] +mod test { + use crate::address_mode::AddressMode::*; + use crate::instruction::Instruction::*; + use super::*; + + #[test] + fn to_string() { + let params = vec![ + (ADC(Immediate(0x01)), "ADC #$01"), + (ADC(ZeroPage(0x01)), "ADC $01"), + (ADC(ZeroPageX(0x01)), "ADC $01,X"), + (ADC(Absolute(0xabcd)), "ADC $abcd"), + (ADC(AbsoluteX(0xabcd)), "ADC $abcd,X"), + (ADC(AbsoluteY(0xabcd)), "ADC $abcd,Y"), + (ADC(IndirectX(0xab)), "ADC ($ab,X)"), + (ADC(IndirectY(0xab)), "ADC ($ab),Y"), + (SBC(Immediate(0x01)), "SBC #$01"), + (SBC(ZeroPage(0x01)), "SBC $01"), + (SBC(ZeroPageX(0x01)), "SBC $01,X"), + (SBC(Absolute(0xabcd)), "SBC $abcd"), + (SBC(AbsoluteX(0xabcd)), "SBC $abcd,X"), + (SBC(AbsoluteY(0xabcd)), "SBC $abcd,Y"), + (SBC(IndirectX(0xab)), "SBC ($ab,X)"), + (SBC(IndirectY(0xab)), "SBC ($ab),Y"), + ]; + } +} \ No newline at end of file diff --git a/core/src/isa/decoder.rs b/core/src/isa/decoder.rs new file mode 100644 index 0000000..074baaf --- /dev/null +++ b/core/src/isa/decoder.rs @@ -0,0 +1,74 @@ +use crate::address_mode::AddressMode::*; +use crate::constants::*; +use crate::instruction::Instruction; +use crate::instruction::Instruction::*; + +pub struct Decoder {} + + +impl Decoder { + /// decode + /// + /// Returns the decoded instruction or a NOP. + /// NOP will be returned when an instruction without a valid parameter + /// and more data is required to decode. + pub fn decode(decode_from: Vec) -> Instruction { + NOP + } +} + +#[cfg(test)] +mod test { + use super::*; + + + #[test] + fn valid_decodes() { + let params = vec![ + (vec![ISA_OP_ADC_I, 0xab], ADC(Immediate(0xab))), + (vec![ISA_OP_ADC_Z, 0xab], ADC(ZeroPage(0xab))), + (vec![ISA_OP_ADC_ZX, 0xab], ADC(ZeroPageX(0xab))), + (vec![ISA_OP_ADC_ABS, 0xab, 0xcd], ADC(Absolute(0xcdab))), + (vec![ISA_OP_ADC_ABSX, 0xcd, 0xab], ADC(AbsoluteX(0xabcd))), + (vec![ISA_OP_ADC_ABSY, 0xcd, 0xab], ADC(AbsoluteY(0xabcd))), + (vec![ISA_OP_ADC_INDX, 0xab], ADC(IndirectX(0xab))), + (vec![ISA_OP_ADC_INDY, 0xcd], ADC(IndirectY(0xcd))), + + (vec![ISA_OP_AND_I, 0xab], AND(Immediate(0xab))), + (vec![ISA_OP_AND_Z, 0xab], AND(ZeroPage(0xab))), + (vec![ISA_OP_AND_ZX, 0xab], AND(ZeroPageX(0xab))), + (vec![ISA_OP_AND_ABS, 0xcd, 0xab], AND(Absolute(0xabcd))), + + (vec![ISA_OP_ASL_A], ASL(Accumulator)), + (vec![ISA_OP_ASL_Z, 0xab], ASL(ZeroPage(0xab))), + (vec![ISA_OP_ASL_ZX, 0xab], ASL(ZeroPageX(0xab))), + (vec![ISA_OP_ASL_ABS, 0xab, 0xcd], ASL(Absolute(0xcdab))), + (vec![ISA_OP_ASL_ABSX, 0xab, 0xcd], ASL(AbsoluteX(0xcdab))), + + (vec![ISA_OP_BCC, 0xab], BCC(Immediate(0xab))), + + (vec![ISA_OP_BEQ, 0xab], BEQ(Immediate(0xab))), + + (vec![ISA_OP_BIT_ZP, 0xab], BIT(ZeroPage(0xab))), + (vec![ISA_OP_BIT_ABS, 0xab, 0xcd], BIT(Absolute(0xcdab))), + + (vec![ISA_OP_BMI, 0xab], BMI(Immediate(0xab))), + (vec![ISA_OP_BNE, 0xab], BNE(Immediate(0xab))), + (vec![ISA_OP_BPL, 0xab], BPL(Immediate(0xab))), + (vec![ISA_OP_BVC, 0xab], BVC(Immediate(0xab))), + (vec![ISA_OP_BVS, 0xab], BVS(Immediate(0xab))), + + (vec![ISA_OP_BRK], BRK), + + ]; + + for (bytes, instruction) in params { + println!("Expecting {:?} to be {:?}", bytes, instruction); + + assert_eq!( + Decoder::decode(bytes), + instruction + ) + } + } +} \ No newline at end of file diff --git a/core/src/isa/encode.rs b/core/src/isa/encode.rs new file mode 100644 index 0000000..ac3667b --- /dev/null +++ b/core/src/isa/encode.rs @@ -0,0 +1,129 @@ +use crate::address_mode::AddressMode::*; +use crate::constants::*; +use crate::instruction::Instruction; +use crate::instruction::Instruction::*; + +pub struct Encoder {} + +impl Encoder { + pub fn encode(to_encode: Instruction) -> Vec { + match to_encode { + // ADC(_) => {} + // AND(_) => {} + // ASL(_) => {} + BCC(mode) => { + match mode { + Immediate(address)=> { + vec![ISA_OP_BCC, address] + } + _ => NOP.to_bytes() + } + } + // BCS(_) => {} + // BEQ(_) => {} + // BIT(_) => {} + // BMI(_) => {} + // BNE(_) => {} + // BPL(_) => {} + // BRK => {} + // BVC(_) => {} + // BVS(_) => {} + // CLC => {} + // CLD => {} + // CLI => {} + // CLV => {} + // CMP(_) => {} + // CPX(_) => {} + // CPY(_) => {} + // DEC(_) => {} + // DEX => {} + // DEY => {} + // EOR(_) => {} + // INC(_) => {} + // INX => {} + // INY => {} + // JMP(_) => {} + // JSR(_) => {} + // LDA(_) => {} + // LDX(_) => {} + // LDY(_) => {} + // LSR(_) => {} + // NOP => {} + // ORA(_) => {} + // PHA => {} + // PHP => {} + // PLA => {} + // PLP => {} + // ROL(_) => {} + // ROR(_) => {} + // RTI => {} + // RTS => {} + // SBC(_) => {} + // SEC => {} + // SED => {} + // SEI => {} + // STA(_) => {} + // STX(_) => {} + // STY(_) => {} + // TAX => {} + // TAY => {} + // TSX => {} + // TXA => {} + // TXS => {} + // TYA => {} + _ => NOP.to_bytes() + } + } +} + +#[cfg(test)] +mod test { + use crate::constants::*; + use super::*; + + #[test] + fn adc_decode() { + let params = vec![ + (vec![ISA_OP_ADC_I, 0xab], ADC(Immediate(0xab))), + (vec![ISA_OP_ADC_Z, 0xab], ADC(ZeroPage(0xab))), + (vec![ISA_OP_ADC_ZX, 0xab], ADC(ZeroPageX(0xab))), + (vec![ISA_OP_ADC_ABS, 0xab, 0xcd], ADC(Absolute(0xcdab))), + (vec![ISA_OP_ADC_ABSX, 0xcd, 0xab], ADC(AbsoluteX(0xabcd))), + (vec![ISA_OP_ADC_ABSY, 0xcd, 0xab], ADC(AbsoluteY(0xabcd))), + (vec![ISA_OP_ADC_INDX, 0xab], ADC(IndirectX(0xab))), + (vec![ISA_OP_ADC_INDY, 0xcd], ADC(IndirectY(0xcd))), + + (vec![ISA_OP_AND_I, 0xab], AND(Immediate(0xab))), + (vec![ISA_OP_AND_Z, 0xab], AND(ZeroPage(0xab))), + (vec![ISA_OP_AND_ZX, 0xab], AND(ZeroPageX(0xab))), + (vec![ISA_OP_AND_ABS, 0xcd, 0xab], AND(Absolute(0xabcd))), + + (vec![ISA_OP_ASL_A], ASL(Accumulator)), + (vec![ISA_OP_ASL_Z, 0xab], ASL(ZeroPage(0xab))), + (vec![ISA_OP_ASL_ZX, 0xab], ASL(ZeroPageX(0xab))), + (vec![ISA_OP_ASL_ABS, 0xab, 0xcd], ASL(Absolute(0xcdab))), + (vec![ISA_OP_ASL_ABSX, 0xab, 0xcd], ASL(AbsoluteX(0xcdab))), + + (vec![ISA_OP_BCC, 0xab], BCC(Immediate(0xab))), + + (vec![ISA_OP_BEQ, 0xab], BEQ(Immediate(0xab))), + + (vec![ISA_OP_BIT_ZP, 0xab], BIT(ZeroPage(0xab))), + (vec![ISA_OP_BIT_ABS, 0xab, 0xcd], BIT(Absolute(0xcdab))), + + (vec![ISA_OP_BMI, 0xab], BMI(Immediate(0xab))), + (vec![ISA_OP_BNE, 0xab], BNE(Immediate(0xab))), + (vec![ISA_OP_BPL, 0xab], BPL(Immediate(0xab))), + (vec![ISA_OP_BVC, 0xab], BVC(Immediate(0xab))), + (vec![ISA_OP_BVS, 0xab], BVS(Immediate(0xab))), + + (vec![ISA_OP_BRK], BRK), + + ]; + + for (bytes, instruction) in params { + let encoded = Encoder::encode(bytes); + assert_eq!(encoded, instruction.into()); + } + } +} diff --git a/core/src/isa/microcode_steps.rs b/core/src/isa/microcode_steps.rs new file mode 100644 index 0000000..2c27d5b --- /dev/null +++ b/core/src/isa/microcode_steps.rs @@ -0,0 +1,18 @@ +use crate::mos6502flags::Mos6502Flag; + +pub enum MicrocodeStep { + ReadRegisterA, + ReadRegisterX, + ReadRegisterY, + ReadFlag(Mos6502Flag), + WriteRegisterA, + WriteRegisterX, + WriteRegisterY, + WriteFlag(Mos6502Flag, bool), + ReadMemory(u16), + WriteMemory(u16, u8), + ALUAdd(u8, u8), + ALUSub(u8, u8), + ALUAddC(u8, u8, bool), + ALUSubC(u8, u8, bool), +} diff --git a/core/src/isa/mod.rs b/core/src/isa/mod.rs new file mode 100644 index 0000000..6f28f74 --- /dev/null +++ b/core/src/isa/mod.rs @@ -0,0 +1,4 @@ + +pub mod encode; +pub mod decoder; +pub mod microcode_steps; diff --git a/core/src/lib.rs b/core/src/lib.rs index e69de29..8537419 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -0,0 +1,6 @@ +pub mod address_mode; +pub mod mos6502cpu; +pub mod instruction; +pub mod mos6502flags; +pub mod isa; +pub mod constants; diff --git a/core/src/mos6502cpu.rs b/core/src/mos6502cpu.rs new file mode 100644 index 0000000..2b95e5d --- /dev/null +++ b/core/src/mos6502cpu.rs @@ -0,0 +1,72 @@ +use crate::mos6502flags::{Mos6502Flag, Mos6502Flags}; + +pub const SIZE_1KB: usize = 1024 * 1024; +pub const SIZE_64KB: usize = SIZE_1KB * 64; + +pub struct Mos6502Cpu { + memory: [u8; SIZE_64KB], + a: u8, + x: u8, + y: u8, + flags: Mos6502Flags, + pc: u16, + s: u8, + microcode_step: u8 +} + +impl Mos6502Cpu { + pub fn new() -> Mos6502Cpu { + Mos6502Cpu { + memory: [0; SIZE_64KB], + a: 0, + x: 0, + y: 0, + flags: Mos6502Flags::default(), + pc: 0, + s: 0xfd, + microcode_step: 0 + } + } + + pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool { + self.flags.flag(flag_to_read) + } + pub fn poke_flag(&mut self, flag_to_set: Mos6502Flag, new_value: bool) { + if new_value { self.flags.set_flag(flag_to_set) } else { self.flags.clear_flag(flag_to_set) } + } + + pub fn peek(&self, offset: u16) -> u8 { + self.memory[offset as usize] + } + + pub fn poke(&mut self, offset: u16, value: u8) { + self.memory[offset as usize] = value + } + + pub fn peek_a(&self) -> u8 { + self.a + } + pub fn poke_a(&mut self, new_a: u8) { + self.a = new_a; + } + + pub fn peek_x(&self) -> u8 { + self.x + } + + pub fn poke_x(&mut self, new_x: u8) { + self.x = new_x + } + + pub fn peek_y(&self) -> u8 { + self.y + } + + pub fn poke_y(&mut self, new_y: u8) { + self.y = new_y + } + + pub fn tick(&mut self) { + + } +} diff --git a/core/src/mos6502flags.rs b/core/src/mos6502flags.rs new file mode 100644 index 0000000..67779f6 --- /dev/null +++ b/core/src/mos6502flags.rs @@ -0,0 +1,98 @@ + +pub enum Mos6502Flag { + Carry, + Zero, + Interrupt, + Decimal, + Break, + Overflow, + Negative +} + +#[derive(Default)] +pub struct Mos6502Flags { + carry: bool, + zero: bool, + interrupt: bool, + decimal: bool, + break_flag: bool, + overflow: bool, + negative: bool, +} + +impl Mos6502Flags { + + pub fn set_flag(&mut self, flag_to_set: Mos6502Flag) { + self.change_flag(flag_to_set, true); + } + + pub fn clear_flag(&mut self, flag_to_clear: Mos6502Flag) { + self.change_flag(flag_to_clear, false); + } + + fn change_flag(&mut self, flag_to_change: Mos6502Flag, new_value: bool) { + match flag_to_change { + Mos6502Flag::Carry => { + self.carry = new_value + } + Mos6502Flag::Zero => { + self.zero = new_value + } + Mos6502Flag::Interrupt => { + self.interrupt = new_value + } + Mos6502Flag::Decimal => { + self.decimal = new_value + } + Mos6502Flag::Break => { + self.break_flag = new_value + } + Mos6502Flag::Overflow => { + self.overflow = new_value + } + Mos6502Flag::Negative => { + self.negative = new_value + } + } + } + + pub fn flag(&self, flag_to_read: Mos6502Flag) -> bool { + match flag_to_read { + Mos6502Flag::Carry => { + self.carry + } + Mos6502Flag::Zero => { + self.zero + } + Mos6502Flag::Interrupt => { + self.interrupt + } + Mos6502Flag::Decimal => { + self.decimal + } + Mos6502Flag::Break => { + self.break_flag + } + Mos6502Flag::Overflow => { + self.overflow + } + Mos6502Flag::Negative => { + self.negative + } + } + } +} + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn default() { + let expected = Mos6502Flag::default(); + + assert_eq!(expected, + Mos6502Flag::default()); + } +}