From c081d7943f2e839052b80aa603a54280a2987e59 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Tue, 14 Oct 2025 13:18:53 -0700 Subject: [PATCH 01/33] speed up dosbox, addresses issue #30 --- test/as65.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/as65.sh b/test/as65.sh index 20059f4..0753879 100755 --- a/test/as65.sh +++ b/test/as65.sh @@ -41,7 +41,14 @@ cp "$src_file" "$dest_dir/" || { echo "Copy failed"; exit 1; } ( cd "$(dirname "$dest_dir")" echo "Running assembler under DOSBox..." - dosbox -c "mount c $(pwd)" \ + dosbox \ + -c "config -set core=dynamic" \ + -c "config -set cycles=max" \ + -c "config -set cycleup=100000" \ + -c "config -set cycledown=100000" \ + -c "config -set frameskip=5" \ + -c "config -set output=surface" \ + -c "mount c $(pwd)" \ -c "c:" \ -c "cd as65_142" \ -c "AS65-DOS.EXE -x1 -o${base_name}.hex -l -m -s2 -w -h0 -c -i -t -u -z $(basename "$src_file")" \ From 19a099ee04e42beb478c845fff326289e9f71d41 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Tue, 14 Oct 2025 14:37:44 -0700 Subject: [PATCH 02/33] minor indentation tweaks --- test/main.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index b0e211c..8955224 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -15,15 +15,18 @@ int start = -1; int success = -1; int retaddr = -1; -void writeRam(uint16_t addr, uint8_t val) { +void writeRam(uint16_t addr, uint8_t val) +{ ram[addr] = val; } -uint8_t readRam(uint16_t addr) { +uint8_t readRam(uint16_t addr) +{ return ram[addr]; } -void tick(mos6502*) { +void tick(mos6502*) +{ static uint16_t lastpc = 0xFFFF; static int count = 0; uint16_t pc = cpu->GetPC(); @@ -40,11 +43,12 @@ void tick(mos6502*) { if (retaddr != -1) { if (ram[retaddr]) { printf("\ncode %02X\n", ram[retaddr]); - printf("Y=%02x\n",cpu->GetY()); + printf("Y=%02x\n", cpu->GetY()); printf("N1=%02x N2=%02x\n", ram[0], ram[1]); printf("HA=%02x HNVZC=%02x\n", ram[2], ram[3]); printf("DA=%02x DNVZC=%02x\n", ram[4], ram[5]); - printf("AR=%02x NF=%02x VF=%02x ZF=%02x CF=%02x\n", ram[6], ram[7], ram[8], ram[9], ram[10]); + printf("AR=%02x NF=%02x VF=%02x ZF=%02x CF=%02x\n", ram[6], ram[7], ram[8], ram[9], + ram[10]); printf("FAIL\n"); exit(-1); } @@ -65,12 +69,14 @@ void tick(mos6502*) { lastpc = pc; } -void bail(const char *s) { +void bail(const char *s) +{ fprintf(stderr, "%s\n", s); exit(-1); } -uint32_t fetch(const char *s, uint16_t offset, uint8_t count) { +uint32_t fetch(const char *s, uint16_t offset, uint8_t count) +{ uint32_t ret = 0; uint32_t val; for (int i = 0; i < count; i++) { @@ -89,7 +95,8 @@ uint32_t fetch(const char *s, uint16_t offset, uint8_t count) { return ret; } -void handle_hex(const char *fname) { +void handle_hex(const char *fname) +{ char buf[1024]; FILE *f = fopen(fname, "r"); if (!f) { @@ -120,7 +127,8 @@ void handle_hex(const char *fname) { fclose(f); } -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ if (argc != 4) { fprintf(stderr, "Usage: %s .hex \n", argv[0]); return -1; From a5433cb84999782d2f5352105e26c7449af68602 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Tue, 14 Oct 2025 16:11:52 -0700 Subject: [PATCH 03/33] fixed IRQ / NMI implementation, working 6502_interrupt_test --- mos6502.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++--------- mos6502.h | 25 ++++++++++++-- test/Makefile | 12 ++++--- test/main.cpp | 7 ++++ 4 files changed, 115 insertions(+), 21 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index 3daca39..2238917 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -35,6 +35,11 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) , reset_Y(0x00) , reset_sp(0xFD) , reset_status(CONSTANT) + , irq_handling(false) + , irq_line(true) + , nmi_pending(false) + , nmi_handling(false) + , nmi_line(true) { Write = (BusWrite)w; Read = (BusRead)r; @@ -399,6 +404,13 @@ uint16_t mos6502::Addr_INY() void mos6502::Reset() { + // do not set or clear irq_line, that's external to us + irq_handling = false; + + // do not set or clear nmi_line, that's external to us + nmi_pending = false; + nmi_handling = false; + A = reset_A; Y = reset_Y; X = reset_X; @@ -431,25 +443,22 @@ uint8_t mos6502::StackPop() return Read(0x0100 + sp); } -void mos6502::IRQ() +void mos6502::Svc_IRQ() { - if(!IF_INTERRUPT()) - { - //SET_BREAK(0); - StackPush((pc >> 8) & 0xFF); - StackPush(pc & 0xFF); - StackPush((status & ~BREAK) | CONSTANT); - SET_INTERRUPT(1); - - // load PC from interrupt request vector - uint8_t pcl = Read(irqVectorL); - uint8_t pch = Read(irqVectorH); - pc = (pch << 8) + pcl; - } + //SET_BREAK(0); + StackPush((pc >> 8) & 0xFF); + StackPush(pc & 0xFF); + StackPush((status & ~BREAK) | CONSTANT); + SET_INTERRUPT(1); + + // load PC from interrupt request vector + uint8_t pcl = Read(irqVectorL); + uint8_t pch = Read(irqVectorH); + pc = (pch << 8) + pcl; return; } -void mos6502::NMI() +void mos6502::Svc_NMI() { //SET_BREAK(0); StackPush((pc >> 8) & 0xFF); @@ -464,6 +473,29 @@ void mos6502::NMI() return; } +bool mos6502::CheckInterrupts() { + + // NMI is edge triggered + if (nmi_pending && !nmi_handling) { + nmi_pending = false; + nmi_handling = true; + Svc_NMI(); + return true; + } + + // check disabled bit + if(!IF_INTERRUPT()) { + // IRQ is level triggered + if (irq_line == false && !nmi_handling && !irq_handling) { + irq_handling = true; + Svc_IRQ(); + return true; + } + } + + return false; +} + void mos6502::Run( int32_t cyclesRemaining, uint64_t& cycleCount, @@ -474,6 +506,10 @@ void mos6502::Run( while(cyclesRemaining > 0 && !illegalOpcode) { + if (CheckInterrupts()) { + cycleCount += 6; // TODO FIX verify this is correct + } + // fetch opcode = Read(pc++); @@ -505,6 +541,8 @@ void mos6502::RunEternally() while(!illegalOpcode) { + CheckInterrupts(); + // fetch opcode = Read(pc++); @@ -558,6 +596,22 @@ uint8_t mos6502::GetY() return Y; } +void mos6502::IRQ(bool line) +{ + irq_line = line; +} + +void mos6502::NMI(bool line) +{ + // falling edge triggered + if (nmi_line == true && line == false) { + if (!nmi_handling) { + nmi_pending = true; + } + } + nmi_line = line; +} + void mos6502::SetResetS(uint8_t value) { reset_sp = value; @@ -1073,6 +1127,14 @@ void mos6502::Op_RTI(uint16_t src) hi = StackPop(); pc = (hi << 8) | lo; + + if (nmi_handling) { + nmi_handling = false; + } + else if (irq_handling) { + irq_handling = false; + } + return; } diff --git a/mos6502.h b/mos6502.h index 6977beb..d5f3068 100644 --- a/mos6502.h +++ b/mos6502.h @@ -55,6 +55,15 @@ class mos6502 bool crossed; + bool irq_handling; // are we currently handling an IRQ? + bool irq_line; // current state of the line + + bool nmi_pending; // is there an NMI pending? + bool nmi_handling; // are we currently handling an NMI? + bool nmi_line; // current state of the NMI line + + bool CheckInterrupts(); + // addressing modes uint16_t Addr_ACC(); // ACCUMULATOR uint16_t Addr_IMM(); // IMMEDIATE @@ -140,6 +149,9 @@ class mos6502 void Op_ILLEGAL(uint16_t src); + void Svc_NMI(); + void Svc_IRQ(); + // IRQ, reset, NMI vectors static const uint16_t irqVectorH = 0xFFFF; static const uint16_t irqVectorL = 0xFFFE; @@ -166,8 +178,17 @@ class mos6502 CYCLE_COUNT, }; mos6502(BusRead r, BusWrite w, ClockCycle c = nullptr); - void NMI(); - void IRQ(); + + // set or clear the NMI line. this is an input to the processor. + // a high to low edge transition will trigger an interrupt. + // line state is NOT cleared by Reset() + void NMI(bool line); + + // set or clear the IRQ line. this is an input to the processor. + // a low level will trigger an interrupt. + // line state is NOT cleared by Reset() + void IRQ(bool line); + void Reset(); void Run( int32_t cycles, diff --git a/test/Makefile b/test/Makefile index 2a55354..0999699 100644 --- a/test/Makefile +++ b/test/Makefile @@ -37,7 +37,7 @@ ft.hex: 6502_functional_test: main ft.hex @echo "================ Running $@" - ./main ft.hex 0x400 0x3469 + ./main ft.hex 0x400 0x3469 # magic numbers come from comments and examination of *.lst dt.hex: cp $(BASE)/6502_decimal_test.a65 dt.a65 @@ -46,8 +46,12 @@ dt.hex: 6502_decimal_test: main dt.hex @echo "================ Running $@" - ./main dt.hex 0x200 ?0x000b + ./main dt.hex 0x200 ?0x000b # magic numbers come from comments and examination of *.lst -6502_interrupt_test: +it.hex: + cp $(BASE)/6502_interrupt_test.a65 it.a65 + ./as65.sh it.a65 + +6502_interrupt_test: main it.hex @echo "================ Running $@" - @echo "(not yet implemented)" + ./main it.hex 0x400 0x06f5 # magic numbers come from comments and examination of *.lst diff --git a/test/main.cpp b/test/main.cpp index 8955224..096ec81 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -18,6 +18,13 @@ int retaddr = -1; void writeRam(uint16_t addr, uint8_t val) { ram[addr] = val; + + // feedback + if (addr == 0xbffc) { + // things are inverted here + cpu->IRQ((val & 1) ? false : true); + cpu->NMI((val & 2) ? false : true); + } } uint8_t readRam(uint16_t addr) From ac4b72660964f5041e70614d965963788cd6165a Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 10:21:26 -0700 Subject: [PATCH 04/33] compile test harness with -O3 for more speed (saves 1 second) --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index 2a55354..104d70a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -27,7 +27,7 @@ $(BASE)/as65_142: ( cd $(BASE)/as65_142 && unzip ../as65_142.zip ) main: main.cpp ../mos6502.cpp ../mos6502.h - g++ -g -o main ../mos6502.cpp main.cpp + g++ -O3 -o main ../mos6502.cpp main.cpp tests: 6502_functional_test 6502_decimal_test 6502_interrupt_test From a276560c8826d93f28543f4722db5467e7b34871 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 11:50:40 -0700 Subject: [PATCH 05/33] adds setters for internal registers --- mos6502.cpp | 39 ++++++++++++++++++++++++++++++++++----- mos6502.h | 16 ++++++++++++++-- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index 3daca39..cc3987c 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -558,14 +558,39 @@ uint8_t mos6502::GetY() return Y; } -void mos6502::SetResetS(uint8_t value) +void mos6502::SetPC(uint16_t n) { - reset_sp = value; + pc = n; } -void mos6502::SetResetP(uint8_t value) +void mos6502::SetS (uint8_t n) { - reset_status = value | CONSTANT | BREAK; + sp = n; +} + +void mos6502::SetP (uint8_t n) +{ + status = n; +} + +void mos6502::SetA (uint8_t n) +{ + A = n; +} + +void mos6502::SetX (uint8_t n) +{ + X = n; +} + +void mos6502::SetY (uint8_t n) +{ + Y = n; +} + +void mos6502::SetResetS(uint8_t value) +{ + reset_sp = value; } void mos6502::SetResetA(uint8_t value) @@ -583,6 +608,11 @@ void mos6502::SetResetY(uint8_t value) reset_Y = value; } +void mos6502::SetResetP(uint8_t value) +{ + reset_status = value | CONSTANT | BREAK; +} + uint8_t mos6502::GetResetS() { return reset_sp; @@ -613,7 +643,6 @@ void mos6502::Op_ILLEGAL(uint16_t src) illegalOpcode = true; } - void mos6502::Op_ADC(uint16_t src) { uint8_t m = Read(src); diff --git a/mos6502.h b/mos6502.h index 6977beb..bd3bc4f 100644 --- a/mos6502.h +++ b/mos6502.h @@ -12,7 +12,7 @@ class mos6502 { -private: + private: // register reset values uint8_t reset_A; uint8_t reset_X; @@ -160,7 +160,7 @@ class mos6502 inline void StackPush(uint8_t byte); inline uint8_t StackPop(); -public: + public: enum CycleMethod { INST_COUNT, CYCLE_COUNT, @@ -177,17 +177,29 @@ class mos6502 // useful when running e.g. WOZ Monitor // no need to worry about cycle exhaus- // tion + + // Various getter/setters + uint16_t GetPC(); uint8_t GetS(); uint8_t GetP(); uint8_t GetA(); uint8_t GetX(); uint8_t GetY(); + + void SetPC(uint16_t n); + void SetS(uint8_t n); + void SetP(uint8_t n); + void SetA(uint8_t n); + void SetX(uint8_t n); + void SetY(uint8_t n); + void SetResetS(uint8_t value); void SetResetP(uint8_t value); void SetResetA(uint8_t value); void SetResetX(uint8_t value); void SetResetY(uint8_t value); + uint8_t GetResetS(); uint8_t GetResetP(); uint8_t GetResetA(); From 62b452ac049d21e71c4a65d7eece87fc9fb44528 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 12:05:26 -0700 Subject: [PATCH 06/33] moved IRQ/NMI to avoid future merge conflict --- mos6502.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index 2238917..7651c5b 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -596,22 +596,6 @@ uint8_t mos6502::GetY() return Y; } -void mos6502::IRQ(bool line) -{ - irq_line = line; -} - -void mos6502::NMI(bool line) -{ - // falling edge triggered - if (nmi_line == true && line == false) { - if (!nmi_handling) { - nmi_pending = true; - } - } - nmi_line = line; -} - void mos6502::SetResetS(uint8_t value) { reset_sp = value; @@ -667,6 +651,21 @@ void mos6502::Op_ILLEGAL(uint16_t src) illegalOpcode = true; } +void mos6502::IRQ(bool line) +{ + irq_line = line; +} + +void mos6502::NMI(bool line) +{ + // falling edge triggered + if (nmi_line == true && line == false) { + if (!nmi_handling) { + nmi_pending = true; + } + } + nmi_line = line; +} void mos6502::Op_ADC(uint16_t src) { From 538631a45e35e865cc2e28bf36f42cb480002541 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 12:11:41 -0700 Subject: [PATCH 07/33] code move anticipating possible future merge conflict --- mos6502.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index 7651c5b..b6c14a7 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -402,6 +402,22 @@ uint16_t mos6502::Addr_INY() return addr; } +void mos6502::IRQ(bool line) +{ + irq_line = line; +} + +void mos6502::NMI(bool line) +{ + // falling edge triggered + if (nmi_line == true && line == false) { + if (!nmi_handling) { + nmi_pending = true; + } + } + nmi_line = line; +} + void mos6502::Reset() { // do not set or clear irq_line, that's external to us @@ -651,21 +667,6 @@ void mos6502::Op_ILLEGAL(uint16_t src) illegalOpcode = true; } -void mos6502::IRQ(bool line) -{ - irq_line = line; -} - -void mos6502::NMI(bool line) -{ - // falling edge triggered - if (nmi_line == true && line == false) { - if (!nmi_handling) { - nmi_pending = true; - } - } - nmi_line = line; -} void mos6502::Op_ADC(uint16_t src) { From 003df4e0ef2a6814b031efd3109ea40a9487e7a7 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 12:42:25 -0700 Subject: [PATCH 08/33] issue #35 ; Guard for the terminally creative user --- test/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Makefile b/test/Makefile index 2a55354..5062035 100644 --- a/test/Makefile +++ b/test/Makefile @@ -17,7 +17,11 @@ BASE := 6502_65C02_functional_tests all: $(BASE) $(BASE)/as65_142 main tests tests @echo TEST COMPLETE: success +clean: + rm -rf $(BASE) ft.* dt.* it.* + $(BASE): + @test ! -e "$@" || { echo "do NOT use 'make -B', use 'make clean ; make' instead"; exit 1; } @echo "Fetching functional tests from GitHub..." git clone https://github.com/Klaus2m5/6502_65C02_functional_tests From d040713056d43522bd7cf8da81aac4903532421c Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 14:19:16 -0700 Subject: [PATCH 09/33] added "quiet" flag --- test/main.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index b0e211c..f9c1bbf 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -3,9 +3,13 @@ #include "../mos6502.h" #include +#include #include #include #include +#include + +bool quiet = false; uint8_t ram[65536] = {0}; @@ -28,7 +32,9 @@ void tick(mos6502*) { static int count = 0; uint16_t pc = cpu->GetPC(); if (pc != lastpc) { - printf("PC=%04x\r", pc); + if (!quiet) { + printf("PC=%04x\r", pc); + } } if (pc == success) { printf("\nsuccess\n"); @@ -121,11 +127,15 @@ void handle_hex(const char *fname) { } int main(int argc, char **argv) { - if (argc != 4) { - fprintf(stderr, "Usage: %s .hex \n", argv[0]); + if (argc != 4 && argc != 5) { + fprintf(stderr, "Usage: %s .hex [quiet]\n", argv[0]); return -1; } + if (argc == 5 && !strcmp(argv[4], "quiet")) { + quiet = true; + } + handle_hex(argv[1]); start = strtoul(argv[2], NULL, 0); From cb4beea2673fe375e9e2f3bce00bf83a7e5ca0e8 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 15:13:14 -0700 Subject: [PATCH 10/33] cleaned up IRQ/NMI handling removed unncessary internal state used more common request/inhibit nomenclature for NMI --- mos6502.cpp | 31 +++++++++++-------------------- mos6502.h | 5 ++--- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index b6c14a7..3562e0a 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -35,10 +35,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) , reset_Y(0x00) , reset_sp(0xFD) , reset_status(CONSTANT) - , irq_handling(false) , irq_line(true) - , nmi_pending(false) - , nmi_handling(false) + , nmi_request(false) + , nmi_inhibit(false) , nmi_line(true) { Write = (BusWrite)w; @@ -411,8 +410,8 @@ void mos6502::NMI(bool line) { // falling edge triggered if (nmi_line == true && line == false) { - if (!nmi_handling) { - nmi_pending = true; + if (!nmi_inhibit) { + nmi_request = true; } } nmi_line = line; @@ -421,11 +420,9 @@ void mos6502::NMI(bool line) void mos6502::Reset() { // do not set or clear irq_line, that's external to us - irq_handling = false; - // do not set or clear nmi_line, that's external to us - nmi_pending = false; - nmi_handling = false; + nmi_request = false; + nmi_inhibit = false; A = reset_A; Y = reset_Y; @@ -492,9 +489,9 @@ void mos6502::Svc_NMI() bool mos6502::CheckInterrupts() { // NMI is edge triggered - if (nmi_pending && !nmi_handling) { - nmi_pending = false; - nmi_handling = true; + if (nmi_request && !nmi_inhibit) { + nmi_request = false; + nmi_inhibit = true; Svc_NMI(); return true; } @@ -502,8 +499,7 @@ bool mos6502::CheckInterrupts() { // check disabled bit if(!IF_INTERRUPT()) { // IRQ is level triggered - if (irq_line == false && !nmi_handling && !irq_handling) { - irq_handling = true; + if (irq_line == false && !nmi_inhibit) { Svc_IRQ(); return true; } @@ -1128,12 +1124,7 @@ void mos6502::Op_RTI(uint16_t src) pc = (hi << 8) | lo; - if (nmi_handling) { - nmi_handling = false; - } - else if (irq_handling) { - irq_handling = false; - } + nmi_inhibit = false; // always, more efficient that if() return; } diff --git a/mos6502.h b/mos6502.h index d5f3068..25eea5c 100644 --- a/mos6502.h +++ b/mos6502.h @@ -55,11 +55,10 @@ class mos6502 bool crossed; - bool irq_handling; // are we currently handling an IRQ? bool irq_line; // current state of the line - bool nmi_pending; // is there an NMI pending? - bool nmi_handling; // are we currently handling an NMI? + bool nmi_request; // is there an NMI pending? + bool nmi_inhibit; // are we currently handling an NMI? bool nmi_line; // current state of the NMI line bool CheckInterrupts(); From e5f431d302004ed10c3403fca1dd7475f71542dd Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 15:46:51 -0700 Subject: [PATCH 11/33] comments describing legal opcodes --- mos6502.cpp | 736 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 694 insertions(+), 42 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index a59bfaf..4b3842b 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -70,190 +70,842 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) instr.penalty = PENALTY; \ InstrTable[HEX] = instr; +// ADC +// Add Memory to Accumulator with Carry +// +// A + M + C -> A, C +// N Z C I D V +// + + + - - + +// addressing assembler opc bytes cycles +// immediate ADC #oper 69 2 2 +// zeropage ADC oper 65 2 3 +// zeropage,X ADC oper,X 75 2 4 +// absolute ADC oper 6D 3 4 +// absolute,X ADC oper,X 7D 3 4* +// absolute,Y ADC oper,Y 79 3 4* +// (indirect,X) ADC (oper,X) 61 2 6 +// (indirect),Y ADC (oper),Y 71 2 5* + MAKE_INSTR(0x69, ADC, IMM, 2, false); - MAKE_INSTR(0x6D, ADC, ABS, 4, false); MAKE_INSTR(0x65, ADC, ZER, 3, false); - MAKE_INSTR(0x61, ADC, INX, 6, false); - MAKE_INSTR(0x71, ADC, INY, 5, true); MAKE_INSTR(0x75, ADC, ZEX, 4, false); + MAKE_INSTR(0x6D, ADC, ABS, 4, false); MAKE_INSTR(0x7D, ADC, ABX, 4, true); MAKE_INSTR(0x79, ADC, ABY, 4, true); + MAKE_INSTR(0x61, ADC, INX, 6, false); + MAKE_INSTR(0x71, ADC, INY, 5, true); + +// AND +// AND Memory with Accumulator +// +// A AND M -> A +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate AND #oper 29 2 2 +// zeropage AND oper 25 2 3 +// zeropage,X AND oper,X 35 2 4 +// absolute AND oper 2D 3 4 +// absolute,X AND oper,X 3D 3 4* +// absolute,Y AND oper,Y 39 3 4* +// (indirect,X) AND (oper,X) 21 2 6 +// (indirect),Y AND (oper),Y 31 2 5* MAKE_INSTR(0x29, AND, IMM, 2, false); - MAKE_INSTR(0x2D, AND, ABS, 4, false); MAKE_INSTR(0x25, AND, ZER, 3, false); - MAKE_INSTR(0x21, AND, INX, 6, false); - MAKE_INSTR(0x31, AND, INY, 5, true); MAKE_INSTR(0x35, AND, ZEX, 4, false); + MAKE_INSTR(0x2D, AND, ABS, 4, false); MAKE_INSTR(0x3D, AND, ABX, 4, true); MAKE_INSTR(0x39, AND, ABY, 4, true); + MAKE_INSTR(0x21, AND, INX, 6, false); + MAKE_INSTR(0x31, AND, INY, 5, true); + +// ASL +// Shift Left One Bit (Memory or Accumulator) +// +// C <- [76543210] <- 0 +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// accumulator ASL A 0A 1 2 +// zeropage ASL oper 06 2 5 +// zeropage,X ASL oper,X 16 2 6 +// absolute ASL oper 0E 3 6 +// absolute,X ASL oper,X 1E 3 7 - MAKE_INSTR(0x0E, ASL, ABS, 6, false); - MAKE_INSTR(0x06, ASL, ZER, 5, false); MAKE_INSTR(0x0A, ASL_ACC, ACC, 2, false); + MAKE_INSTR(0x06, ASL, ZER, 5, false); MAKE_INSTR(0x16, ASL, ZEX, 6, false); + MAKE_INSTR(0x0E, ASL, ABS, 6, false); MAKE_INSTR(0x1E, ASL, ABX, 7, false); +// BCC +// Branch on Carry Clear +// +// branch on C = 0 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BCC oper 90 2 2** + MAKE_INSTR(0x90, BCC, REL, 2, true); + +// BCS +// Branch on Carry Set +// +// branch on C = 1 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BCS oper B0 2 2** + MAKE_INSTR(0xB0, BCS, REL, 2, true); + +// BEQ +// Branch on Result Zero +// +// branch on Z = 1 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BEQ oper F0 2 2** + MAKE_INSTR(0xF0, BEQ, REL, 2, true); - MAKE_INSTR(0x2C, BIT, ABS, 4, false); +// BIT +// Test Bits in Memory with Accumulator +// +// bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V); +// the zero-flag is set according to the result of the operand AND +// the accumulator (set, if the result is zero, unset otherwise). +// This allows a quick check of a few bits at once without affecting +// any of the registers, other than the status register (SR). +// +// → Further details. +// +// A AND M -> Z, M7 -> N, M6 -> V +// N Z C I D V +// M7 + - - - M6 +// addressing assembler opc bytes cycles +// zeropage BIT oper 24 2 3 +// absolute BIT oper 2C 3 4 + MAKE_INSTR(0x24, BIT, ZER, 3, false); + MAKE_INSTR(0x2C, BIT, ABS, 4, false); + +// BMI +// Branch on Result Minus +// +// branch on N = 1 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BMI oper 30 2 2** MAKE_INSTR(0x30, BMI, REL, 2, true); + +// BNE +// Branch on Result not Zero +// +// branch on Z = 0 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BNE oper D0 2 2** + MAKE_INSTR(0xD0, BNE, REL, 2, true); + +// BPL +// Branch on Result Plus +// +// branch on N = 0 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BPL oper 10 2 2** + MAKE_INSTR(0x10, BPL, REL, 2, true); +// BRK +// Force Break +// +// BRK initiates a software interrupt similar to a hardware +// interrupt (IRQ). The return address pushed to the stack is +// PC+2, providing an extra byte of spacing for a break mark +// (identifying a reason for the break.) +// The status register will be pushed to the stack with the break +// flag set to 1. However, when retrieved during RTI or by a PLP +// instruction, the break flag will be ignored. +// The interrupt disable flag is not set automatically. +// +// → Further details. +// +// interrupt, +// push PC+2, push SR +// N Z C I D V +// - - - 1 - - +// addressing assembler opc bytes cycles +// implied BRK 00 1 7 + MAKE_INSTR(0x00, BRK, IMP, 7, false); +// BVC +// Branch on Overflow Clear +// +// branch on V = 0 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BVC oper 50 2 2** + MAKE_INSTR(0x50, BVC, REL, 2, true); + +// BVS +// Branch on Overflow Set +// +// branch on V = 1 +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// relative BVS oper 70 2 2** + MAKE_INSTR(0x70, BVS, REL, 2, true); +// CLC +// Clear Carry Flag +// +// 0 -> C +// N Z C I D V +// - - 0 - - - +// addressing assembler opc bytes cycles +// implied CLC 18 1 2 + MAKE_INSTR(0x18, CLC, IMP, 2, false); + +// CLD +// Clear Decimal Mode +// +// 0 -> D +// N Z C I D V +// - - - - 0 - +// addressing assembler opc bytes cycles +// implied CLD D8 1 2 + MAKE_INSTR(0xD8, CLD, IMP, 2, false); + +// CLI +// Clear Interrupt Disable Bit +// +// 0 -> I +// N Z C I D V +// - - - 0 - - +// addressing assembler opc bytes cycles +// implied CLI 58 1 2 + MAKE_INSTR(0x58, CLI, IMP, 2, false); + +// CLV +// Clear Overflow Flag +// +// 0 -> V +// N Z C I D V +// - - - - - 0 +// addressing assembler opc bytes cycles +// implied CLV B8 1 2 + MAKE_INSTR(0xB8, CLV, IMP, 2, false); +// CMP +// Compare Memory with Accumulator +// +// A - M +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// immediate CMP #oper C9 2 2 +// zeropage CMP oper C5 2 3 +// zeropage,X CMP oper,X D5 2 4 +// absolute CMP oper CD 3 4 +// absolute,X CMP oper,X DD 3 4* +// absolute,Y CMP oper,Y D9 3 4* +// (indirect,X) CMP (oper,X) C1 2 6 +// (indirect),Y CMP (oper),Y D1 2 5* + MAKE_INSTR(0xC9, CMP, IMM, 2, false); - MAKE_INSTR(0xCD, CMP, ABS, 4, false); MAKE_INSTR(0xC5, CMP, ZER, 3, false); - MAKE_INSTR(0xC1, CMP, INX, 6, false); - MAKE_INSTR(0xD1, CMP, INY, 5, true); MAKE_INSTR(0xD5, CMP, ZEX, 4, false); + MAKE_INSTR(0xCD, CMP, ABS, 4, false); MAKE_INSTR(0xDD, CMP, ABX, 4, true); MAKE_INSTR(0xD9, CMP, ABY, 4, true); + MAKE_INSTR(0xC1, CMP, INX, 6, false); + MAKE_INSTR(0xD1, CMP, INY, 5, true); + +// CPX +// Compare Memory and Index X +// +// X - M +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// immediate CPX #oper E0 2 2 +// zeropage CPX oper E4 2 3 +// absolute CPX oper EC 3 4 MAKE_INSTR(0xE0, CPX, IMM, 2, false); - MAKE_INSTR(0xEC, CPX, ABS, 4, false); MAKE_INSTR(0xE4, CPX, ZER, 3, false); + MAKE_INSTR(0xEC, CPX, ABS, 4, false); + +// CPY +// Compare Memory and Index Y +// +// Y - M +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// immediate CPY #oper C0 2 2 +// zeropage CPY oper C4 2 3 +// absolute CPY oper CC 3 4 MAKE_INSTR(0xC0, CPY, IMM, 2, false); - MAKE_INSTR(0xCC, CPY, ABS, 4, false); MAKE_INSTR(0xC4, CPY, ZER, 3, false); + MAKE_INSTR(0xCC, CPY, ABS, 4, false); + +// DEC +// Decrement Memory by One +// +// M - 1 -> M +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// zeropage DEC oper C6 2 5 +// zeropage,X DEC oper,X D6 2 6 +// absolute DEC oper CE 3 6 +// absolute,X DEC oper,X DE 3 7 - MAKE_INSTR(0xCE, DEC, ABS, 6, false); MAKE_INSTR(0xC6, DEC, ZER, 5, false); MAKE_INSTR(0xD6, DEC, ZEX, 6, false); + MAKE_INSTR(0xCE, DEC, ABS, 6, false); MAKE_INSTR(0xDE, DEC, ABX, 7, false); +// DEX +// Decrement Index X by One +// +// X - 1 -> X +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied DEX CA 1 2 + MAKE_INSTR(0xCA, DEX, IMP, 2, false); + +// DEY +// Decrement Index Y by One +// +// Y - 1 -> Y +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied DEY 88 1 2 + MAKE_INSTR(0x88, DEY, IMP, 2, false); +// EOR +// Exclusive-OR Memory with Accumulator +// +// A EOR M -> A +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate EOR #oper 49 2 2 +// zeropage EOR oper 45 2 3 +// zeropage,X EOR oper,X 55 2 4 +// absolute EOR oper 4D 3 4 +// absolute,X EOR oper,X 5D 3 4* +// absolute,Y EOR oper,Y 59 3 4* +// (indirect,X) EOR (oper,X) 41 2 6 +// (indirect),Y EOR (oper),Y 51 2 5* + MAKE_INSTR(0x49, EOR, IMM, 2, false); - MAKE_INSTR(0x4D, EOR, ABS, 4, false); MAKE_INSTR(0x45, EOR, ZER, 3, false); - MAKE_INSTR(0x41, EOR, INX, 6, false); - MAKE_INSTR(0x51, EOR, INY, 5, true); MAKE_INSTR(0x55, EOR, ZEX, 4, false); + MAKE_INSTR(0x4D, EOR, ABS, 4, false); MAKE_INSTR(0x5D, EOR, ABX, 4, true); MAKE_INSTR(0x59, EOR, ABY, 4, true); + MAKE_INSTR(0x41, EOR, INX, 6, false); + MAKE_INSTR(0x51, EOR, INY, 5, true); + +// INC +// Increment Memory by One +// +// M + 1 -> M +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// zeropage INC oper E6 2 5 +// zeropage,X INC oper,X F6 2 6 +// absolute INC oper EE 3 6 +// absolute,X INC oper,X FE 3 7 - MAKE_INSTR(0xEE, INC, ABS, 6, false); MAKE_INSTR(0xE6, INC, ZER, 5, false); MAKE_INSTR(0xF6, INC, ZEX, 6, false); + MAKE_INSTR(0xEE, INC, ABS, 6, false); MAKE_INSTR(0xFE, INC, ABX, 7, false); +// INX +// Increment Index X by One +// +// X + 1 -> X +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied INX E8 1 2 + MAKE_INSTR(0xE8, INX, IMP, 2, false); + +// INY +// Increment Index Y by One +// +// Y + 1 -> Y +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied INY C8 1 2 + MAKE_INSTR(0xC8, INY, IMP, 2, false); +// JMP +// Jump to New Location +// +// operand 1st byte -> PCL +// operand 2nd byte -> PCH +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// absolute JMP oper 4C 3 3 +// indirect JMP (oper) 6C 3 5 + MAKE_INSTR(0x4C, JMP, ABS, 3, false); MAKE_INSTR(0x6C, JMP, ABI, 5, false); +// JSR +// Jump to New Location Saving Return Address +// +// push (PC+2), +// operand 1st byte -> PCL +// operand 2nd byte -> PCH +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// absolute JSR oper 20 3 6 + MAKE_INSTR(0x20, JSR, ABS, 6, false); +// LDA +// Load Accumulator with Memory +// +// M -> A +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate LDA #oper A9 2 2 +// zeropage LDA oper A5 2 3 +// zeropage,X LDA oper,X B5 2 4 +// absolute LDA oper AD 3 4 +// absolute,X LDA oper,X BD 3 4* +// absolute,Y LDA oper,Y B9 3 4* +// (indirect,X) LDA (oper,X) A1 2 6 +// (indirect),Y LDA (oper),Y B1 2 5* + MAKE_INSTR(0xA9, LDA, IMM, 2, false); - MAKE_INSTR(0xAD, LDA, ABS, 4, false); MAKE_INSTR(0xA5, LDA, ZER, 3, false); - MAKE_INSTR(0xA1, LDA, INX, 6, false); - MAKE_INSTR(0xB1, LDA, INY, 5, true); MAKE_INSTR(0xB5, LDA, ZEX, 4, false); + MAKE_INSTR(0xAD, LDA, ABS, 4, false); MAKE_INSTR(0xBD, LDA, ABX, 4, true); MAKE_INSTR(0xB9, LDA, ABY, 4, true); + MAKE_INSTR(0xA1, LDA, INX, 6, false); + MAKE_INSTR(0xB1, LDA, INY, 5, true); + +// LDX +// Load Index X with Memory +// +// M -> X +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate LDX #oper A2 2 2 +// zeropage LDX oper A6 2 3 +// zeropage,Y LDX oper,Y B6 2 4 +// absolute LDX oper AE 3 4 +// absolute,Y LDX oper,Y BE 3 4* MAKE_INSTR(0xA2, LDX, IMM, 2, false); - MAKE_INSTR(0xAE, LDX, ABS, 4, false); MAKE_INSTR(0xA6, LDX, ZER, 3, false); - MAKE_INSTR(0xBE, LDX, ABY, 4, true); MAKE_INSTR(0xB6, LDX, ZEY, 4, false); + MAKE_INSTR(0xAE, LDX, ABS, 4, false); + MAKE_INSTR(0xBE, LDX, ABY, 4, true); + +// LDY +// Load Index Y with Memory +// +// M -> Y +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate LDY #oper A0 2 2 +// zeropage LDY oper A4 2 3 +// zeropage,X LDY oper,X B4 2 4 +// absolute LDY oper AC 3 4 +// absolute,X LDY oper,X BC 3 4* MAKE_INSTR(0xA0, LDY, IMM, 2, false); - MAKE_INSTR(0xAC, LDY, ABS, 4, false); MAKE_INSTR(0xA4, LDY, ZER, 3, false); MAKE_INSTR(0xB4, LDY, ZEX, 4, false); + MAKE_INSTR(0xAC, LDY, ABS, 4, false); MAKE_INSTR(0xBC, LDY, ABX, 4, true); - MAKE_INSTR(0x4E, LSR, ABS, 6, false); - MAKE_INSTR(0x46, LSR, ZER, 5, false); +// LSR +// Shift One Bit Right (Memory or Accumulator) +// +// 0 -> [76543210] -> C +// N Z C I D V +// 0 + + - - - +// addressing assembler opc bytes cycles +// accumulator LSR A 4A 1 2 +// zeropage LSR oper 46 2 5 +// zeropage,X LSR oper,X 56 2 6 +// absolute LSR oper 4E 3 6 +// absolute,X LSR oper,X 5E 3 7 + MAKE_INSTR(0x4A, LSR_ACC, ACC, 2, false); + MAKE_INSTR(0x46, LSR, ZER, 5, false); MAKE_INSTR(0x56, LSR, ZEX, 6, false); + MAKE_INSTR(0x4E, LSR, ABS, 6, false); MAKE_INSTR(0x5E, LSR, ABX, 7, false); +// NOP +// No Operation +// +// --- +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// implied NOP EA 1 2 + MAKE_INSTR(0xEA, NOP, IMP, 2, false); +// ORA +// OR Memory with Accumulator +// +// A OR M -> A +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate ORA #oper 09 2 2 +// zeropage ORA oper 05 2 3 +// zeropage,X ORA oper,X 15 2 4 +// absolute ORA oper 0D 3 4 +// absolute,X ORA oper,X 1D 3 4* +// absolute,Y ORA oper,Y 19 3 4* +// (indirect,X) ORA (oper,X) 01 2 6 +// (indirect),Y ORA (oper),Y 11 2 5* + MAKE_INSTR(0x09, ORA, IMM, 2, false); - MAKE_INSTR(0x0D, ORA, ABS, 4, false); MAKE_INSTR(0x05, ORA, ZER, 3, false); - MAKE_INSTR(0x01, ORA, INX, 6, false); - MAKE_INSTR(0x11, ORA, INY, 5, true); MAKE_INSTR(0x15, ORA, ZEX, 4, false); + MAKE_INSTR(0x0D, ORA, ABS, 4, false); MAKE_INSTR(0x1D, ORA, ABX, 4, true); MAKE_INSTR(0x19, ORA, ABY, 4, true); + MAKE_INSTR(0x01, ORA, INX, 6, false); + MAKE_INSTR(0x11, ORA, INY, 5, true); + +// PHA +// Push Accumulator on Stack +// +// push A +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// implied PHA 48 1 3 MAKE_INSTR(0x48, PHA, IMP, 3, false); + +// PHP +// Push Processor Status on Stack +// +// The status register will be pushed with the break +// flag and bit 5 set to 1. +// +// push SR +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// implied PHP 08 1 3 + MAKE_INSTR(0x08, PHP, IMP, 3, false); + +// PLA +// Pull Accumulator from Stack +// +// pull A +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied PLA 68 1 4 + MAKE_INSTR(0x68, PLA, IMP, 4, false); + +// PLP +// Pull Processor Status from Stack +// +// The status register will be pulled with the break +// flag and bit 5 ignored. +// +// pull SR +// N Z C I D V +// from stack +// addressing assembler opc bytes cycles +// implied PLP 28 1 4 + MAKE_INSTR(0x28, PLP, IMP, 4, false); - MAKE_INSTR(0x2E, ROL, ABS, 6, false); - MAKE_INSTR(0x26, ROL, ZER, 5, false); +// ROL +// Rotate One Bit Left (Memory or Accumulator) +// +// C <- [76543210] <- C +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// accumulator ROL A 2A 1 2 +// zeropage ROL oper 26 2 5 +// zeropage,X ROL oper,X 36 2 6 +// absolute ROL oper 2E 3 6 +// absolute,X ROL oper,X 3E 3 7 + MAKE_INSTR(0x2A, ROL_ACC, ACC, 2, false); + MAKE_INSTR(0x26, ROL, ZER, 5, false); MAKE_INSTR(0x36, ROL, ZEX, 6, false); + MAKE_INSTR(0x2E, ROL, ABS, 6, false); MAKE_INSTR(0x3E, ROL, ABX, 7, false); - MAKE_INSTR(0x6E, ROR, ABS, 6, false); - MAKE_INSTR(0x66, ROR, ZER, 5, false); +// ROR +// Rotate One Bit Right (Memory or Accumulator) +// +// C -> [76543210] -> C +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// accumulator ROR A 6A 1 2 +// zeropage ROR oper 66 2 5 +// zeropage,X ROR oper,X 76 2 6 +// absolute ROR oper 6E 3 6 +// absolute,X ROR oper,X 7E 3 7 + MAKE_INSTR(0x6A, ROR_ACC, ACC, 2, false); + MAKE_INSTR(0x66, ROR, ZER, 5, false); MAKE_INSTR(0x76, ROR, ZEX, 6, false); + MAKE_INSTR(0x6E, ROR, ABS, 6, false); MAKE_INSTR(0x7E, ROR, ABX, 7, false); +// RTI +// Return from Interrupt +// +// The status register is pulled with the break flag +// and bit 5 ignored. Then PC is pulled from the stack. +// +// pull SR, pull PC +// N Z C I D V +// from stack +// addressing assembler opc bytes cycles +// implied RTI 40 1 6 + MAKE_INSTR(0x40, RTI, IMP, 6, false); + +// RTS +// Return from Subroutine +// +// pull PC, PC+1 -> PC +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// implied RTS 60 1 6 + MAKE_INSTR(0x60, RTS, IMP, 6, false); +// SBC +// Subtract Memory from Accumulator with Borrow +// +// A - M - C̅ -> A +// N Z C I D V +// + + + - - + +// addressing assembler opc bytes cycles +// immediate SBC #oper E9 2 2 +// zeropage SBC oper E5 2 3 +// zeropage,X SBC oper,X F5 2 4 +// absolute SBC oper ED 3 4 +// absolute,X SBC oper,X FD 3 4* +// absolute,Y SBC oper,Y F9 3 4* +// (indirect,X) SBC (oper,X) E1 2 6 +// (indirect),Y SBC (oper),Y F1 2 5* + MAKE_INSTR(0xE9, SBC, IMM, 2, false); - MAKE_INSTR(0xED, SBC, ABS, 4, false); MAKE_INSTR(0xE5, SBC, ZER, 3, false); - MAKE_INSTR(0xE1, SBC, INX, 6, false); - MAKE_INSTR(0xF1, SBC, INY, 5, true); MAKE_INSTR(0xF5, SBC, ZEX, 4, false); + MAKE_INSTR(0xED, SBC, ABS, 4, false); MAKE_INSTR(0xFD, SBC, ABX, 4, true); MAKE_INSTR(0xF9, SBC, ABY, 4, true); + MAKE_INSTR(0xE1, SBC, INX, 6, false); + MAKE_INSTR(0xF1, SBC, INY, 5, true); + +// SEC +// Set Carry Flag +// +// 1 -> C +// N Z C I D V +// - - 1 - - - +// addressing assembler opc bytes cycles +// implied SEC 38 1 2 MAKE_INSTR(0x38, SEC, IMP, 2, false); + +// SED +// Set Decimal Flag +// +// 1 -> D +// N Z C I D V +// - - - - 1 - +// addressing assembler opc bytes cycles +// implied SED F8 1 2 + MAKE_INSTR(0xF8, SED, IMP, 2, false); + +// SEI +// Set Interrupt Disable Status +// +// 1 -> I +// N Z C I D V +// - - - 1 - - +// addressing assembler opc bytes cycles +// implied SEI 78 1 2 + MAKE_INSTR(0x78, SEI, IMP, 2, false); - MAKE_INSTR(0x8D, STA, ABS, 4, false); +// STA +// Store Accumulator in Memory +// +// A -> M +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// zeropage STA oper 85 2 3 +// zeropage,X STA oper,X 95 2 4 +// absolute STA oper 8D 3 4 +// absolute,X STA oper,X 9D 3 5 +// absolute,Y STA oper,Y 99 3 5 +// (indirect,X) STA (oper,X) 81 2 6 +// (indirect),Y STA (oper),Y 91 2 6 + MAKE_INSTR(0x85, STA, ZER, 3, false); - MAKE_INSTR(0x81, STA, INX, 6, false); - MAKE_INSTR(0x91, STA, INY, 6, false); MAKE_INSTR(0x95, STA, ZEX, 4, false); + MAKE_INSTR(0x8D, STA, ABS, 4, false); MAKE_INSTR(0x9D, STA, ABX, 5, false); MAKE_INSTR(0x99, STA, ABY, 5, false); + MAKE_INSTR(0x81, STA, INX, 6, false); + MAKE_INSTR(0x91, STA, INY, 6, false); + +// STX +// Store Index X in Memory +// +// X -> M +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// zeropage STX oper 86 2 3 +// zeropage,Y STX oper,Y 96 2 4 +// absolute STX oper 8E 3 4 - MAKE_INSTR(0x8E, STX, ABS, 4, false); MAKE_INSTR(0x86, STX, ZER, 3, false); MAKE_INSTR(0x96, STX, ZEY, 4, false); + MAKE_INSTR(0x8E, STX, ABS, 4, false); + +// STY +// Sore Index Y in Memory +// +// Y -> M +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// zeropage STY oper 84 2 3 +// zeropage,X STY oper,X 94 2 4 +// absolute STY oper 8C 3 4 - MAKE_INSTR(0x8C, STY, ABS, 4, false); MAKE_INSTR(0x84, STY, ZER, 3, false); MAKE_INSTR(0x94, STY, ZEX, 4, false); + MAKE_INSTR(0x8C, STY, ABS, 4, false); + +// TAX +// Transfer Accumulator to Index X +// +// A -> X +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied TAX AA 1 2 MAKE_INSTR(0xAA, TAX, IMP, 2, false); + +// TAY +// Transfer Accumulator to Index Y +// +// A -> Y +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied TAY A8 1 2 + MAKE_INSTR(0xA8, TAY, IMP, 2, false); + +// TSX +// Transfer Stack Pointer to Index X +// +// SP -> X +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied TSX BA 1 2 + MAKE_INSTR(0xBA, TSX, IMP, 2, false); + +// TXA +// Transfer Index X to Accumulator +// +// X -> A +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied TXA 8A 1 2 + MAKE_INSTR(0x8A, TXA, IMP, 2, false); + +// TXS +// Transfer Index X to Stack Register +// +// X -> SP +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// implied TXS 9A 1 2 + MAKE_INSTR(0x9A, TXS, IMP, 2, false); + +// TYA +// Transfer Index Y to Accumulator +// +// Y -> A +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// implied TYA 98 1 2 + MAKE_INSTR(0x98, TYA, IMP, 2, false); return; From 87319ad8d57eb7d41b544fcf10bd320e4a4f4d94 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 15:57:19 -0700 Subject: [PATCH 12/33] comments for ilegal instructions --- mos6502.cpp | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 4b3842b..f0404c7 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -908,6 +908,337 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) MAKE_INSTR(0x98, TYA, IMP, 2, false); +#ifdef ILLEGAL_OPCODES +// ALR (ASR) +// AND oper + LSR +// +// A AND oper, 0 -> [76543210] -> C +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// immediate ALR #oper 4B 2 2 + +// ANC +// AND oper + set C as ASL +// +// A AND oper, bit(7) -> C +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// immediate ANC #oper 0B 2 2 + +// ANC (ANC2) +// AND oper + set C as ROL +// +// effectively the same as instr. 0B +// +// A AND oper, bit(7) -> C +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// immediate ANC #oper 2B 2 2 + +// ANE (XAA) +// * OR X + AND oper +// +// Highly unstable, do not use. +// +// A base value in A is determined based on the contets of A and a constant, +// which may be typically $00, $ff, $ee, etc. The value of this constant +// depends on temperature, the chip series, and maybe other factors, as well. +// In order to eliminate these uncertaincies from the equation, use either 0 +// as the operand or a value of $FF in the accumulator. +// +// (A OR CONST) AND X AND oper -> A +// +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate ANE #oper 8B 2 2 †† + +// ARR +// AND oper + ROR +// +// This operation involves the adder: +// V-flag is set according to (A AND oper) + oper +// The carry is not set, but bit 7 (sign) is exchanged with the carry +// +// A AND oper, C -> [76543210] -> C +// +// N Z C I D V +// + + + - - + +// addressing assembler opc bytes cycles +// immediate ARR #oper 6B 2 2 + +// DCP (DCM) +// DEC oper + CMP oper +// +// M - 1 -> M, A - M +// +// Decrements the operand and then compares the result to the accumulator. +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// zeropage DCP oper C7 2 5 +// zeropage,X DCP oper,X D7 2 6 +// absolute DCP oper CF 3 6 +// absolute,X DCP oper,X DF 3 7 +// absolute,Y DCP oper,Y DB 3 7 +// (indirect,X) DCP (oper,X) C3 2 8 +// (indirect),Y DCP (oper),Y D3 2 8 + +// ISC (ISB, INS) +// INC oper + SBC oper +// +// M + 1 -> M, A - M - C̅ -> A +// +// N Z C I D V +// + + + - - + +// addressing assembler opc bytes cycles +// zeropage ISC oper E7 2 5 +// zeropage,X ISC oper,X F7 2 6 +// absolute ISC oper EF 3 6 +// absolute,X ISC oper,X FF 3 7 +// absolute,Y ISC oper,Y FB 3 7 +// (indirect,X) ISC (oper,X) E3 2 8 +// (indirect),Y ISC (oper),Y F3 2 8 + +// LAS (LAR) +// LDA/TSX oper +// +// M AND SP -> A, X, SP +// +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// absolute,Y LAS oper,Y BB 3 4* + +// LAX +// LDA oper + LDX oper +// +// M -> A -> X +// +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// zeropage LAX oper A7 2 3 +// zeropage,Y LAX oper,Y B7 2 4 +// absolute LAX oper AF 3 4 +// absolute,Y LAX oper,Y BF 3 4* +// (indirect,X) LAX (oper,X) A3 2 6 +// (indirect),Y LAX (oper),Y B3 2 5* + +// LXA (LAX immediate) +// Store * AND oper in A and X +// +// Highly unstable, involves a 'magic' constant, see ANE +// +// (A OR CONST) AND oper -> A -> X +// +// N Z C I D V +// + + - - - - +// addressing assembler opc bytes cycles +// immediate LXA #oper AB 2 2 †† + +// RLA +// ROL oper + AND oper +// +// M = C <- [76543210] <- C, A AND M -> A +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// zeropage RLA oper 27 2 5 +// zeropage,X RLA oper,X 37 2 6 +// absolute RLA oper 2F 3 6 +// absolute,X RLA oper,X 3F 3 7 +// absolute,Y RLA oper,Y 3B 3 7 +// (indirect,X) RLA (oper,X) 23 2 8 +// (indirect),Y RLA (oper),Y 33 2 8 + +// RRA +// ROR oper + ADC oper +// +// M = C -> [76543210] -> C, A + M + C -> A, C +// +// N Z C I D V +// + + + - - + +// addressing assembler opc bytes cycles +// zeropage RRA oper 67 2 5 +// zeropage,X RRA oper,X 77 2 6 +// absolute RRA oper 6F 3 6 +// absolute,X RRA oper,X 7F 3 7 +// absolute,Y RRA oper,Y 7B 3 7 +// (indirect,X) RRA (oper,X) 63 2 8 +// (indirect),Y RRA (oper),Y 73 2 8 + +// SAX (AXS, AAX) +// A and X are put on the bus at the same time (resulting effectively in an AND operation) and stored in M +// +// A AND X -> M +// +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// zeropage SAX oper 87 2 3 +// zeropage,Y SAX oper,Y 97 2 4 +// absolute SAX oper 8F 3 4 +// (indirect,X) SAX (oper,X) 83 2 6 + +// SBX (AXS, SAX) +// CMP and DEX at once, sets flags like CMP +// +// (A AND X) - oper -> X +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// immediate SBX #oper CB 2 2 + +// SHA (AHX, AXA) +// Stores A AND X AND (high-byte of addr. + 1) at addr. +// +// unstable: sometimes 'AND (H+1)' is dropped, page boundary crossings +// may not work (with the high-byte of the value used as the high-byte of the address) +// +// A AND X AND (H+1) -> M +// +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// absolute,Y SHA oper,Y 9F 3 5 † +// (indirect),Y SHA (oper),Y 93 2 6 † + +// SHX (A11, SXA, XAS) +// Stores X AND (high-byte of addr. + 1) at addr. +// +// unstable: sometimes 'AND (H+1)' is dropped, page boundary +// crossings may not work (with the high-byte of the value used as the high-byte of the address) +// +// X AND (H+1) -> M +// +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// absolute,Y SHX oper,Y 9E 3 5 † + +// SHY (A11, SYA, SAY) +// Stores Y AND (high-byte of addr. + 1) at addr. +// +// unstable: sometimes 'AND (H+1)' is dropped, page boundary +// crossings may not work (with the high-byte of the value used as the high-byte of the address) +// +// Y AND (H+1) -> M +// +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// absolute,X SHY oper,X 9C 3 5 † + +// SLO (ASO) +// ASL oper + ORA oper +// +// M = C <- [76543210] <- 0, A OR M -> A +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// zeropage SLO oper 07 2 5 +// zeropage,X SLO oper,X 17 2 6 +// absolute SLO oper 0F 3 6 +// absolute,X SLO oper,X 1F 3 7 +// absolute,Y SLO oper,Y 1B 3 7 +// (indirect,X) SLO (oper,X) 03 2 8 +// (indirect),Y SLO (oper),Y 13 2 8 + +// SRE (LSE) +// LSR oper + EOR oper +// +// M = 0 -> [76543210] -> C, A EOR M -> A +// +// N Z C I D V +// + + + - - - +// addressing assembler opc bytes cycles +// zeropage SRE oper 47 2 5 +// zeropage,X SRE oper,X 57 2 6 +// absolute SRE oper 4F 3 6 +// absolute,X SRE oper,X 5F 3 7 +// absolute,Y SRE oper,Y 5B 3 7 +// (indirect,X) SRE (oper,X) 43 2 8 +// (indirect),Y SRE (oper),Y 53 2 8 + +// TAS (XAS, SHS) +// Puts A AND X in SP and stores A AND X AND (high-byte of addr. + 1) at addr. +// +// unstable: sometimes 'AND (H+1)' is dropped, page boundary +// crossings may not work (with the high-byte of the value used as the high-byte of the address) +// +// A AND X -> SP, A AND X AND (H+1) -> M +// +// N Z C I D V +// - - - - - - +// addressing assembler opc bytes cycles +// absolute,Y TAS oper,Y 9B 3 5 † + +// USBC (SBC) +// SBC oper + NOP +// +// effectively same as normal SBC immediate, instr. E9. +// +// A - M - C̅ -> A +// +// N Z C I D V +// + + + - - + +// addressing assembler opc bytes cycles +// immediate USBC #oper EB 2 2 + +// NOPs (including DOP, TOP) +// Instructions effecting in 'no operations' in various address modes. Operands are ignored. +// +// N Z C I D V +// - - - - - - +// opc addressing bytes cycles +// 1A implied 1 2 +// 3A implied 1 2 +// 5A implied 1 2 +// 7A implied 1 2 +// DA implied 1 2 +// FA implied 1 2 +// 80 immediate 2 2 +// 82 immediate 2 2 +// 89 immediate 2 2 +// C2 immediate 2 2 +// E2 immediate 2 2 +// 04 zeropage 2 3 +// 44 zeropage 2 3 +// 64 zeropage 2 3 +// 14 zeropage,X 2 4 +// 34 zeropage,X 2 4 +// 54 zeropage,X 2 4 +// 74 zeropage,X 2 4 +// D4 zeropage,X 2 4 +// F4 zeropage,X 2 4 +// 0C absolute 3 4 +// 1C absolute,X 3 4* +// 3C absolute,X 3 4* +// 5C absolute,X 3 4* +// 7C absolute,X 3 4* +// DC absolute,X 3 4* +// FC absolute,X 3 4* + +// JAM (KIL, HLT) +// These instructions freeze the CPU. +// +// The processor will be trapped infinitely in T1 phase with $FF on the data bus. — Reset required. +// +// Instruction codes: 02, 12, 22, 32, 42, 52, 62, 72, 92, B2, D2, F2 + +#endif + return; } From debd89e282fa36b1b3f6c3b812881ff255afffd6 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 16:05:42 -0700 Subject: [PATCH 13/33] NOP and JAM --- mos6502.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index f0404c7..8979a19 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -55,6 +55,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) instr.code = &mos6502::Op_ILLEGAL; instr.scode = "(null)"; instr.penalty = false; + instr.cycles = 0; for(int i = 0; i < 256; i++) { InstrTable[i] = instr; @@ -1208,21 +1209,52 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // 7A implied 1 2 // DA implied 1 2 // FA implied 1 2 + + MAKE_INSTR(0x1A, NOP, IMP, 2, false); + MAKE_INSTR(0x3A, NOP, IMP, 2, false); + MAKE_INSTR(0x5A, NOP, IMP, 2, false); + MAKE_INSTR(0x7A, NOP, IMP, 2, false); + MAKE_INSTR(0xDA, NOP, IMP, 2, false); + MAKE_INSTR(0xFA, NOP, IMP, 2, false); + // 80 immediate 2 2 // 82 immediate 2 2 // 89 immediate 2 2 // C2 immediate 2 2 // E2 immediate 2 2 + + MAKE_INSTR(0x80, NOP, IMM, 2, false); + MAKE_INSTR(0x82, NOP, IMM, 2, false); + MAKE_INSTR(0x89, NOP, IMM, 2, false); + MAKE_INSTR(0xC2, NOP, IMM, 2, false); + MAKE_INSTR(0xE2, NOP, IMM, 2, false); + // 04 zeropage 2 3 // 44 zeropage 2 3 // 64 zeropage 2 3 + + MAKE_INSTR(0x04, NOP, ZER, 3, false); + MAKE_INSTR(0x44, NOP, ZER, 3, false); + MAKE_INSTR(0x64, NOP, ZER, 3, false); + // 14 zeropage,X 2 4 // 34 zeropage,X 2 4 // 54 zeropage,X 2 4 // 74 zeropage,X 2 4 // D4 zeropage,X 2 4 // F4 zeropage,X 2 4 + + MAKE_INSTR(0x14, NOP, ZEX, 4, false); + MAKE_INSTR(0x34, NOP, ZEX, 4, false); + MAKE_INSTR(0x54, NOP, ZEX, 4, false); + MAKE_INSTR(0x74, NOP, ZEX, 4, false); + MAKE_INSTR(0xD4, NOP, ZEX, 4, false); + MAKE_INSTR(0xF4, NOP, ZEX, 4, false); + // 0C absolute 3 4 + + MAKE_INSTR(0x0C, NOP, ABS, 4, false); + // 1C absolute,X 3 4* // 3C absolute,X 3 4* // 5C absolute,X 3 4* @@ -1230,6 +1262,13 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // DC absolute,X 3 4* // FC absolute,X 3 4* + MAKE_INSTR(0x1C, NOP, ABX, 4, true); + MAKE_INSTR(0x3C, NOP, ABX, 4, true); + MAKE_INSTR(0x5C, NOP, ABX, 4, true); + MAKE_INSTR(0x7C, NOP, ABX, 4, true); + MAKE_INSTR(0xDC, NOP, ABX, 4, true); + MAKE_INSTR(0xFC, NOP, ABX, 4, true); + // JAM (KIL, HLT) // These instructions freeze the CPU. // @@ -1237,6 +1276,19 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // // Instruction codes: 02, 12, 22, 32, 42, 52, 62, 72, 92, B2, D2, F2 + MAKE_INSTR(0x02, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x12, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x22, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x32, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x42, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x52, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x62, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x72, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0x92, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0xB2, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0xD2, ILLEGAL, IMP, 0, false); + MAKE_INSTR(0xF2, ILLEGAL, IMP, 0, false); + #endif return; From b047c97a85e4dcaa7553f0af5d3e9b1e2b7dff48 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 16:16:44 -0700 Subject: [PATCH 14/33] low progress --- mos6502.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 8979a19..411e076 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -910,6 +910,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) MAKE_INSTR(0x98, TYA, IMP, 2, false); #ifdef ILLEGAL_OPCODES + // ALR (ASR) // AND oper + LSR // @@ -1197,6 +1198,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate USBC #oper EB 2 2 + MAKE_INSTR(0xEB, SBC, IMM, 2, false); + // NOPs (including DOP, TOP) // Instructions effecting in 'no operations' in various address modes. Operands are ignored. // From be67a7a75ccd855d7fa110caf7b9676758d1a984 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 16:41:24 -0700 Subject: [PATCH 15/33] Op_ALR --- mos6502.cpp | 19 +++++++++++++++++++ mos6502.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 411e076..b231bad 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -921,6 +921,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate ALR #oper 4B 2 2 + MAKE_INSTR(0x4B, ALR, IMM, 2, false); + // ANC // AND oper + set C as ASL // @@ -2321,3 +2323,20 @@ void mos6502::Op_TYA(uint16_t src) A = m; return; } + +#ifdef ILLEGAL_OPCODES + +void mos6502::Op_ALR(uint16_t src) +{ + uint8_t m = Read(src); + uint8_t res = m & A; + SET_CARRY(res & 1); + res >>= 1; + SET_NEGATIVE(res & 0x80); + SET_ZERO(!res); + A = res; + return; + fnord +} + +#endif diff --git a/mos6502.h b/mos6502.h index b48a29b..2c967c8 100644 --- a/mos6502.h +++ b/mos6502.h @@ -146,6 +146,10 @@ class mos6502 void Op_TXS(uint16_t src); void Op_TYA(uint16_t src); +#ifdef ILLEGAL_OPCODES + void Op_ALR(uint16_t src); +#endif + void Op_ILLEGAL(uint16_t src); void Svc_NMI(); From c0434a287925caedab08fd24dfb24338cd5a5248 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 16:45:00 -0700 Subject: [PATCH 16/33] Op_ANC --- mos6502.cpp | 16 +++++++++++++++- mos6502.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/mos6502.cpp b/mos6502.cpp index b231bad..d31ac2b 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -933,6 +933,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate ANC #oper 0B 2 2 + MAKE_INSTR(0x0B, ANC, IMM, 2, false); + // ANC (ANC2) // AND oper + set C as ROL // @@ -945,6 +947,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate ANC #oper 2B 2 2 + MAKE_INSTR(0x2B, ANC, IMM, 2, false); + // ANE (XAA) // * OR X + AND oper // @@ -2336,7 +2340,17 @@ void mos6502::Op_ALR(uint16_t src) SET_ZERO(!res); A = res; return; - fnord +} + +void mos6502::Op_ANC(uint16_t src) +{ + uint8_t m = Read(src); + uint8_t res = m & A; + SET_CARRY(res & 0x80); + SET_NEGATIVE(res & 0x80); + SET_ZERO(!res); + A = res; + return; } #endif diff --git a/mos6502.h b/mos6502.h index 2c967c8..391d6f8 100644 --- a/mos6502.h +++ b/mos6502.h @@ -148,6 +148,7 @@ class mos6502 #ifdef ILLEGAL_OPCODES void Op_ALR(uint16_t src); + void Op_ANC(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From ae651c26259ff84a8e876430f356bb6cdcace747 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 16:51:04 -0700 Subject: [PATCH 17/33] Op_ANE --- mos6502.cpp | 17 +++++++++++++++++ mos6502.h | 1 + 2 files changed, 18 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index d31ac2b..ac7dd60 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -967,6 +967,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate ANE #oper 8B 2 2 †† + MAKE_INSTR(0x8B, ANE, IMM, 2, false); + // ARR // AND oper + ROR // @@ -2353,4 +2355,19 @@ void mos6502::Op_ANC(uint16_t src) return; } +void mos6502::Op_ANE(uint16_t src) +{ +// A base value in A is determined based on the contets of A and a constant, +// which may be typically $00, $ff, $ee, etc. The value of this constant +// depends on temperature, the chip series, and maybe other factors, as well. + const uint8_t constant = 0xee; + + uint8_t m = Read(src); + uint8_t res = ((A | constant) & X & m); + SET_NEGATIVE(res & 0x80); + SET_ZERO(!res); + A = res; + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 391d6f8..076ac3a 100644 --- a/mos6502.h +++ b/mos6502.h @@ -149,6 +149,7 @@ class mos6502 #ifdef ILLEGAL_OPCODES void Op_ALR(uint16_t src); void Op_ANC(uint16_t src); + void Op_ANE(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 06dcbdcf496c677ea60865ef6c47e2d6da944906 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 17:09:03 -0700 Subject: [PATCH 18/33] Op_ARR --- mos6502.cpp | 28 ++++++++++++++++++++++++++++ mos6502.h | 1 + 2 files changed, 29 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index ac7dd60..5983dab 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -983,6 +983,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate ARR #oper 6B 2 2 + MAKE_INSTR(0x6B, ARR, IMM, 2, false); + // DCP (DCM) // DEC oper + CMP oper // @@ -2370,4 +2372,30 @@ void mos6502::Op_ANE(uint16_t src) return; } +void mos6502::Op_ARR(uint16_t src) +{ + bool carry = IF_CARRY(); + uint8_t m = Read(src); + uint8_t res = m & A; + SET_CARRY(res & 1); + res >>= 1; + if (carry) { + res |= 0x80; + } + SET_NEGATIVE(res & 0x80); + SET_ZERO(!res); + + if (IF_DECIMAL()) + { + // ARR in decimal mode routes signals through the ALU’s decimal + // adder path, but with no valid carry-in, so the outputs are + // garbage. It’s not emulatable in a meaningful way. + } + + SET_OVERFLOW(((A ^ res) & 0x40) != 0); + + A = res; + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 076ac3a..48ce869 100644 --- a/mos6502.h +++ b/mos6502.h @@ -150,6 +150,7 @@ class mos6502 void Op_ALR(uint16_t src); void Op_ANC(uint16_t src); void Op_ANE(uint16_t src); + void Op_ARR(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From c7cb2fdb60f64ba60d2f61be933aa0d6b908cabd Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 17:15:59 -0700 Subject: [PATCH 19/33] Op_DCP --- mos6502.cpp | 21 +++++++++++++++++++++ mos6502.h | 1 + 2 files changed, 22 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 5983dab..5f57f4b 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1003,6 +1003,14 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // (indirect,X) DCP (oper,X) C3 2 8 // (indirect),Y DCP (oper),Y D3 2 8 + MAKE_INSTR(0xC7, DCP, ZER, 5, false); + MAKE_INSTR(0xD7, DCP, ZEX, 6, false); + MAKE_INSTR(0xCF, DCP, ABS, 6, false); + MAKE_INSTR(0xDF, DCP, ABX, 7, false); + MAKE_INSTR(0xDB, DCP, ABY, 7, false); + MAKE_INSTR(0xC3, DCP, INX, 8, false); + MAKE_INSTR(0xD3, DCP, INY, 8, false); + // ISC (ISB, INS) // INC oper + SBC oper // @@ -2398,4 +2406,17 @@ void mos6502::Op_ARR(uint16_t src) return; } +void mos6502::Op_DCP(uint16_t src) +{ + uint8_t m = Read(src); + m = (m - 1) & 0xFF; + Write(src, m); + + unsigned int tmp = A - m; + SET_CARRY(tmp < 0x100); + SET_NEGATIVE(tmp & 0x80); + SET_ZERO(!(tmp & 0xFF)); + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 48ce869..7ad4d75 100644 --- a/mos6502.h +++ b/mos6502.h @@ -151,6 +151,7 @@ class mos6502 void Op_ANC(uint16_t src); void Op_ANE(uint16_t src); void Op_ARR(uint16_t src); + void Op_DCP(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 8357833026a5504c0ab0725af04456c34467ab6c Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 17:24:23 -0700 Subject: [PATCH 20/33] Op_ISC --- mos6502.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ mos6502.h | 1 + 2 files changed, 43 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 5f57f4b..fb00f78 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1027,6 +1027,14 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // (indirect,X) ISC (oper,X) E3 2 8 // (indirect),Y ISC (oper),Y F3 2 8 + MAKE_INSTR(0xE7, ISC, ZER, 5, false); + MAKE_INSTR(0xF7, ISC, ZEX, 6, false); + MAKE_INSTR(0xEF, ISC, ABS, 6, false); + MAKE_INSTR(0xFF, ISC, ABX, 7, false); + MAKE_INSTR(0xFB, ISC, ABY, 7, false); + MAKE_INSTR(0xE3, ISC, INX, 8, false); + MAKE_INSTR(0xF3, ISC, INY, 8, false); + // LAS (LAR) // LDA/TSX oper // @@ -2419,4 +2427,38 @@ void mos6502::Op_DCP(uint16_t src) return; } +void mos6502::Op_ISC(uint16_t src) +{ + uint8_t m = Read(src); + + // from Op_INC + m = (m + 1) & 0xFF; + Write(src, m); + + // from here on is Op_SBC + int tmp = A - m - (IF_CARRY() ? 0 : 1); + + // N and V computed *BEFORE* adjustment (binary semantics) + SET_NEGATIVE(tmp & 0x80 ); + SET_OVERFLOW(((A ^ m) & (A ^ tmp) & 0x80) != 0); + + if (IF_DECIMAL()) + { + // see http://www.6502.org/tutorials/decimal_mode.html + int AL = (A & 0x0F) - (m & 0x0F) - (IF_CARRY() ? 0 : 1); + if (AL < 0) { + AL = ((AL - 6) & 0x0F) - 0x10; + } + tmp = (A & 0xF0) - (m & 0xF0) + AL; + if (tmp < 0) tmp -= 0x60; + } + + // Z and C computed *AFTER* adjustment + SET_ZERO(!(tmp & 0xFF)); + SET_CARRY( tmp >= 0 ); + + A = tmp & 0xFF; + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 7ad4d75..635e018 100644 --- a/mos6502.h +++ b/mos6502.h @@ -152,6 +152,7 @@ class mos6502 void Op_ANE(uint16_t src); void Op_ARR(uint16_t src); void Op_DCP(uint16_t src); + void Op_ISC(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 0fcb97676539e167ead245055bbff0ee9be2a442 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 17:29:38 -0700 Subject: [PATCH 21/33] Op_LAS --- mos6502.cpp | 12 ++++++++++++ mos6502.h | 1 + 2 files changed, 13 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index fb00f78..e6d0eb5 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1045,6 +1045,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // absolute,Y LAS oper,Y BB 3 4* + MAKE_INSTR(0xBB, LAS, ABY, 4, true); + // LAX // LDA oper + LDX oper // @@ -2461,4 +2463,14 @@ void mos6502::Op_ISC(uint16_t src) return; } +void mos6502::Op_LAS(uint16_t src) +{ + uint8_t tmp = Read(src); + tmp &= sp; + A = X = sp = tmp; + SET_NEGATIVE(tmp & 0x80); + SET_ZERO(tmp == 0); + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 635e018..62eed86 100644 --- a/mos6502.h +++ b/mos6502.h @@ -153,6 +153,7 @@ class mos6502 void Op_ARR(uint16_t src); void Op_DCP(uint16_t src); void Op_ISC(uint16_t src); + void Op_LAS(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 8fac4219097cce9b40e551e26f1c13715b47c454 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 17:49:16 -0700 Subject: [PATCH 22/33] Op_LAX --- mos6502.cpp | 15 +++++++++++++++ mos6502.h | 1 + 2 files changed, 16 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index e6d0eb5..a0a5fda 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1062,6 +1062,13 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // (indirect,X) LAX (oper,X) A3 2 6 // (indirect),Y LAX (oper),Y B3 2 5* + MAKE_INSTR(0xA7, LAX, ZER, 3, false); + MAKE_INSTR(0xB7, LAX, ZEY, 4, false); + MAKE_INSTR(0xAF, LAX, ABS, 4, false); + MAKE_INSTR(0xBF, LAX, ABY, 4, true); + MAKE_INSTR(0xA3, LAX, INX, 6, false); + MAKE_INSTR(0xB3, LAX, INY, 5, true); + // LXA (LAX immediate) // Store * AND oper in A and X // @@ -2473,4 +2480,12 @@ void mos6502::Op_LAS(uint16_t src) return; } +void mos6502::Op_LAX(uint16_t src) +{ + uint8_t m = Read(src); + SET_NEGATIVE(m & 0x80); + SET_ZERO(!m); + A = X = m; +} + #endif diff --git a/mos6502.h b/mos6502.h index 62eed86..edae34c 100644 --- a/mos6502.h +++ b/mos6502.h @@ -154,6 +154,7 @@ class mos6502 void Op_DCP(uint16_t src); void Op_ISC(uint16_t src); void Op_LAS(uint16_t src); + void Op_LAX(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From a78fb69d2ceb12b9d8d377a919e1d11bc415d172 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 17:53:55 -0700 Subject: [PATCH 23/33] Op_LXA --- mos6502.cpp | 11 +++++++++++ mos6502.h | 1 + 2 files changed, 12 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index a0a5fda..3bdb531 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1081,6 +1081,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate LXA #oper AB 2 2 †† + MAKE_INSTR(0xAB, LXA, IMM, 2, false); + // RLA // ROL oper + AND oper // @@ -2488,4 +2490,13 @@ void mos6502::Op_LAX(uint16_t src) A = X = m; } +void mos6502::Op_LXA(uint16_t src) +{ + uint8_t m = Read(src); + A = (A | 0xee) & m; // like ANE, unstable mystery constant + X = A; + SET_NEGATIVE(A & 0x80); + SET_ZERO(!A); +} + #endif diff --git a/mos6502.h b/mos6502.h index edae34c..9549330 100644 --- a/mos6502.h +++ b/mos6502.h @@ -155,6 +155,7 @@ class mos6502 void Op_ISC(uint16_t src); void Op_LAS(uint16_t src); void Op_LAX(uint16_t src); + void Op_LXA(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 0b40820212dcb8c59d7cfcad774f86596ed905bc Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 18:17:48 -0700 Subject: [PATCH 24/33] Op_RLA --- mos6502.cpp | 25 +++++++++++++++++++++++++ mos6502.h | 1 + 2 files changed, 26 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 3bdb531..98823bf 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1099,6 +1099,14 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // (indirect,X) RLA (oper,X) 23 2 8 // (indirect),Y RLA (oper),Y 33 2 8 + MAKE_INSTR(0x27, RLA, ZER, 5, false); + MAKE_INSTR(0x37, RLA, ZEX, 6, false); + MAKE_INSTR(0x2F, RLA, ABS, 6, false); + MAKE_INSTR(0x3F, RLA, ABX, 7, false); + MAKE_INSTR(0x3B, RLA, ABY, 7, false); + MAKE_INSTR(0x23, RLA, INX, 8, false); + MAKE_INSTR(0x33, RLA, INY, 8, false); + // RRA // ROR oper + ADC oper // @@ -2499,4 +2507,21 @@ void mos6502::Op_LXA(uint16_t src) SET_ZERO(!A); } +void mos6502::Op_RLA(uint16_t src) +{ + uint16_t m = Read(src); + m <<= 1; + if (IF_CARRY()) m |= 0x01; + SET_CARRY(m > 0xFF); + m &= 0xFF; + Write(src, m); + + A &= m; + + SET_NEGATIVE(A & 0x80); + SET_ZERO(!A); + + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 9549330..0465c21 100644 --- a/mos6502.h +++ b/mos6502.h @@ -156,6 +156,7 @@ class mos6502 void Op_LAS(uint16_t src); void Op_LAX(uint16_t src); void Op_LXA(uint16_t src); + void Op_RLA(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 6d381e6b27e74e833dd10ed99e2c405bf84123dd Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 18:29:10 -0700 Subject: [PATCH 25/33] Op_RRA --- mos6502.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mos6502.h | 1 + 2 files changed, 53 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 98823bf..4f67164 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1123,6 +1123,14 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // (indirect,X) RRA (oper,X) 63 2 8 // (indirect),Y RRA (oper),Y 73 2 8 + MAKE_INSTR(0x67, RRA, ZER, 5, false); + MAKE_INSTR(0x77, RRA, ZEX, 6, false); + MAKE_INSTR(0x6F, RRA, ABS, 6, false); + MAKE_INSTR(0x7F, RRA, ABX, 7, false); + MAKE_INSTR(0x7B, RRA, ABY, 7, false); + MAKE_INSTR(0x63, RRA, INX, 8, false); + MAKE_INSTR(0x73, RRA, INY, 8, false); + // SAX (AXS, AAX) // A and X are put on the bus at the same time (resulting effectively in an AND operation) and stored in M // @@ -2524,4 +2532,48 @@ void mos6502::Op_RLA(uint16_t src) return; } +void mos6502::Op_RRA(uint16_t src) +{ + uint16_t m = Read(src); + bool oldC = false; + if (IF_CARRY()) { + m |= 0x100; + oldC = true; + } + SET_CARRY(m & 0x01); + m >>= 1; + m &= 0xFF; + Write(src, m); + + unsigned int tmp = m + A + (oldC ? 1 : 0); + + // N and V computed *BEFORE* adjustment + SET_NEGATIVE(tmp & 0x80); + SET_OVERFLOW(!((A ^ m) & 0x80) && ((A ^ tmp) & 0x80)); + + if (IF_DECIMAL()) + { + // see http://www.6502.org/tutorials/decimal_mode.html + int AL = ((A & 0xF) + (m & 0xF) + (IF_CARRY() ? 1 : 0)); + if (AL >= 0xA) { + AL = ((AL + 6) & 0xF) + 0x10; + } + tmp = (m & 0xF0) + (A & 0xF0) + AL; + if (tmp >= 0xA0) tmp += 0x60; + } + + // Z and C computed *AFTER* adjustment + SET_ZERO(!(tmp & 0xFF)); + SET_CARRY(tmp > 0xFF); + + A = tmp & 0xFF; + return; + + + + SET_NEGATIVE(m & 0x80); + SET_ZERO(!m); + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 0465c21..0e3b28f 100644 --- a/mos6502.h +++ b/mos6502.h @@ -157,6 +157,7 @@ class mos6502 void Op_LAX(uint16_t src); void Op_LXA(uint16_t src); void Op_RLA(uint16_t src); + void Op_RRA(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From ea56f91a056b92df7e43d23a2f50a8ab1cca611d Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 18:35:55 -0700 Subject: [PATCH 26/33] Op_SAX --- mos6502.cpp | 14 +++++++++----- mos6502.h | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index 4f67164..5e78b12 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1144,6 +1144,11 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // absolute SAX oper 8F 3 4 // (indirect,X) SAX (oper,X) 83 2 6 + MAKE_INSTR(0x87, SAX, ZER, 3, false); + MAKE_INSTR(0x97, SAX, ZEY, 4, false); + MAKE_INSTR(0x8F, SAX, ABS, 4, false); + MAKE_INSTR(0x83, SAX, INX, 6, false); + // SBX (AXS, SAX) // CMP and DEX at once, sets flags like CMP // @@ -2568,12 +2573,11 @@ void mos6502::Op_RRA(uint16_t src) A = tmp & 0xFF; return; +} - - - SET_NEGATIVE(m & 0x80); - SET_ZERO(!m); - return; +void mos6502::Op_SAX(uint16_t src) +{ + Write(src, A & X); // most simple illegal here } #endif diff --git a/mos6502.h b/mos6502.h index 0e3b28f..5bc09ae 100644 --- a/mos6502.h +++ b/mos6502.h @@ -158,6 +158,7 @@ class mos6502 void Op_LXA(uint16_t src); void Op_RLA(uint16_t src); void Op_RRA(uint16_t src); + void Op_SAX(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From ab4c17f18837ef2ff03bad82c438a132b20edf1b Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 18:44:04 -0700 Subject: [PATCH 27/33] Op_SBX --- mos6502.cpp | 15 +++++++++++++++ mos6502.h | 1 + 2 files changed, 16 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 5e78b12..1b40893 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1159,6 +1159,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // immediate SBX #oper CB 2 2 + MAKE_INSTR(0xCB, SBX, IMM, 2, false); + // SHA (AHX, AXA) // Stores A AND X AND (high-byte of addr. + 1) at addr. // @@ -2580,4 +2582,17 @@ void mos6502::Op_SAX(uint16_t src) Write(src, A & X); // most simple illegal here } +void mos6502::Op_SBX(uint16_t src) +{ + uint16_t m = Read(src); + uint8_t tmp = A & X; + + SET_CARRY(tmp >= m); + SET_ZERO(tmp == m); + + X = tmp - m; + + SET_NEGATIVE(X & 0x80); +} + #endif diff --git a/mos6502.h b/mos6502.h index 5bc09ae..283a46c 100644 --- a/mos6502.h +++ b/mos6502.h @@ -159,6 +159,7 @@ class mos6502 void Op_RLA(uint16_t src); void Op_RRA(uint16_t src); void Op_SAX(uint16_t src); + void Op_SBX(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 0cdddd2ec4b8a241e5d9afbeddecd4c52e537c11 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 18:52:20 -0700 Subject: [PATCH 28/33] Op_SHX --- mos6502.cpp | 19 +++++++++++++++++++ mos6502.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 1b40893..e51fb9d 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1175,6 +1175,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // absolute,Y SHA oper,Y 9F 3 5 † // (indirect),Y SHA (oper),Y 93 2 6 † + MAKE_INSTR(0x9F, SHA, ABY, 5, false); + MAKE_INSTR(0x93, SHA, INY, 6, false); + // SHX (A11, SXA, XAS) // Stores X AND (high-byte of addr. + 1) at addr. // @@ -1188,6 +1191,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // absolute,Y SHX oper,Y 9E 3 5 † + MAKE_INSTR(0x9E, SHX, ABY, 5, false); + // SHY (A11, SYA, SAY) // Stores Y AND (high-byte of addr. + 1) at addr. // @@ -2595,4 +2600,18 @@ void mos6502::Op_SBX(uint16_t src) SET_NEGATIVE(X & 0x80); } +void mos6502::Op_SHA(uint16_t src) +{ + // unstable, but this is the stable behavior + uint8_t tmp = A & X & ((src >> 8) + 1); + Write(src, tmp); +} + +void mos6502::Op_SHX(uint16_t src) +{ + // unstable, but this is the stable behavior + uint8_t tmp = X & ((src >> 8) + 1); + Write(src, tmp); +} + #endif diff --git a/mos6502.h b/mos6502.h index 283a46c..f0d2a87 100644 --- a/mos6502.h +++ b/mos6502.h @@ -160,6 +160,8 @@ class mos6502 void Op_RRA(uint16_t src); void Op_SAX(uint16_t src); void Op_SBX(uint16_t src); + void Op_SHA(uint16_t src); + void Op_SHX(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 6d63be6623c348c731c43b8a82162567fb688833 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 18:58:00 -0700 Subject: [PATCH 29/33] Op_SHY --- mos6502.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mos6502.h b/mos6502.h index f0d2a87..ceaa62b 100644 --- a/mos6502.h +++ b/mos6502.h @@ -162,6 +162,7 @@ class mos6502 void Op_SBX(uint16_t src); void Op_SHA(uint16_t src); void Op_SHX(uint16_t src); + void Op_SHY(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From f6ad00c1b74954137ffa8fe9a9a0d76b774cfb8b Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 19:02:24 -0700 Subject: [PATCH 30/33] Op_SLO --- mos6502.cpp | 32 ++++++++++++++++++++++++++++++++ mos6502.h | 1 + 2 files changed, 33 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index e51fb9d..3dfa1d3 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1206,6 +1206,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // absolute,X SHY oper,X 9C 3 5 † + MAKE_INSTR(0x9C, SHY, ABX, 5, false); + // SLO (ASO) // ASL oper + ORA oper // @@ -1222,6 +1224,14 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // (indirect,X) SLO (oper,X) 03 2 8 // (indirect),Y SLO (oper),Y 13 2 8 + MAKE_INSTR(0x07, SLO, ZER, 5, false); + MAKE_INSTR(0x17, SLO, ZEX, 6, false); + MAKE_INSTR(0x0F, SLO, ABS, 6, false); + MAKE_INSTR(0x1F, SLO, ABX, 7, false); + MAKE_INSTR(0x1B, SLO, ABY, 7, false); + MAKE_INSTR(0x03, SLO, INX, 8, false); + MAKE_INSTR(0x13, SLO, INY, 8, false); + // SRE (LSE) // LSR oper + EOR oper // @@ -2614,4 +2624,26 @@ void mos6502::Op_SHX(uint16_t src) Write(src, tmp); } +void mos6502::Op_SHY(uint16_t src) +{ + // unstable, but this is the stable behavior + uint8_t tmp = Y & ((src >> 8) + 1); + Write(src, tmp); +} + +void mos6502::Op_SLO(uint16_t src) +{ + uint8_t m = Read(src); + SET_CARRY(m & 0x80); + m <<= 1; + m &= 0xFF; + Write(src, m); + + A |= m; + + SET_NEGATIVE(A & 0x80); + SET_ZERO(!A); + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index ceaa62b..4a49ec6 100644 --- a/mos6502.h +++ b/mos6502.h @@ -163,6 +163,7 @@ class mos6502 void Op_SHA(uint16_t src); void Op_SHX(uint16_t src); void Op_SHY(uint16_t src); + void Op_SLO(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 8fdcde961ebf5807210e42ec8884b501cce56f81 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 19:05:43 -0700 Subject: [PATCH 31/33] Op_SRE --- mos6502.cpp | 22 ++++++++++++++++++++++ mos6502.h | 1 + 2 files changed, 23 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 3dfa1d3..5295e2f 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1248,6 +1248,14 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // (indirect,X) SRE (oper,X) 43 2 8 // (indirect),Y SRE (oper),Y 53 2 8 + MAKE_INSTR(0x47, SRE, ZER, 5, false); + MAKE_INSTR(0x57, SRE, ZEX, 6, false); + MAKE_INSTR(0x4F, SRE, ABS, 6, false); + MAKE_INSTR(0x5F, SRE, ABX, 7, false); + MAKE_INSTR(0x5B, SRE, ABY, 7, false); + MAKE_INSTR(0x43, SRE, INX, 8, false); + MAKE_INSTR(0x53, SRE, INY, 8, false); + // TAS (XAS, SHS) // Puts A AND X in SP and stores A AND X AND (high-byte of addr. + 1) at addr. // @@ -2646,4 +2654,18 @@ void mos6502::Op_SLO(uint16_t src) return; } +void mos6502::Op_SRE(uint16_t src) +{ + uint8_t m = Read(src); + SET_CARRY(m & 0x01); + m >>= 1; + Write(src, m); + + A ^= m; + + SET_NEGATIVE(A & 0x80); + SET_ZERO(!A); + return; +} + #endif diff --git a/mos6502.h b/mos6502.h index 4a49ec6..00bdad9 100644 --- a/mos6502.h +++ b/mos6502.h @@ -164,6 +164,7 @@ class mos6502 void Op_SHX(uint16_t src); void Op_SHY(uint16_t src); void Op_SLO(uint16_t src); + void Op_SRE(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From cf279f6676ccc978196ec81970b4bf023776f08b Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 19:09:34 -0700 Subject: [PATCH 32/33] Op_TAS --- mos6502.cpp | 11 +++++++++++ mos6502.h | 1 + 2 files changed, 12 insertions(+) diff --git a/mos6502.cpp b/mos6502.cpp index 5295e2f..055f180 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -1269,6 +1269,8 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // addressing assembler opc bytes cycles // absolute,Y TAS oper,Y 9B 3 5 † + MAKE_INSTR(0x9B, TAS, ABY, 5, false); + // USBC (SBC) // SBC oper + NOP // @@ -2668,4 +2670,13 @@ void mos6502::Op_SRE(uint16_t src) return; } +void mos6502::Op_TAS(uint16_t src) +{ + // unstable, but this is the stable behavior + sp = A & X; + + uint8_t tmp = A & X & ((src >> 8) + 1); + Write(src, tmp); +} + #endif diff --git a/mos6502.h b/mos6502.h index 00bdad9..51b5f78 100644 --- a/mos6502.h +++ b/mos6502.h @@ -165,6 +165,7 @@ class mos6502 void Op_SHY(uint16_t src); void Op_SLO(uint16_t src); void Op_SRE(uint16_t src); + void Op_TAS(uint16_t src); #endif void Op_ILLEGAL(uint16_t src); From 8f3460b5745ba36d516f840f01a52948d3188718 Mon Sep 17 00:00:00 2001 From: Gorilla Sapiens Date: Wed, 15 Oct 2025 19:13:19 -0700 Subject: [PATCH 33/33] removed trailing linespace --- mos6502.cpp | 240 ++++++++++++++++++++++++++-------------------------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/mos6502.cpp b/mos6502.cpp index 055f180..8cf6a67 100644 --- a/mos6502.cpp +++ b/mos6502.cpp @@ -73,7 +73,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ADC // Add Memory to Accumulator with Carry -// +// // A + M + C -> A, C // N Z C I D V // + + + - - + @@ -98,7 +98,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // AND // AND Memory with Accumulator -// +// // A AND M -> A // N Z C I D V // + + - - - - @@ -123,7 +123,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ASL // Shift Left One Bit (Memory or Accumulator) -// +// // C <- [76543210] <- 0 // N Z C I D V // + + + - - - @@ -142,7 +142,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BCC // Branch on Carry Clear -// +// // branch on C = 0 // N Z C I D V // - - - - - - @@ -153,7 +153,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BCS // Branch on Carry Set -// +// // branch on C = 1 // N Z C I D V // - - - - - - @@ -164,7 +164,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BEQ // Branch on Result Zero -// +// // branch on Z = 1 // N Z C I D V // - - - - - - @@ -175,15 +175,15 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BIT // Test Bits in Memory with Accumulator -// +// // bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V); // the zero-flag is set according to the result of the operand AND // the accumulator (set, if the result is zero, unset otherwise). // This allows a quick check of a few bits at once without affecting // any of the registers, other than the status register (SR). -// +// // → Further details. -// +// // A AND M -> Z, M7 -> N, M6 -> V // N Z C I D V // M7 + - - - M6 @@ -196,7 +196,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BMI // Branch on Result Minus -// +// // branch on N = 1 // N Z C I D V // - - - - - - @@ -207,7 +207,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BNE // Branch on Result not Zero -// +// // branch on Z = 0 // N Z C I D V // - - - - - - @@ -218,7 +218,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BPL // Branch on Result Plus -// +// // branch on N = 0 // N Z C I D V // - - - - - - @@ -229,7 +229,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BRK // Force Break -// +// // BRK initiates a software interrupt similar to a hardware // interrupt (IRQ). The return address pushed to the stack is // PC+2, providing an extra byte of spacing for a break mark @@ -238,9 +238,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // flag set to 1. However, when retrieved during RTI or by a PLP // instruction, the break flag will be ignored. // The interrupt disable flag is not set automatically. -// +// // → Further details. -// +// // interrupt, // push PC+2, push SR // N Z C I D V @@ -252,7 +252,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BVC // Branch on Overflow Clear -// +// // branch on V = 0 // N Z C I D V // - - - - - - @@ -263,7 +263,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // BVS // Branch on Overflow Set -// +// // branch on V = 1 // N Z C I D V // - - - - - - @@ -274,7 +274,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // CLC // Clear Carry Flag -// +// // 0 -> C // N Z C I D V // - - 0 - - - @@ -285,7 +285,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // CLD // Clear Decimal Mode -// +// // 0 -> D // N Z C I D V // - - - - 0 - @@ -296,7 +296,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // CLI // Clear Interrupt Disable Bit -// +// // 0 -> I // N Z C I D V // - - - 0 - - @@ -307,7 +307,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // CLV // Clear Overflow Flag -// +// // 0 -> V // N Z C I D V // - - - - - 0 @@ -318,7 +318,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // CMP // Compare Memory with Accumulator -// +// // A - M // N Z C I D V // + + + - - - @@ -343,7 +343,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // CPX // Compare Memory and Index X -// +// // X - M // N Z C I D V // + + + - - - @@ -358,7 +358,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // CPY // Compare Memory and Index Y -// +// // Y - M // N Z C I D V // + + + - - - @@ -373,7 +373,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // DEC // Decrement Memory by One -// +// // M - 1 -> M // N Z C I D V // + + - - - - @@ -390,7 +390,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // DEX // Decrement Index X by One -// +// // X - 1 -> X // N Z C I D V // + + - - - - @@ -401,7 +401,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // DEY // Decrement Index Y by One -// +// // Y - 1 -> Y // N Z C I D V // + + - - - - @@ -412,7 +412,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // EOR // Exclusive-OR Memory with Accumulator -// +// // A EOR M -> A // N Z C I D V // + + - - - - @@ -437,7 +437,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // INC // Increment Memory by One -// +// // M + 1 -> M // N Z C I D V // + + - - - - @@ -454,7 +454,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // INX // Increment Index X by One -// +// // X + 1 -> X // N Z C I D V // + + - - - - @@ -465,7 +465,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // INY // Increment Index Y by One -// +// // Y + 1 -> Y // N Z C I D V // + + - - - - @@ -476,7 +476,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // JMP // Jump to New Location -// +// // operand 1st byte -> PCL // operand 2nd byte -> PCH // N Z C I D V @@ -490,7 +490,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // JSR // Jump to New Location Saving Return Address -// +// // push (PC+2), // operand 1st byte -> PCL // operand 2nd byte -> PCH @@ -503,7 +503,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // LDA // Load Accumulator with Memory -// +// // M -> A // N Z C I D V // + + - - - - @@ -528,7 +528,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // LDX // Load Index X with Memory -// +// // M -> X // N Z C I D V // + + - - - - @@ -547,7 +547,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // LDY // Load Index Y with Memory -// +// // M -> Y // N Z C I D V // + + - - - - @@ -566,7 +566,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // LSR // Shift One Bit Right (Memory or Accumulator) -// +// // 0 -> [76543210] -> C // N Z C I D V // 0 + + - - - @@ -585,7 +585,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // NOP // No Operation -// +// // --- // N Z C I D V // - - - - - - @@ -596,7 +596,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ORA // OR Memory with Accumulator -// +// // A OR M -> A // N Z C I D V // + + - - - - @@ -621,7 +621,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // PHA // Push Accumulator on Stack -// +// // push A // N Z C I D V // - - - - - - @@ -632,10 +632,10 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // PHP // Push Processor Status on Stack -// +// // The status register will be pushed with the break // flag and bit 5 set to 1. -// +// // push SR // N Z C I D V // - - - - - - @@ -646,7 +646,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // PLA // Pull Accumulator from Stack -// +// // pull A // N Z C I D V // + + - - - - @@ -657,10 +657,10 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // PLP // Pull Processor Status from Stack -// +// // The status register will be pulled with the break // flag and bit 5 ignored. -// +// // pull SR // N Z C I D V // from stack @@ -671,7 +671,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ROL // Rotate One Bit Left (Memory or Accumulator) -// +// // C <- [76543210] <- C // N Z C I D V // + + + - - - @@ -690,7 +690,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ROR // Rotate One Bit Right (Memory or Accumulator) -// +// // C -> [76543210] -> C // N Z C I D V // + + + - - - @@ -709,10 +709,10 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // RTI // Return from Interrupt -// +// // The status register is pulled with the break flag // and bit 5 ignored. Then PC is pulled from the stack. -// +// // pull SR, pull PC // N Z C I D V // from stack @@ -723,7 +723,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // RTS // Return from Subroutine -// +// // pull PC, PC+1 -> PC // N Z C I D V // - - - - - - @@ -734,7 +734,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SBC // Subtract Memory from Accumulator with Borrow -// +// // A - M - C̅ -> A // N Z C I D V // + + + - - + @@ -759,7 +759,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SEC // Set Carry Flag -// +// // 1 -> C // N Z C I D V // - - 1 - - - @@ -770,7 +770,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SED // Set Decimal Flag -// +// // 1 -> D // N Z C I D V // - - - - 1 - @@ -781,7 +781,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SEI // Set Interrupt Disable Status -// +// // 1 -> I // N Z C I D V // - - - 1 - - @@ -792,7 +792,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // STA // Store Accumulator in Memory -// +// // A -> M // N Z C I D V // - - - - - - @@ -815,7 +815,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // STX // Store Index X in Memory -// +// // X -> M // N Z C I D V // - - - - - - @@ -830,7 +830,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // STY // Sore Index Y in Memory -// +// // Y -> M // N Z C I D V // - - - - - - @@ -845,7 +845,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // TAX // Transfer Accumulator to Index X -// +// // A -> X // N Z C I D V // + + - - - - @@ -856,7 +856,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // TAY // Transfer Accumulator to Index Y -// +// // A -> Y // N Z C I D V // + + - - - - @@ -867,7 +867,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // TSX // Transfer Stack Pointer to Index X -// +// // SP -> X // N Z C I D V // + + - - - - @@ -878,7 +878,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // TXA // Transfer Index X to Accumulator -// +// // X -> A // N Z C I D V // + + - - - - @@ -889,7 +889,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // TXS // Transfer Index X to Stack Register -// +// // X -> SP // N Z C I D V // - - - - - - @@ -900,7 +900,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // TYA // Transfer Index Y to Accumulator -// +// // Y -> A // N Z C I D V // + + - - - - @@ -913,9 +913,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ALR (ASR) // AND oper + LSR -// +// // A AND oper, 0 -> [76543210] -> C -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -925,9 +925,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ANC // AND oper + set C as ASL -// +// // A AND oper, bit(7) -> C -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -937,11 +937,11 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ANC (ANC2) // AND oper + set C as ROL -// +// // effectively the same as instr. 0B -// +// // A AND oper, bit(7) -> C -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -951,17 +951,17 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ANE (XAA) // * OR X + AND oper -// +// // Highly unstable, do not use. -// +// // A base value in A is determined based on the contets of A and a constant, // which may be typically $00, $ff, $ee, etc. The value of this constant // depends on temperature, the chip series, and maybe other factors, as well. // In order to eliminate these uncertaincies from the equation, use either 0 // as the operand or a value of $FF in the accumulator. -// +// // (A OR CONST) AND X AND oper -> A -// +// // N Z C I D V // + + - - - - // addressing assembler opc bytes cycles @@ -971,13 +971,13 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ARR // AND oper + ROR -// +// // This operation involves the adder: // V-flag is set according to (A AND oper) + oper // The carry is not set, but bit 7 (sign) is exchanged with the carry -// +// // A AND oper, C -> [76543210] -> C -// +// // N Z C I D V // + + + - - + // addressing assembler opc bytes cycles @@ -987,11 +987,11 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // DCP (DCM) // DEC oper + CMP oper -// +// // M - 1 -> M, A - M -// +// // Decrements the operand and then compares the result to the accumulator. -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -1013,9 +1013,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // ISC (ISB, INS) // INC oper + SBC oper -// +// // M + 1 -> M, A - M - C̅ -> A -// +// // N Z C I D V // + + + - - + // addressing assembler opc bytes cycles @@ -1037,9 +1037,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // LAS (LAR) // LDA/TSX oper -// +// // M AND SP -> A, X, SP -// +// // N Z C I D V // + + - - - - // addressing assembler opc bytes cycles @@ -1049,9 +1049,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // LAX // LDA oper + LDX oper -// +// // M -> A -> X -// +// // N Z C I D V // + + - - - - // addressing assembler opc bytes cycles @@ -1071,11 +1071,11 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // LXA (LAX immediate) // Store * AND oper in A and X -// +// // Highly unstable, involves a 'magic' constant, see ANE -// +// // (A OR CONST) AND oper -> A -> X -// +// // N Z C I D V // + + - - - - // addressing assembler opc bytes cycles @@ -1085,9 +1085,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // RLA // ROL oper + AND oper -// +// // M = C <- [76543210] <- C, A AND M -> A -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -1109,9 +1109,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // RRA // ROR oper + ADC oper -// +// // M = C -> [76543210] -> C, A + M + C -> A, C -// +// // N Z C I D V // + + + - - + // addressing assembler opc bytes cycles @@ -1133,9 +1133,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SAX (AXS, AAX) // A and X are put on the bus at the same time (resulting effectively in an AND operation) and stored in M -// +// // A AND X -> M -// +// // N Z C I D V // - - - - - - // addressing assembler opc bytes cycles @@ -1151,9 +1151,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SBX (AXS, SAX) // CMP and DEX at once, sets flags like CMP -// +// // (A AND X) - oper -> X -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -1163,12 +1163,12 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SHA (AHX, AXA) // Stores A AND X AND (high-byte of addr. + 1) at addr. -// +// // unstable: sometimes 'AND (H+1)' is dropped, page boundary crossings // may not work (with the high-byte of the value used as the high-byte of the address) -// +// // A AND X AND (H+1) -> M -// +// // N Z C I D V // - - - - - - // addressing assembler opc bytes cycles @@ -1180,12 +1180,12 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SHX (A11, SXA, XAS) // Stores X AND (high-byte of addr. + 1) at addr. -// +// // unstable: sometimes 'AND (H+1)' is dropped, page boundary // crossings may not work (with the high-byte of the value used as the high-byte of the address) -// +// // X AND (H+1) -> M -// +// // N Z C I D V // - - - - - - // addressing assembler opc bytes cycles @@ -1195,12 +1195,12 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SHY (A11, SYA, SAY) // Stores Y AND (high-byte of addr. + 1) at addr. -// +// // unstable: sometimes 'AND (H+1)' is dropped, page boundary // crossings may not work (with the high-byte of the value used as the high-byte of the address) -// +// // Y AND (H+1) -> M -// +// // N Z C I D V // - - - - - - // addressing assembler opc bytes cycles @@ -1210,9 +1210,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SLO (ASO) // ASL oper + ORA oper -// +// // M = C <- [76543210] <- 0, A OR M -> A -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -1234,9 +1234,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // SRE (LSE) // LSR oper + EOR oper -// +// // M = 0 -> [76543210] -> C, A EOR M -> A -// +// // N Z C I D V // + + + - - - // addressing assembler opc bytes cycles @@ -1258,12 +1258,12 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // TAS (XAS, SHS) // Puts A AND X in SP and stores A AND X AND (high-byte of addr. + 1) at addr. -// +// // unstable: sometimes 'AND (H+1)' is dropped, page boundary // crossings may not work (with the high-byte of the value used as the high-byte of the address) -// +// // A AND X -> SP, A AND X AND (H+1) -> M -// +// // N Z C I D V // - - - - - - // addressing assembler opc bytes cycles @@ -1273,11 +1273,11 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // USBC (SBC) // SBC oper + NOP -// +// // effectively same as normal SBC immediate, instr. E9. -// +// // A - M - C̅ -> A -// +// // N Z C I D V // + + + - - + // addressing assembler opc bytes cycles @@ -1287,7 +1287,7 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // NOPs (including DOP, TOP) // Instructions effecting in 'no operations' in various address modes. Operands are ignored. -// +// // N Z C I D V // - - - - - - // opc addressing bytes cycles @@ -1359,9 +1359,9 @@ mos6502::mos6502(BusRead r, BusWrite w, ClockCycle c) // JAM (KIL, HLT) // These instructions freeze the CPU. -// +// // The processor will be trapped infinitely in T1 phase with $FF on the data bus. — Reset required. -// +// // Instruction codes: 02, 12, 22, 32, 42, 52, 62, 72, 92, B2, D2, F2 MAKE_INSTR(0x02, ILLEGAL, IMP, 0, false); @@ -2437,7 +2437,7 @@ void mos6502::Op_ANE(uint16_t src) // A base value in A is determined based on the contets of A and a constant, // which may be typically $00, $ff, $ee, etc. The value of this constant // depends on temperature, the chip series, and maybe other factors, as well. - const uint8_t constant = 0xee; + const uint8_t constant = 0xee; uint8_t m = Read(src); uint8_t res = ((A | constant) & X & m);