]> Shamusworld >> Repos - thunder/commitdiff
Added v6808 CPUs, support files
authorShamus Hammons <jlhamm@acm.org>
Thu, 30 Jul 2009 21:28:03 +0000 (21:28 +0000)
committerShamus Hammons <jlhamm@acm.org>
Thu, 30 Jul 2009 21:28:03 +0000 (21:28 +0000)
src/dis6808.cpp [new file with mode: 0755]
src/dis6808.h [new file with mode: 0755]
src/v6808.cpp [new file with mode: 0755]
src/v6808.h [new file with mode: 0755]

diff --git a/src/dis6808.cpp b/src/dis6808.cpp
new file mode 100755 (executable)
index 0000000..35c5479
--- /dev/null
@@ -0,0 +1,151 @@
+//
+// 6808 disassembler
+//
+// by James L. Hammons
+//
+// (c) 2004 Underground Software
+//
+
+#include "dis6808.h"
+
+#include <stdio.h>
+#include <string>
+#include "v6808.h"
+#include "log.h"
+
+using namespace std;
+
+// External shit
+
+#warning "THIS ISN'T GENERIC ENOUGH... !!! FIX !!!"
+/*extern*/ V6808REGS soundCPU;//Hm.
+
+// Private globals variables
+
+static char op_mat[256] = {
+  0, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+  5, 5, 0, 0, 0, 0, 5, 5, 0, 5, 0, 5, 0, 0, 0, 0,
+  3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, 0, 0, 5, 5,
+  5, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5,
+  5, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5,
+  7, 0, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7,
+  2, 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,
+  8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 8, 9, 3, 9, 0,
+  1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
+  7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+  2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 8, 0, 0, 9, 0,
+  1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1,
+  7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7,
+  2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2
+};
+
+static char mnemonics[256][6] = {
+  "???  ","NOP  ","???  ","???  ","???  ","???  ","TAP  ","TPA  ",
+  "INX  ","DEX  ","CLV  ","SEV  ","CLC  ","SEC  ","CLI  ","SEI  ",
+  "SBA  ","CBA  ","???  ","???  ","???  ","???  ","TAB  ","TBA  ",
+  "???  ","DAA  ","???  ","ABA  ","???  ","???  ","???  ","???  ",
+  "BRA  ","???  ","BHI  ","BLS  ","BCC  ","BCS  ","BNE  ","BEQ  ",
+  "BVC  ","BVS  ","BPL  ","BMI  ","BGE  ","BLT  ","BGT  ","BLE  ",
+  "TSX  ","INS  ","PULA ","PULB ","DES  ","TXS  ","PSHA ","PSHB ",
+  "???  ","RTS  ","???  ","RTI  ","???  ","???  ","WAI  ","SWI  ",
+  "NEGA ","???  ","???  ","COMA ","LSRA ","???  ","RORA ","ASRA ",
+  "ASLA ","ROLA ","DECA ","???  ","INCA ","TSTA ","???  ","CLRA ",
+  "NEGB ","???  ","???  ","COMB ","LSRB ","???  ","RORB ","ASRB ",
+  "ASLB ","ROLB ","DECB ","???  ","INCB ","TSTB ","???  ","CLRB ",
+  "NEG  ","???  ","???  ","COM  ","LSR  ","???  ","ROR  ","ASR  ",
+  "ASL  ","ROL  ","DEC  ","???  ","INC  ","TST  ","JMP  ","CLR  ",
+  "NEG  ","???  ","???  ","COM  ","LSR  ","???  ","ROR  ","ASR  ",
+  "ASL  ","ROL  ","DEC  ","???  ","INC  ","TST  ","JMP  ","CLR  ",
+  "SUBA ","CMPA ","SBCA ","???  ","ANDA ","BITA ","LDAA ","???  ",
+  "EORA ","ADCA ","ORAA ","ADDA ","CPX  ","BSR  ","LDS  ","???  ",
+  "SUBA ","CMPA ","SBCA ","???  ","ANDA ","BITA ","LDAA ","STAA ",
+  "EORA ","ADCA ","ORAA ","ADDA ","CPX  ","???  ","LDS  ","STS  ",
+  "SUBA ","CMPA ","SBCA ","???  ","ANDA ","BITA ","LDAA ","STAA ",
+  "EORA ","ADCA ","ORAA ","ADDA ","CPX  ","JSR  ","LDS  ","STS  ",
+  "SUBA ","CMPA ","SBCA ","???  ","ANDA ","BITA ","LDAA ","STAA ",
+  "EORA ","ADCA ","ORAA ","ADDA ","CPX  ","JSR  ","LDS  ","STS  ",
+  "SUBB ","CMPB ","SBCB ","???  ","ANDB ","BITB ","LDAB ","???  ",
+  "EORB ","ADCB ","ORAB ","ADDB ","???  ","???  ","LDX  ","???  ",
+  "SUBB ","CMPB ","SBCB ","???  ","ANDB ","BITB ","LDAB ","STAB ",
+  "EORB ","ADCB ","ORAB ","ADDB ","???  ","???  ","LDX  ","STX  ",
+  "SUBB ","CMPB ","SBCB ","???  ","ANDB ","BITB ","LDAB ","STAB ",
+  "EORB ","ADCB ","ORAB ","ADDB ","???  ","???  ","LDX  ","STX  ",
+  "SUBB ","CMPB ","SBCB ","???  ","ANDB ","BITB ","LDAB ","STAB ",
+  "EORB ","ADCB ","ORAB ","ADDB ","???  ","???  ","LDX  ","STX  "
+};
+
+//
+// Display bytes in mem in hex
+//
+static void DisplayBytes(uint16 src, uint32 dst)
+{
+       WriteLog("%04X: ", src);
+       uint8 cnt = 0;                                                                          // Init counter...
+
+       if (src > dst)
+               dst += 0x10000;                                                                 // That should fix the FFFF bug...
+
+       for(uint32 i=src; i<dst; i++)
+       {
+               WriteLog("%02X ", soundCPU.RdMem(i));
+               cnt++;                                                                                  // Bump counter...
+       }
+
+       for(int i=cnt; i<5; i++)                                                        // Pad the leftover spaces...
+               WriteLog("   ");
+}
+
+//
+// Decode a 6808 instruction
+//
+int Decode6808(uint16 pc)
+{
+       char outbuf[80];
+
+       uint16 addr = pc, offset;
+       uint8 opcode = soundCPU.RdMem(addr++);                          // Get the opcode
+
+       switch (op_mat[opcode])                                                         // Decode the addressing mode...
+       {
+       case 0:                                                                                         // Illegal
+               sprintf(outbuf, "???          ");
+               break;
+       case 1:                                                                                         // Zero page
+               sprintf(outbuf, "%s $%02X    ", mnemonics[opcode], soundCPU.RdMem(addr++));
+               break;
+       case 2:                                                                                         // Absolute
+//             sprintf(outbuf, "%s $%04X", mnemonics[opcode], (soundCPU.RdMem(addr++) << 8) | soundCPU.RdMem(addr++));
+               offset = (soundCPU.RdMem(addr + 0) << 8) | soundCPU.RdMem(addr + 1);
+               addr += 2;
+               sprintf(outbuf, "%s $%04X  ", mnemonics[opcode], offset);
+               break;
+       case 3:                                                                                         // Relative
+//             sprintf(outbuf, "%s $%04X", mnemonics[opcode], ++addr + (int16)(int8)soundCPU.RdMem(addr));
+               offset = addr + 1 + (int16)(int8)soundCPU.RdMem(addr);
+               addr++;
+               sprintf(outbuf, "%s $%04X  ", mnemonics[opcode], offset);
+               break;
+       case 5:                                                                                         // Inherent
+               sprintf(outbuf, "%s        ", mnemonics[opcode]);
+               break;
+       case 7:                                                                                         // Indexed
+               sprintf(outbuf, "%s $%02X,X  ", mnemonics[opcode], soundCPU.RdMem(addr++));
+               break;
+       case 8:                                                                                         // Immediate
+               sprintf(outbuf, "%s #$%02X   ", mnemonics[opcode], soundCPU.RdMem(addr++));
+               break;
+       case 9:                                                                                         // Long Immediate
+//             sprintf(outbuf, "%s #$%04X", mnemonics[opcode], (soundCPU.RdMem(addr++) << 8) | soundCPU.RdMem(addr++));
+               offset = (soundCPU.RdMem(addr + 0) << 8) | soundCPU.RdMem(addr + 1);
+               addr += 2;
+               sprintf(outbuf, "%s #$%04X ", mnemonics[opcode], offset);
+               break;
+       }
+
+       DisplayBytes(pc, addr);                                                         // Show bytes
+       WriteLog("%s", outbuf);                                                         // Display opcode & addressing, etc.
+
+       return addr - pc;
+}
diff --git a/src/dis6808.h b/src/dis6808.h
new file mode 100755 (executable)
index 0000000..3f77e13
--- /dev/null
@@ -0,0 +1,15 @@
+//
+// DIS6809.H
+//
+// by James L. Hammons
+// (C) 2004 Underground Software
+//
+
+#ifndef __DIS6809_H__
+#define __DIS6809_H__
+
+#include "types.h"
+
+int Decode6808(uint16 pc);
+
+#endif // __DIS6809_H__
diff --git a/src/v6808.cpp b/src/v6808.cpp
new file mode 100755 (executable)
index 0000000..2022e90
--- /dev/null
@@ -0,0 +1,2119 @@
+//
+// Virtual 6808 Emulator v2.0
+//
+// by James L. Hammons
+// (C) 2006 Underground Software
+//
+// JLH = James L. Hammons <jlhamm@acm.org>
+//
+// WHO  WHEN        WHAT
+// ---  ----------  ------------------------------------------------------------
+// JLH  06/15/2006  Added changelog ;-)
+// JLH  06/15/2006  Scrubbed all BYTE, WORD & DWORD references from the code
+// JLH  11/13/2006  Converted core to V65C02 macro style :-)
+// JLH  11/13/2006  Converted flags to unpacked and separate flags
+// JLH  07/21/2009  Converted clock from 32-bit to 64-bit value, added possible
+//                  "don't branch" optimization
+//
+
+// NOTE: V6808_STATE_WAI is not handled in the main loop correctly. !!! FIX !!!
+
+// Some random thoughts: Could there be a performance gain by breaking
+// out the flags in regs.cc into separate uint8 variables (or bools)?
+// You'd have to convert on entering and exiting the emulation loop, but I
+// think the perfomance hit would be negligible compared to the gain in not
+// having to mask and shift flags all the time. Investigate after the
+// conversion to macro style opcodes is completed. :-)
+// [DONE--remain to be seen if there is any performance increase]
+
+//#define __DEBUG__
+#define TEST_DONT_BRANCH_OPTIMIZATION
+
+#include "v6808.h"
+
+#ifdef __DEBUG__
+#include "dis6808.h"
+#include "log.h"
+#endif
+
+// Various macros
+
+#define CLR_Z                                  (flagZ = 0)
+#define CLR_ZN                                 (flagZ = flagN = 0)
+#define CLR_ZNC                                        (flagZ = flagN = flagC = 0)
+#define CLR_NVC                                        (flagN = flagV = flagC = 0)
+#define CLR_VC                                 (flagV = flagC = 0)
+#define CLR_V                                  (flagV = 0)
+#define CLR_N                                  (flagN = 0)
+#define SET_Z(r)                               (flagZ = ((r) == 0 ? 1 : 0))
+#define SET_N(r)                               (flagN = ((r) & 0x80) >> 7)
+#define SET_V(a,b,r)                   (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
+
+#define SET_C_CMP(a,b)                 (flagC = ((uint8)(b) < (uint8)(a) ? 1 : 0))
+#define SET_ZN(r)                              SET_N(r); SET_Z(r)
+#define SET_ZNC_ADD(a,b,r)             SET_N(r); SET_Z(r); SET_C_ADD(a,b)
+#define SET_ZNVC_CMP(a,b,r)            SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
+
+#define SET_N16(r)                             (flagN = ((r) & 0x8000) >> 15)
+#define SET_V16(a,b,r)                 (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
+#define SET_C_CMP16(a,b)               (flagC = ((uint16)(b) < (uint16)(a) ? 1 : 0))
+#define SET_ZNVC_CMP16(a,b,r)  SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
+
+//Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!! [DONE, kinda]
+//Can't fix for reading...
+#define EA_IMM                         regs.pc++
+#define EA_ZP                          regs.RdMem(regs.pc++)
+#define EA_ZP_X                                (regs.RdMem(regs.pc++) + regs.x)
+#define EA_ABS                         RdMemW(regs.pc)
+
+#define READ_IMM                       regs.RdMem(EA_IMM)
+#define READ_ZP                                regs.RdMem(EA_ZP)
+#define READ_ZP_X                      regs.RdMem(EA_ZP_X)
+#define READ_ABS                       regs.RdMem(EA_ABS);                     regs.pc += 2
+
+#define READ_IMM16                     RdMemW(regs.pc);                        regs.pc += 2
+#define READ_ZP16                      RdMemW(EA_ZP)
+#define READ_ZP_X16                    RdMemW(EA_ZP_X)
+#define READ_ABS16                     RdMemW(EA_ABS);                         regs.pc += 2
+
+#define READ_IMM_WB(v)         uint16 addr = EA_IMM;           v = regs.RdMem(addr)
+#define READ_ZP_WB(v)          uint16 addr = EA_ZP;            v = regs.RdMem(addr)
+#define READ_ZP_X_WB(v)                uint16 addr = EA_ZP_X;          v = regs.RdMem(addr)
+#define READ_ABS_WB(v)         uint16 addr = EA_ABS;           v = regs.RdMem(addr); regs.pc += 2
+
+#define WRITE_BACK(d)          regs.WrMem(addr, (d))
+
+#define PULL                           regs.RdMem(regs.s++)
+#define PUSH(r)                                regs.WrMem(--regs.s, (r))
+#define PULL16                         RdMemW(regs.s);                         regs.s += 2
+#define PUSH16(r)                      regs.WrMem(--regs.s, (r) & 0xFF); regs.WrMem(--regs.s, (r) >> 8)
+
+#define PACK_FLAGS                     ((regs.cc & 0xC0) | (flagH << 5) | (flagI << 4) | (flagN << 3) | (flagZ << 2) | (flagV << 1) | flagC)
+#define UNPACK_FLAGS           flagH = (regs.cc & FLAG_H) >> 5; \
+       flagI = (regs.cc & FLAG_I) >> 4; \
+       flagN = (regs.cc & FLAG_N) >> 3; \
+       flagZ = (regs.cc & FLAG_Z) >> 2; \
+       flagV = (regs.cc & FLAG_V) >> 1; \
+       flagC = (regs.cc & FLAG_C)
+
+// Private global variables
+
+static V6808REGS regs;
+static uint8 flagH, flagI, flagN, flagZ, flagV, flagC;
+
+static uint8 CPUCycles[256] = {
+       1,  2,  1,  1,  1,  1,  2,  2,  4,  4,  2,  2,  2,  2,  2,  2,
+       2,  2,  1,  1,  1,  1,  2,  2,  1,  2,  1,  2,  1,  1,  1,  1,
+       4,  1,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+       4,  4,  4,  4,  4,  4,  4,  4,  1,  5,  1, 10,  1,  1,  9, 12,
+       2,  1,  1,  2,  2,  1,  2,  2,  2,  2,  2,  1,  2,  2,  1,  2,
+       2,  1,  1,  2,  2,  1,  2,  2,  2,  2,  2,  1,  2,  2,  1,  2,
+       7,  1,  1,  8,  7,  1,  7,  7,  7,  7,  7,  1,  7,  7,  4,  7,
+       6,  1,  1,  7,  6,  1,  6,  6,  6,  6,  6,  1,  6,  6,  3,  6,
+       2,  2,  2,  1,  2,  2,  2,  1,  2,  2,  2,  2,  3,  8,  3,  1,
+       3,  3,  3,  1,  3,  3,  3,  4,  3,  3,  3,  3,  4,  1,  4,  5,
+       5,  5,  5,  1,  5,  5,  5,  6,  5,  5,  5,  5,  6,  8,  6,  7,
+       4,  4,  4,  1,  4,  4,  4,  5,  4,  4,  4,  4,  5,  9,  5,  6,
+       2,  2,  2,  1,  2,  2,  2,  1,  2,  2,  2,  2,  1,  1,  3,  1,
+       3,  3,  3,  1,  3,  3,  3,  4,  3,  3,  3,  3,  1,  1,  4,  5,
+       5,  5,  5,  1,  5,  5,  5,  6,  5,  5,  5,  5,  1,  1,  6,  7,
+       4,  4,  4,  1,  4,  4,  4,  5,  4,  4,  4,  4,  1,  1,  5,  6
+};
+
+// Private function prototypes
+
+static uint16 RdMemW(uint16);
+
+//
+// Read a word out of 6808 memory (little endian format)
+//
+static inline uint16 RdMemW(uint16 address)
+{
+       return (uint16)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
+}
+
+//
+// 6808 OPCODE IMPLEMENTATION
+//
+// NOTE: Lots of macros are used here to save a LOT of typing. Also
+//       helps speed the debugging process. :-) Because of this, combining
+//       certain lines may look like a good idea but would end in disaster.
+//       You have been warned! ;-)
+//
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Add                     |ADDA |8B 2 2|9B 3 2|AB 5 2|BB 4 3|      |A=A+M     |T TTTT|
+                        |ADDB |CB 2 2|DB 3 2|EB 5 2|FB 4 3|      |B=B+M     |T TTTT|
+Add Accumulators        |ABA  |      |      |      |      |1B 2 1|A=A+B     |T TTTT|
+*/
+
+// ADD opcodes
+
+#define OP_ADD_HANDLER(m, acc) \
+       uint16 sum = (uint16)(acc) + (m); \
+       flagC = sum >> 8; \
+       flagH = (sum >> 4) & 0x01; \
+       SET_V(m, acc, sum); \
+       (acc) = sum & 0xFF; \
+       SET_ZN(acc)
+
+static void Op8B(void)                                                 // ADDA #
+{
+       uint16 m = READ_IMM;
+       OP_ADD_HANDLER(m, regs.a);
+}
+
+static void Op9B(void)                                                 // ADDA ZP
+{
+       uint16 m = READ_ZP;
+       OP_ADD_HANDLER(m, regs.a);
+}
+
+static void OpAB(void)                                                 // ADDA ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_ADD_HANDLER(m, regs.a);
+}
+
+static void OpBB(void)                                                 // ADDA ABS
+{
+       uint16 m = READ_ABS;
+       OP_ADD_HANDLER(m, regs.a);
+}
+
+static void OpCB(void)                                                 // ADDB #
+{
+       uint16 m = READ_IMM;
+       OP_ADD_HANDLER(m, regs.b);
+}
+
+static void OpDB(void)                                                 // ADDB ZP
+{
+       uint16 m = READ_ZP;
+       OP_ADD_HANDLER(m, regs.b);
+}
+
+static void OpEB(void)                                                 // ADDB ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_ADD_HANDLER(m, regs.b);
+}
+
+static void OpFB(void)                                                 // ADDB ABS
+{
+       uint16 m = READ_ABS;
+       OP_ADD_HANDLER(m, regs.b);
+}
+
+static void Op1B(void)                                                 // ABA
+{
+       OP_ADD_HANDLER(regs.b, regs.a);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Add with Carry          |ADCA |89 2 2|99 3 2|A9 5 2|B9 4 3|      |A=A+M+C   |T TTTT|
+                        |ADCB |C9 2 2|D9 3 2|E9 5 2|F9 4 3|      |B=B+M+C   |T TTTT|
+*/
+
+// ADC opcodes
+
+#define OP_ADC_HANDLER(m, acc) \
+       uint16 sum = (uint16)acc + (m) + (uint16)flagC; \
+       flagC = sum >> 8; \
+       flagH = (sum >> 4) & 0x01; \
+       SET_V(m, acc, sum); \
+       acc = sum & 0xFF; \
+       SET_ZN(acc)
+
+static void Op89(void)                                                 // ADCA #
+{
+       uint16 m = READ_IMM;
+       OP_ADC_HANDLER(m, regs.a);
+}
+
+static void Op99(void)                                                 // ADCA ZP
+{
+       uint16 m = READ_ZP;
+       OP_ADC_HANDLER(m, regs.a);
+}
+
+static void OpA9(void)                                                 // ADCA ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_ADC_HANDLER(m, regs.a);
+}
+
+static void OpB9(void)                                                 // ADCA ABS
+{
+       uint16 m = READ_ABS;
+       OP_ADC_HANDLER(m, regs.a);
+}
+
+static void OpC9(void)                                                 // ADCB #
+{
+       uint16 m = READ_IMM;
+       OP_ADC_HANDLER(m, regs.b);
+}
+
+static void OpD9(void)                                                 // ADCB ZP
+{
+       uint16 m = READ_ZP;
+       OP_ADC_HANDLER(m, regs.b);
+}
+
+static void OpE9(void)                                                 // ADCB ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_ADC_HANDLER(m, regs.b);
+}
+
+static void OpF9(void)                                                 // ADCB ABS
+{
+       uint16 m = READ_ABS;
+       OP_ADC_HANDLER(m, regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+And                     |ANDA |84 2 2|94 3 2|A4 5 2|B4 4 3|      |A=A+M     |  TTR |
+                        |ANDB |C4 2 2|D4 3 2|E4 5 2|F4 4 3|      |B=B+M     |  TTR |
+*/
+
+// AND opcodes
+
+#define OP_AND_HANDLER(m, acc) \
+       acc &= m; \
+       SET_ZN(acc); \
+       CLR_V
+
+static void Op84(void)                                                 // ANDA #
+{
+       uint8 m = READ_IMM;
+       OP_AND_HANDLER(m, regs.a);
+}
+
+static void Op94(void)                                                 // ANDA ZP
+{
+       uint8 m = READ_ZP;
+       OP_AND_HANDLER(m, regs.a);
+}
+
+static void OpA4(void)                                                 // ANDA ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_AND_HANDLER(m, regs.a);
+}
+
+static void OpB4(void)                                                 // ANDA ABS
+{
+       uint16 m = READ_ABS;
+       OP_AND_HANDLER(m, regs.a);
+}
+
+static void OpC4(void)                                                 // ANDB #
+{
+       uint8 m = READ_IMM;
+       OP_AND_HANDLER(m, regs.b);
+}
+
+static void OpD4(void)                                                 // ANDB ZP
+{
+       uint8 m = READ_ZP;
+       OP_AND_HANDLER(m, regs.b);
+}
+
+static void OpE4(void)                                                 // ANDB ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_AND_HANDLER(m, regs.b);
+}
+
+static void OpF4(void)                                                 // ANDB ABS
+{
+       uint16 m = READ_ABS;
+       OP_AND_HANDLER(m, regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Bit Test                |BITA |85 2 2|95 3 2|A5 5 2|B5 4 3|      |A+M       |  TTR |
+                        |BITB |C5 2 2|D5 3 2|E5 5 2|F5 4 3|      |B+M       |  TTR |
+*/
+
+// BIT opcodes
+
+#define OP_BIT_HANDLER(m, acc) \
+       int8 result = acc & (m); \
+       SET_ZN(result)
+
+static void Op85(void)                                                 // BITA #
+{
+       uint8 m = READ_IMM;
+       OP_BIT_HANDLER(m, regs.a);
+}
+
+static void Op95(void)                                                 // BITA ZP
+{
+       uint8 m = READ_ZP;
+       OP_BIT_HANDLER(m, regs.a);
+}
+
+static void OpA5(void)                                                 // BITA ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_BIT_HANDLER(m, regs.a);
+}
+
+static void OpB5(void)                                                 // BITA ABS
+{
+       uint8 m = READ_ABS;
+       OP_BIT_HANDLER(m, regs.a);
+}
+
+static void OpC5(void)                                                 // BITB #
+{
+       uint8 m = READ_IMM;
+       OP_BIT_HANDLER(m, regs.b);
+}
+
+static void OpD5(void)                                                 // BITB ZP
+{
+       uint8 m = READ_ZP;
+       OP_BIT_HANDLER(m, regs.b);
+}
+
+static void OpE5(void)                                                 // BITB ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_BIT_HANDLER(m, regs.b);
+}
+
+static void OpF5(void)                                                 // BITB ABS
+{
+       uint8 m = READ_ABS;
+       OP_BIT_HANDLER(m, regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Clear                   |CLR  |      |      |6F 7 2|7F 6 3|      |M=00      |  RSRR|
+                        |CLRA |      |      |      |      |4F 2 1|A=00      |  RSRR|
+                        |CLRB |      |      |      |      |5F 2 1|B=00      |  RSRR|
+*/
+
+// CLR opcodes
+
+static void Op6F(void)                                                 // CLR ZP, X
+{
+       regs.WrMem(EA_ZP_X, 0);
+       CLR_NVC;
+       SET_Z(0);
+}
+
+static void Op7F(void)                                                 // CLR ABS
+{
+       regs.WrMem(EA_ABS, 0);
+       regs.pc += 2;
+       CLR_NVC;
+       SET_Z(0);
+}
+
+static void Op4F(void)                                                 // CLRA
+{
+       regs.a = 0;
+       CLR_NVC;
+       SET_Z(0);
+}
+
+static void Op5F(void)                                                 // CLRB
+{
+       regs.b = 0;
+       CLR_NVC;
+       SET_Z(0);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Compare                 |CMPA |81 2 2|91 3 2|A1 5 2|B1 4 3|      |A-M       |  TTTT|
+                        |CMPB |C1 2 2|D1 3 2|E1 5 2|F1 4 3|      |B-M       |  TTTT|
+Compare Accumulators    |CBA  |      |      |      |      |11 2 1|A-B       |  TTTT|
+*/
+
+// CMP opcodes
+
+/*
+Compare sets flags as if a subtraction had been carried out. If the value in the accumulator is equal or greater than the compared value, the Carry will be set. The equal (Z) and sign (S) flags will be set based on equality or lack thereof and the sign (i.e. A>=$80) of the accumulator.
+*/
+
+#define OP_CMP_HANDLER(m, acc) \
+       uint16 result = acc - (m); \
+       SET_ZNVC_CMP(m, acc, result)
+
+static void Op81(void)                                                 // CMPA #
+{
+       uint8 m = READ_IMM;
+       OP_CMP_HANDLER(m, regs.a);
+}
+
+static void Op91(void)                                                 // CMPA ZP
+{
+       uint8 m = READ_ZP;
+       OP_CMP_HANDLER(m, regs.a);
+}
+
+static void OpA1(void)                                                 // CMPA ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_CMP_HANDLER(m, regs.a);
+}
+
+static void OpB1(void)                                                 // CMPA ABS
+{
+       uint8 m = READ_ABS;
+       OP_CMP_HANDLER(m, regs.a);
+}
+
+static void OpC1(void)                                                 // CMPB #
+{
+       uint8 m = READ_IMM;
+       OP_CMP_HANDLER(m, regs.b);
+}
+
+static void OpD1(void)                                                 // CMPB ZP
+{
+       uint8 m = READ_ZP;
+       OP_CMP_HANDLER(m, regs.b);
+}
+
+static void OpE1(void)                                                 // CMPB ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_CMP_HANDLER(m, regs.b);
+}
+
+static void OpF1(void)                                                 // CMPB ABS
+{
+       uint8 m = READ_ABS;
+       OP_CMP_HANDLER(m, regs.b);
+}
+
+static void Op11(void)                                                 // CBA
+{
+       OP_CMP_HANDLER(regs.b, regs.a);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Complement 1's          |COM  |      |      |63 7 2|73 6 3|      |M=-M      |  TTRS|
+                        |COMA |      |      |      |      |43 2 1|A=-A      |  TTRS|
+                        |COMB |      |      |      |      |53 2 1|B=-B      |  TTRS|
+*/
+
+// COM opcodes
+
+#define OP_COM_HANDLER(m) \
+       m = m ^ 0xFF; \
+       SET_ZN(m); \
+       CLR_V; \
+       flagC = 1
+
+static void Op63(void)                                                 // COM ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_COM_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op73(void)                                                 // COM ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_COM_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op43(void)                                                 // COMA
+{
+       OP_COM_HANDLER(regs.a);
+}
+
+static void Op53(void)                                                 // COMB
+{
+       OP_COM_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Complement 2's          |NEG  |      |      |60 7 2|70 6 3|      |M=00-M    |  TT12|
+                        |NEGA |      |      |      |      |40 2 1|A=00-A    |  TT12|
+                        |NEGB |      |      |      |      |50 2 1|B=00-B    |  TT12|
+*/
+
+// NEG opcodes
+
+#define OP_NEG_HANDLER(m) \
+       m = -m; \
+       SET_ZN(m); \
+       flagV = (m == 0x80 ? 1 : 0); \
+       flagC = (m == 0x00 ? 1 : 0)
+
+static void Op60(void)                                                 // NEG ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_NEG_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op70(void)                                                 // NEG ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_NEG_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op40(void)                                                 // NEGA
+{
+       OP_NEG_HANDLER(regs.a);
+}
+
+static void Op50(void)                                                 // NEGB
+{
+       OP_NEG_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Decimal Adjust          |DAA  |      |      |      |      |19 2 1|*         |  TTT3|
+*/
+
+static void Op19(void)                                                 // DAA
+{
+       uint16 result = (uint16)regs.a;
+
+       if ((regs.a & 0x0F) > 0x09 || flagH)
+               result += 0x06;
+
+       if ((regs.a & 0xF0) > 0x90 || flagC || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
+               result += 0x60;
+
+       regs.a = (uint8)result;
+       SET_ZN(result);
+       CLR_V;                                                                          // Not sure this is correct...
+       flagC |= (result & 0x100) >> 8;                         // Overwrite carry if it was 0, otherwise, ignore
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Decrement               |DEC  |      |      |6A 7 2|7A 6 3|      |M=M-1     |  TT4 |
+                        |DECA |      |      |      |      |4A 2 1|A=A-1     |  TT4 |
+                        |DECB |      |      |      |      |5A 2 1|B=B-1     |  TT4 |
+*/
+
+// DEC opcodes
+
+#define OP_DEC_HANDLER(m) \
+       m--; \
+       SET_ZN(m); \
+       flagV = (m == 0x7F ? 1 : 0)
+
+static void Op6A(void)                                                 // DEC ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_DEC_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op7A(void)                                                 // DEC ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_DEC_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op4A(void)                                                 // DECA
+{
+       OP_DEC_HANDLER(regs.a);
+}
+
+static void Op5A(void)                                                 // DECB
+{
+       OP_DEC_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Exclusive OR            |EORA |88 2 2|98 3 2|A8 5 2|B8 4 3|      |A=A(+)M   |  TTR |
+                        |EORB |C8 2 2|D8 3 2|E8 5 2|F8 4 3|      |B=B(+)M   |  TTR |
+*/
+
+// EOR opcodes
+
+#define OP_EOR_HANDLER(m, acc) \
+       acc ^= m; \
+       SET_ZN(acc); \
+       CLR_V
+
+static void Op88(void)                                                 // EORA #
+{
+       uint8 m = READ_IMM;
+       OP_EOR_HANDLER(m, regs.a);
+}
+
+static void Op98(void)                                                 // EORA ZP
+{
+       uint8 m = READ_ZP;
+       OP_EOR_HANDLER(m, regs.a);
+}
+
+static void OpA8(void)                                                 // EORA ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_EOR_HANDLER(m, regs.a);
+}
+
+static void OpB8(void)                                                 // EORA ABS
+{
+       uint8 m = READ_ABS;
+       OP_EOR_HANDLER(m, regs.a);
+}
+
+static void OpC8(void)                                                 // EORB #
+{
+       uint8 m = READ_IMM;
+       OP_EOR_HANDLER(m, regs.b);
+}
+
+static void OpD8(void)                                                 // EORB ZP
+{
+       uint8 m = READ_ZP;
+       OP_EOR_HANDLER(m, regs.b);
+}
+
+static void OpE8(void)                                                 // EORB ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_EOR_HANDLER(m, regs.b);
+}
+
+static void OpF8(void)                                                 // EORB ABS
+{
+       uint8 m = READ_ABS;
+       OP_EOR_HANDLER(m, regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Increment               |INC  |      |      |6C 7 2|7C 6 3|      |M=M+1     |  TT5 |
+                        |INCA |      |      |      |      |4C 2 1|A=A+1     |  TT5 |
+                        |INCB |      |      |      |      |5C 2 1|B=B+1     |  TT5 |
+*/
+
+// INC opcodes
+
+#define OP_INC_HANDLER(m) \
+       m++; \
+       SET_ZN(m); \
+       flagV = (m == 0x80 ? 1 : 0)
+
+static void Op6C(void)                                                 // INC ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_INC_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op7C(void)                                                 // INC ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_INC_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op4C(void)                                                 // INCA
+{
+       OP_INC_HANDLER(regs.a);
+}
+
+static void Op5C(void)                                                 // INCB
+{
+       OP_INC_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Load Accumulator        |LDAA |86 2 2|96 3 2|A6 5 2|B6 4 3|      |A=M       |  TTR |
+                        |LDAB |C6 2 2|D6 3 2|E6 5 2|F6 4 3|      |B=M       |  TTR |
+*/
+
+// LDA opcodes
+
+#define OP_LDA_HANDLER(m, acc) \
+       acc = m; \
+       SET_ZN(acc); \
+       CLR_V
+
+static void Op86(void)                                                 // LDAA #
+{
+       uint8 m = READ_IMM;
+       OP_LDA_HANDLER(m, regs.a);
+}
+
+static void Op96(void)                                                 // LDAA ZP
+{
+       uint8 m = READ_ZP;
+       OP_LDA_HANDLER(m, regs.a);
+}
+
+static void OpA6(void)                                                 // LDAA ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_LDA_HANDLER(m, regs.a);
+}
+
+static void OpB6(void)                                                 // LDAA ABS
+{
+       uint8 m = READ_ABS;
+       OP_LDA_HANDLER(m, regs.a);
+}
+
+static void OpC6(void)                                                 // LDAB #
+{
+       uint8 m = READ_IMM;
+       OP_LDA_HANDLER(m, regs.b);
+}
+
+static void OpD6(void)                                                 // LDAB ZP
+{
+       uint8 m = READ_ZP;
+       OP_LDA_HANDLER(m, regs.b);
+}
+
+static void OpE6(void)                                                 // LDAB ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_LDA_HANDLER(m, regs.b);
+}
+
+static void OpF6(void)                                                 // LDAB ABS
+{
+       uint8 m = READ_ABS;
+       OP_LDA_HANDLER(m, regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+OR, Inclusive           |ORAA |8A 2 2|9A 3 2|AA 5 2|BA 4 3|      |A=A+M     |  TTR |
+                        |ORAB |CA 2 2|DA 3 2|EA 5 2|FA 4 3|      |B=B+M     |  TTR |
+*/
+
+// ORA opcodes
+
+#define OP_ORA_HANDLER(m, acc) \
+       acc |= m; \
+       SET_ZN(acc); \
+       CLR_V
+
+static void Op8A(void)                                                 // ORAA #
+{
+       uint8 m = READ_IMM;
+       OP_ORA_HANDLER(m, regs.a);
+}
+
+static void Op9A(void)                                                 // ORAA ZP
+{
+       uint8 m = READ_ZP;
+       OP_ORA_HANDLER(m, regs.a);
+}
+
+static void OpAA(void)                                                 // ORAA ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_ORA_HANDLER(m, regs.a);
+}
+
+static void OpBA(void)                                                 // ORAA ABS
+{
+       uint8 m = READ_ABS;
+       OP_ORA_HANDLER(m, regs.a);
+}
+
+static void OpCA(void)                                                 // ORAB #
+{
+       uint8 m = READ_IMM;
+       OP_ORA_HANDLER(m, regs.b);
+}
+
+static void OpDA(void)                                                 // ORAB ZP
+{
+       uint8 m = READ_ZP;
+       OP_ORA_HANDLER(m, regs.b);
+}
+
+static void OpEA(void)                                                 // ORAB ZP, X
+{
+       uint8 m = READ_ZP_X;
+       OP_ORA_HANDLER(m, regs.b);
+}
+
+static void OpFA(void)                                                 // ORAB ABS
+{
+       uint8 m = READ_ABS;
+       OP_ORA_HANDLER(m, regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Push Data               |PSHA |      |      |      |      |36 4 1|Msp=A, *- |      |
+                        |PSHB |      |      |      |      |37 4 1|Msp=B, *- |      |
+Pull Data               |PULA |      |      |      |      |32 4 1|A=Msp, *+ |      |
+                        |PULB |      |      |      |      |33 4 1|B=Msp, *+ |      |
+*/
+
+static void Op36(void)                                                 // PSHA
+{
+       PUSH(regs.a);
+}
+
+static void Op37(void)                                                 // PSHB
+{
+       PUSH(regs.b);
+}
+
+static void Op32(void)                                                 // PULA
+{
+       regs.a = PULL;
+}
+
+static void Op33(void)                                                 // PULB
+{
+       regs.b = PULL;
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Rotate Left             |ROL  |      |      |69 7 2|79 6 3|      |Memory  *1|  TT6T|
+                        |ROLA |      |      |      |      |49 2 1|Accum A *1|  TT6T|
+                        |ROLB |      |      |      |      |59 2 1|Accum B *1|  TT6T|
+*/
+
+// ROL opcodes
+
+#define OP_ROL_HANDLER(m) \
+       uint8 newCarry = (m & 0x80) >> 7; \
+       m = (m << 1) | flagC; \
+       SET_ZN(m); \
+       flagC = newCarry; \
+       flagV = flagN ^ flagC
+
+static void Op69(void)                                                 // ROL ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_ROL_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op79(void)                                                 // ROL ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_ROL_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op49(void)                                                 // ROLA
+{
+       OP_ROL_HANDLER(regs.a);
+}
+
+static void Op59(void)                                                 // ROLB
+{
+       OP_ROL_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Rotate Right            |ROR  |      |      |66 7 2|76 6 3|      |Memory  *2|  TT6T|
+                        |RORA |      |      |      |      |46 2 1|Accum A *2|  TT6T|
+                        |RORB |      |      |      |      |56 2 1|Accum B *2|  TT6T|
+*/
+
+// ROR opcodes
+
+#define OP_ROR_HANDLER(m) \
+       uint8 newCarry = m & 0x01; \
+       m = (m >> 1) | (flagC << 7); \
+       SET_ZN(m); \
+       flagC = newCarry; \
+       flagV = flagN ^ flagC
+
+static void Op66(void)                                                 // ROR ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_ROR_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op76(void)                                                 // ROR ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_ROR_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op46(void)                                                 // RORA
+{
+       OP_ROR_HANDLER(regs.a);
+}
+
+static void Op56(void)                                                 // RORB
+{
+       OP_ROR_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Arithmetic Shift Left   |ASL  |      |      |68 7 2|78 6 3|      |Memory  *3|  TT6T|
+                        |ASLA |      |      |      |      |48 2 1|Accum A *3|  TT6T|
+                        |ASLB |      |      |      |      |58 2 1|Accum B *3|  TT6T|
+*/
+
+// ASL opcodes
+
+#define OP_ASL_HANDLER(m) \
+       uint8 newCarry = (m & 0x80) >> 7; \
+       m <<= 1; \
+       SET_ZN(m); \
+       flagC = newCarry; \
+       flagV = flagN ^ flagC
+
+static void Op68(void)                                                 // ASL ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_ASL_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op78(void)                                                 // ASL ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_ASL_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op48(void)                                                 // ASLA
+{
+       OP_ASL_HANDLER(regs.a);
+}
+
+static void Op58(void)                                                 // ASLB
+{
+       OP_ASL_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Arithmetic Shift Right  |ASR  |      |      |67 7 2|77 6 3|      |Memory  *4|  TT6T|
+                        |ASRA |      |      |      |      |47 2 1|Accum A *4|  TT6T|
+                        |ASRB |      |      |      |      |57 2 1|Accum B *4|  TT6T|
+*/
+
+// ASR opcodes
+
+#define OP_ASR_HANDLER(m) \
+       uint8 newCarry = m & 0x01; \
+       m = (m >> 1) | (m & 0x80); \
+       SET_ZN(m); \
+       flagC = newCarry; \
+       flagV = flagN ^ flagC
+
+static void Op67(void)                                                 // ASR ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_ASR_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op77(void)                                                 // ASR ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_ASR_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op47(void)                                                 // ASRA
+{
+       OP_ASR_HANDLER(regs.a);
+}
+
+static void Op57(void)                                                 // ASRB
+{
+       OP_ASR_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Logic Shift Right       |LSR  |      |      |64 7 2|74 6 3|      |Memory  *5|  TT6T|
+                        |LSRA |      |      |      |      |44 2 1|Accum A *5|  TT6T|
+                        |LSRB |      |      |      |      |54 2 1|Accum B *5|  TT6T|
+*/
+
+// LSR opcodes
+
+#define OP_LSR_HANDLER(m) \
+       uint8 newCarry = m & 0x01; \
+       m >>= 1; \
+       SET_ZN(m); \
+       flagC = newCarry; \
+       flagV = flagN ^ flagC
+
+static void Op64(void)                                                 // LSR ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_LSR_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op74(void)                                                 // LSR ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_LSR_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op44(void)                                                 // LSRA
+{
+       OP_LSR_HANDLER(regs.a);
+}
+
+static void Op54(void)                                                 // LSRB
+{
+       OP_LSR_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Store Accumulator       |STAA |      |97 4 2|A7 6 2|B7 5 3|      |M=A       |  TTR |
+                        |STAB |      |D7 4 2|E7 6 2|F7 5 3|      |M=B       |  TTR |
+*/
+
+static void Op97(void)                                                 // STAA ZP
+{
+       regs.WrMem(EA_ZP, regs.a);
+}
+
+static void OpA7(void)                                                 // STAA ZP, X
+{
+       regs.WrMem(EA_ZP_X, regs.a);
+}
+
+static void OpB7(void)                                                 // STAA ABS
+{
+       regs.WrMem(EA_ABS, regs.a);
+       regs.pc += 2;
+}
+
+static void OpD7(void)                                                 // STAB ZP
+{
+       regs.WrMem(EA_ZP, regs.b);
+}
+
+static void OpE7(void)                                                 // STAB ZP, X
+{
+       regs.WrMem(EA_ZP_X, regs.b);
+}
+
+static void OpF7(void)                                                 // STAB ABS
+{
+       regs.WrMem(EA_ABS, regs.b);
+       regs.pc += 2;
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Subtract                |SUBA |80 2 2|90 3 2|A0 5 2|B0 4 3|      |A=A-M     |  TTTT|
+                        |SUBB |C0 2 2|D0 3 2|E0 5 2|F0 4 3|      |B=B-M     |  TTTT|
+Subtract Accumulators   |SBA  |      |      |      |      |10 2 1|A=A-B     |  TTTT|
+*/
+
+// SUB opcodes
+
+#define OP_SUB_HANDLER(m, acc) \
+       uint16 sum = (uint16)acc - (m); \
+       flagC = sum >> 15; \
+       SET_V(m, acc, sum); \
+       acc = (uint8)sum; \
+       SET_ZN(acc)
+
+static void Op80(void)                                                 // SUBA #
+{
+       uint16 m = READ_IMM;
+       OP_SUB_HANDLER(m, regs.a);
+}
+
+static void Op90(void)                                                 // SUBA ZP
+{
+       uint16 m = READ_ZP;
+       OP_SUB_HANDLER(m, regs.a);
+}
+
+static void OpA0(void)                                                 // SUBA ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_SUB_HANDLER(m, regs.a);
+}
+
+static void OpB0(void)                                                 // SUBA ABS
+{
+       uint16 m = READ_ABS;
+       OP_SUB_HANDLER(m, regs.a);
+}
+
+static void OpC0(void)                                                 // SUBB #
+{
+       uint16 m = READ_IMM;
+       OP_SUB_HANDLER(m, regs.b);
+}
+
+static void OpD0(void)                                                 // SUBB ZP
+{
+       uint16 m = READ_ZP;
+       OP_SUB_HANDLER(m, regs.b);
+}
+
+static void OpE0(void)                                                 // SUBB ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_SUB_HANDLER(m, regs.b);
+}
+
+static void OpF0(void)                                                 // SUBB ABS
+{
+       uint16 m = READ_ABS;
+       OP_SUB_HANDLER(m, regs.b);
+}
+
+static void Op10(void)                                                 // SBA
+{
+       OP_SUB_HANDLER(regs.b, regs.a);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Subtract with Carry     |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3|      |A=A-M-C   |  TTTT|
+                        |SBCB |C2 2 2|D2 3 2|E2 5 2|F2 4 3|      |B=B-M-C   |  TTTT|
+*/
+
+// SBC opcodes
+
+#define OP_SBC_HANDLER(m, acc) \
+       uint16 sum = (uint16)acc - (m) - (uint16)flagC; \
+       flagC = sum >> 15; \
+       SET_V(m, acc, sum); \
+       acc = (uint8)sum; \
+       SET_ZN(acc)
+
+static void Op82(void)                                                 // SBCA #
+{
+       uint16 m = READ_IMM;
+       OP_SBC_HANDLER(m, regs.a);
+}
+
+static void Op92(void)                                                 // SBCA ZP
+{
+       uint16 m = READ_ZP;
+       OP_SBC_HANDLER(m, regs.a);
+}
+
+static void OpA2(void)                                                 // SBCA ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_SBC_HANDLER(m, regs.a);
+}
+
+static void OpB2(void)                                                 // SBCA ABS
+{
+       uint16 m = READ_ABS;
+       OP_SBC_HANDLER(m, regs.a);
+}
+
+static void OpC2(void)                                                 // SBCB #
+{
+       uint16 m = READ_IMM;
+       OP_SBC_HANDLER(m, regs.b);
+}
+
+static void OpD2(void)                                                 // SBCB ZP
+{
+       uint16 m = READ_ZP;
+       OP_SBC_HANDLER(m, regs.b);
+}
+
+static void OpE2(void)                                                 // SBCB ZP, X
+{
+       uint16 m = READ_ZP_X;
+       OP_SBC_HANDLER(m, regs.b);
+}
+
+static void OpF2(void)                                                 // SBCB ABS
+{
+       uint16 m = READ_ABS;
+       OP_SBC_HANDLER(m, regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Transfer Accumulators   |TAB  |      |      |      |      |16 2 1|B=A       |  TTR |
+                        |TBA  |      |      |      |      |17 2 1|A=B       |  TTR |
+*/
+
+static void Op16(void)                                                 // TAB
+{
+       regs.b = regs.a;
+       SET_ZN(regs.b);
+       CLR_V;
+}
+
+static void Op17(void)                                                 // TBA
+{
+       regs.a = regs.b;
+       SET_ZN(regs.a);
+       CLR_V;
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Test, Zero/Minus        |TST  |      |      |6D 7 2|7D 6 3|      |M-00      |  TTRR|
+                        |TSTA |      |      |      |      |4D 2 1|A-00      |  TTRR|
+                        |TSTB |      |      |      |      |5D 2 1|B-00      |  TTRR|
+*/
+
+// TST opcodes
+
+#define OP_TST_HANDLER(m) \
+       SET_ZN(m); \
+       CLR_VC
+
+static void Op6D(void)                                                 // TST ZP, X
+{
+       uint8 m;
+       READ_ZP_X_WB(m);
+       OP_TST_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op7D(void)                                                 // TST ABS
+{
+       uint8 m;
+       READ_ABS_WB(m);
+       OP_TST_HANDLER(m);
+       WRITE_BACK(m);
+}
+
+static void Op4D(void)                                                 // TSTA
+{
+       OP_TST_HANDLER(regs.a);
+}
+
+static void Op5D(void)                                                 // TSTB
+{
+       OP_TST_HANDLER(regs.b);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Compare Index Register  |CPX  |8C 3 3|9C 4 2|AC 6 2|BC 5 3|      |Formula 1 |  7T8 |
+*/
+
+// CPX opcodes
+
+/*
+Compare sets flags as if a subtraction had been carried out. If the value in the X register is equal or greater than the compared value, the Carry will be set. The equal (Z) and sign (S) flags will be set based on equality or lack thereof and the sign (i.e. X>=$8000) of the X register.
+*/
+
+#define OP_CPX_HANDLER(m) \
+       uint32 result = regs.x - (m); \
+       SET_ZNVC_CMP16(m, regs.x, result)
+
+static void Op8C(void)                                                 // CPX #
+{
+       uint16 m = READ_IMM16;
+       OP_CPX_HANDLER(m);
+}
+
+static void Op9C(void)                                                 // CPX ZP
+{
+       uint16 m = READ_ZP16;
+       OP_CPX_HANDLER(m);
+}
+
+static void OpAC(void)                                                 // CPX ZP, X
+{
+       uint16 m = READ_ZP_X16;
+       OP_CPX_HANDLER(m);
+}
+
+static void OpBC(void)                                                 // CPX ABS
+{
+       uint16 m = READ_ABS16;
+       OP_CPX_HANDLER(m);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Decrement Index Register|DEX  |      |      |      |      |09 4 1|X=X-1     |   T  |
+Dec Stack Pointer       |DES  |      |      |      |      |34 4 1|SP=SP-1   |      |
+Inc Index Regster       |INX  |      |      |      |      |08 4 1|X=X+1     |   T  |
+Inc Stack Pointer       |INS  |      |      |      |      |31 4 1|SP=SP+1   |      |
+*/
+
+static void Op09(void)                                                 // DEX
+{
+       regs.x--;
+       SET_Z(regs.x);
+}
+
+static void Op34(void)                                                 // DES
+{
+       regs.s--;
+}
+
+static void Op08(void)                                                 // INX
+{
+       regs.x++;
+       SET_Z(regs.x);
+}
+
+static void Op31(void)                                                 // INS
+{
+       regs.s++;
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Load Index Register     |LDX  |CE 3 3|DE 4 2|EE 6 2|FE 5 3|      |Formula 2 |  9TR |
+Load Stack Pointer      |LDS  |8E 3 3|9E 4 2|AE 6 2|BE 5 3|      |Formula 3 |  9TR |
+*/
+
+// LD* opcode handler
+
+#define OP_LD_HANDLER(acc) \
+       SET_N16(acc); \
+       SET_Z(acc); \
+       CLR_V
+
+static void OpCE(void)                                                 // LDX #
+{
+       regs.x = READ_IMM16;
+       OP_LD_HANDLER(regs.x);
+}
+
+static void OpDE(void)                                                 // LDX ZP
+{
+       regs.x = READ_ZP16;
+       OP_LD_HANDLER(regs.x);
+}
+
+static void OpEE(void)                                                 // LDX ZP, X
+{
+       regs.x = READ_ZP_X16;
+       OP_LD_HANDLER(regs.x);
+}
+
+static void OpFE(void)                                                 // LDX ABS
+{
+       regs.x = READ_ABS16;
+       OP_LD_HANDLER(regs.x);
+}
+
+static void Op8E(void)                                                 // LDS #
+{
+       regs.s = READ_IMM16;
+       OP_LD_HANDLER(regs.s);
+}
+
+static void Op9E(void)                                                 // LDS ZP
+{
+       regs.s = READ_ZP16;
+       OP_LD_HANDLER(regs.s);
+}
+
+static void OpAE(void)                                                 // LDS ZP, X
+{
+       regs.s = READ_ZP_X16;
+       OP_LD_HANDLER(regs.s);
+}
+
+static void OpBE(void)                                                 // LDS ABS
+{
+       regs.s = READ_ABS16;
+       OP_LD_HANDLER(regs.s);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Store Index Register    |STX  |      |DF 5 2|EF 7 2|FF 6 3|      |Formula 4 |  9TR |
+Store Stack Pointer     |STS  |      |9F 5 2|AF 7 2|BF 6 3|      |Formula 5 |  9TR |
+*/
+
+// ST* opcode handler
+
+#define OP_ST_HANDLER(m, acc) \
+       regs.WrMem(m + 0, acc >> 8); \
+       regs.WrMem(m + 1, acc & 0xFF); \
+       SET_N16(acc); \
+       SET_Z(acc); \
+       CLR_V
+
+static void OpDF(void)                                                 // STX ZP
+{
+       uint16 m = EA_ZP;
+       OP_ST_HANDLER(m, regs.x);
+}
+
+static void OpEF(void)                                                 // STX ZP, X
+{
+       uint16 m = EA_ZP_X;
+       OP_ST_HANDLER(m, regs.x);
+}
+
+static void OpFF(void)                                                 // STX ABS
+{
+       uint16 m = EA_ABS;
+       regs.pc += 2;
+       OP_ST_HANDLER(m, regs.x);
+}
+
+static void Op9F(void)                                                 // STS ZP
+{
+       uint16 m = EA_ZP;
+       OP_ST_HANDLER(m, regs.s);
+}
+
+static void OpAF(void)                                                 // STS ZP, X
+{
+       uint16 m = EA_ZP_X;
+       OP_ST_HANDLER(m, regs.s);
+}
+
+static void OpBF(void)                                                 // STS ABS
+{
+       uint16 m = EA_ABS;
+       regs.pc += 2;
+       OP_ST_HANDLER(m, regs.s);
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Index Reg > Stack Pnter |TXS  |      |      |      |      |35 4 1|SP=X-1    |      |
+Stack Ptr > Index Regtr |TSX  |      |      |      |      |30 4 1|X=SP+1    |      |
+*/
+
+static void Op35(void)                                                 // TXS
+{
+       regs.s = regs.x - 1;
+}
+
+static void Op30(void)                                                 // TSX
+{
+       regs.x = regs.s + 1;
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Always                  |BRA  |      |20 4 2|      |      |      |none      |      |
+Carry is Clear          |BCC  |      |24 4 2|      |      |      |C=0       |      |
+Carry is Set            |BCS  |      |25 4 2|      |      |      |C=1       |      |
+Equals Zero             |BEQ  |      |27 4 2|      |      |      |Z=1       |      |
+Greater or Equal to Zero|BGE  |      |2C 4 2|      |      |      |N(+)V=0   |      |
+Greater than Zero       |BGT  |      |2E 4 2|      |      |      |Z+N(+)V=0 |      |
+Higher                  |BHI  |      |22 4 2|      |      |      |C+Z=0     |      |
+Less or Equal than Zero |BLE  |      |2F 4 2|      |      |      |Z+N(+)V=1 |      |
+Lower or Same           |BLS  |      |23 4 2|      |      |      |C+Z=1     |      |
+Less Than Zero          |BLT  |      |2D 4 2|      |      |      |N(+)V=1   |      |
+Minus                   |BMI  |      |2B 4 2|      |      |      |N=1       |      |
+Not Zero                |BNE  |      |26 4 2|      |      |      |Z=0       |      |
+Overflow Clear          |BVC  |      |28 4 2|      |      |      |V=0       |      |
+Overflow Set            |BVS  |      |29 4 2|      |      |      |V=1       |      |
+Plus                    |BPL  |      |2A 4 2|      |      |      |N=0       |      |
+*/
+
+static void Op20(void)                                                 // BRA
+{
+       int16 m = (int16)(int8)READ_IMM;
+       regs.pc += m;
+}
+
+static void Op24(void)                                                 // BCC
+{
+// NOTE: We can optimize this by following the maxim: "Don't branch!" by converting the boolean
+//       result into a multiplication. The only way to know if this is a win is to do some profiling
+//       both with and without the optimization.
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+//Note sure if the ! operator will do what we want, so we use ^ 1
+       regs.pc += m * (flagC ^ 0x01);
+#else
+       if (!flagC)
+               regs.pc += m;
+#endif
+}
+
+static void Op25(void)                                                 // BCS
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagC);
+#else
+       if (flagC)
+               regs.pc += m;
+#endif
+}
+
+static void Op27(void)                                                 // BEQ
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagZ);
+#else
+       if (flagZ)
+               regs.pc += m;
+#endif
+}
+
+static void Op2C(void)                                                 // BGE
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * ((flagN ^ flagV) ^ 0x01);
+#else
+       if (!(flagN ^ flagV))
+               regs.pc += m;
+#endif
+}
+
+static void Op2E(void)                                                 // BGT
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * ((flagZ | (flagN ^ flagV)) ^ 0x01);
+#else
+       if (!(flagZ | (flagN ^ flagV)))
+               regs.pc += m;
+#endif
+}
+
+static void Op22(void)                                                 // BHI
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * ((flagZ | flagC) ^ 0x01);
+#else
+       if (!(flagZ | flagC))
+               regs.pc += m;
+#endif
+}
+
+static void Op2F(void)                                                 // BLE
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagZ | (flagN ^ flagV));
+#else
+       if (flagZ | (flagN ^ flagV))
+               regs.pc += m;
+#endif
+}
+
+static void Op23(void)                                                 // BLS
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagZ | flagC);
+#else
+       if (flagZ | flagC)
+               regs.pc += m;
+#endif
+}
+
+static void Op2D(void)                                                 // BLT
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagN ^ flagV);
+#else
+       if (flagN ^ flagV)
+               regs.pc += m;
+#endif
+}
+
+static void Op2B(void)                                                 // BMI
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagN);
+#else
+       if (flagN)
+               regs.pc += m;
+#endif
+}
+
+static void Op26(void)                                                 // BNE
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagZ ^ 0x01);
+#else
+       if (!flagZ)
+               regs.pc += m;
+#endif
+}
+
+static void Op28(void)                                                 // BVC
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagV ^ 0x01);
+#else
+       if (!flagV)
+               regs.pc += m;
+#endif
+}
+
+static void Op29(void)                                                 // BVS
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagV);
+#else
+       if (flagV)
+               regs.pc += m;
+#endif
+}
+
+static void Op2A(void)                                                 // BPL
+{
+       int16 m = (int16)(int8)READ_IMM;
+
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+       regs.pc += m * (flagN ^ 0x01);
+#else
+       if (!flagN)
+               regs.pc += m;
+#endif
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Branch to Subroutine    |BSR  |      |8D 8 2|      |      |      |          |      |
+Jump                    |JMP  |      |      |6E 4 2|7E 3 3|      |          |      |
+Jump to Subroutine      |JSR  |      |      |AD 8 2|BD 9 3|      |          |      |
+*/
+
+static void Op8D(void)                                                 // BSR
+{
+       int16 m = (int16)(int8)READ_IMM;
+       PUSH16(regs.pc);
+       regs.pc += m;
+}
+
+static void Op6E(void)                                                 // JMP ZP, X
+{
+       regs.pc = EA_ZP_X;
+}
+
+static void Op7E(void)                                                 // JMP ABS
+{
+       regs.pc = EA_ABS;
+}
+
+static void OpAD(void)                                                 // JSR ZP, X
+{
+       uint16 m = EA_ZP_X;
+       PUSH16(regs.pc);
+       regs.pc = m;
+}
+
+static void OpBD(void)                                                 // JSR ABS
+{
+       uint16 m = EA_ABS;
+       regs.pc += 2;
+       PUSH16(regs.pc);
+       regs.pc = m;
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+No Operation            |NOP  |      |      |      |      |01 2 1|          |      |
+Return from Interrupt   |RTI  |      |      |      |      |3B A 1|          |AAAAAA|
+Return from Subroutine  |RTS  |      |      |      |      |39 5 1|          |      |
+Software Interrupt      |SWI  |      |      |      |      |3F C 1|          | S    |
+Wait For Interrupt      |WAI  |      |      |      |      |3E 9 1|          | B    |
+*/
+
+static void Op01(void)                                                 // NOP
+{
+}
+
+static void Op3B(void)                                                 // RTI
+{
+       regs.cc = PULL;
+       regs.a  = PULL;
+       regs.b  = PULL;
+       regs.x  = PULL16;
+       regs.pc = PULL16;
+       UNPACK_FLAGS;
+}
+
+static void Op39(void)                                                 // RTS
+{
+       regs.pc = PULL16;
+}
+
+static void Op3F(void)                                                 // SWI
+{
+       // It seems that the SWI is non-maskable, unlike the IRQ...
+       regs.cc = PACK_FLAGS;                                           // Mash flags back into the CC register
+       PUSH16(regs.pc);                                                        // Save all regs...
+       PUSH16(regs.x);
+       PUSH(regs.b);
+       PUSH(regs.a);
+       PUSH(regs.cc);
+       regs.pc = RdMemW(0xFFFA);                                       // And do it!
+       flagI = 1;                                                                      // Also, set IRQ inhibit
+}
+
+static void Op3E(void)                                                 // WAI
+{
+#ifdef __DEBUG__
+WriteLog("*** WAI STATE ASSERTED ***\n");
+#endif
+       regs.cc = PACK_FLAGS;                                           // Mash flags back into the CC register
+       PUSH16(regs.pc);                                                        // Save all regs...
+       PUSH16(regs.x);
+       PUSH(regs.b);
+       PUSH(regs.a);
+       PUSH(regs.cc);
+       regs.cpuFlags |= V6808_STATE_WAI;                       // And signal that we're in WAI mode
+}
+
+/*
+Operation               |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
+                        |     |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #|          |HINZVC|
+Clear Carry             |CLC  |      |      |      |      |0C 2 1|C=0       |     R|
+Clear Interrupt         |CLI  |      |      |      |      |0E 2 1|I=0       | R    |
+Clear Overflow          |CLV  |      |      |      |      |0A 2 1|V=0       |    R |
+Set Carry               |SEC  |      |      |      |      |0D 2 1|C=1       |     S|
+Set Interrupt           |SEI  |      |      |      |      |0F 2 1|I=1       | S    |
+Set Overflow            |SEV  |      |      |      |      |0B 2 1|V=1       |    S |
+CCR=Accumulator A       |TAP  |      |      |      |      |06 2 1|CCR=A     |CCCCCC|
+Accumlator A=CCR        |TPA  |      |      |      |      |07 2 1|A=CCR     |      |
+*/
+
+static void Op0C(void)                                                 // CLC
+{
+       flagC = 0;
+}
+
+static void Op0E(void)                                                 // CLI
+{
+       flagI = 0;
+}
+
+static void Op0A(void)                                                 // CLV
+{
+       flagV = 0;
+}
+
+static void Op0D(void)                                                 // SEC
+{
+       flagC = 1;
+}
+
+static void Op0F(void)                                                 // SEI
+{
+       flagI = 1;
+}
+
+static void Op0B(void)                                                 // SEV
+{
+       flagV = 1;
+}
+
+static void Op06(void)                                                 // TAP
+{
+       regs.cc = regs.a;
+       UNPACK_FLAGS;
+}
+
+static void Op07(void)                                                 // TPA
+{
+       regs.a = PACK_FLAGS;
+}
+
+/*
+  OP  Operation Code, in Hexadecimal
+  ~   Number of MPU cycles required
+  #   Number of program bytes required
+  +   Arithmetic Plus
+  -   Arithmetic Minus
+  +   Boolean AND
+  Msp Contents of Memory pointed to be Stack Pointer
+  +   Boolean Inclusive OR
+  (+) Boolean Exclusive OR (XOR)
+  *   Converts Binary Addition of BCD Characters into BCD Format
+  *-  SP=SP-1
+  *+  SP=SP+1
+
+  Condition Code Register Legend
+     Not Affected
+   R Reset (0, Low)
+   S Set   (1, High)
+   T Tests and sets if True, cleared otherise
+   1 Test: Result=10000000?
+   2 Test: Result=00000000?
+   3 Test: Decimal value of most significant BCD character greater than nine?
+           (Not cleared if previously set)
+   4 Test: Operand=10000000 prior to execution?
+   5 Test: Operand=01111111 prior to execution?
+   6 Test: Set equal to result or N(+)C after shift has occurred.
+   7 Test: Sign bit of most significant byte or result=1?
+   8 Test: 2's compliment overflow from subtraction of least
+           significant bytes?
+   9 Test: Result less than zero? (Bit 15=1)
+   A Load Condition Code Register from Stack.
+   B Set when interrupt occurs.  If previously set, a NMI is
+        required to exit the wait state.
+   C Set according to the contents of Accumulator A.
+
+  *x SHIFT AND ROTATION DIAGRAMS
+   *1     +-----------------+       C to LSB
+          - C <- 76543210 <-+
+
+   *2    +-----------------+
+         +> C -> 76543210 -+
+
+   *3       C <- 76543210 <- 0(Data)
+               +-+
+
+   *4          �>76543210 -> C
+
+   *5 (Data)0 -> 76543210 -> C
+
+  FORMULAS
+   1: (Xh/Xl)-(M/M+1)
+   2: Xh=M, Xl=M+1
+   3: SPh=M, SPl=M+1
+   4: M=Xh, M+1=Xl
+*/
+
+static void Op__(void)
+{
+       regs.cpuFlags |= V6808_STATE_ILLEGAL_INST;
+}
+
+
+//
+// Ok, the exec_op[] array is globally defined here basically to save
+// a LOT of unnecessary typing.  Sure it's ugly, but hey, it works!
+//
+void (* exec_op[256])() = {
+       Op__, Op01, Op__, Op__, Op__, Op__, Op06, Op07, Op08, Op09, Op0A, Op0B, Op0C, Op0D, Op0E, Op0F,
+       Op10, Op11, Op__, Op__, Op__, Op__, Op16, Op17, Op__, Op19, Op__, Op1B, Op__, Op__, Op__, Op__,
+       Op20, Op__, Op22, Op23, Op24, Op25, Op26, Op27, Op28, Op29, Op2A, Op2B, Op2C, Op2D, Op2E, Op2F,
+       Op30, Op31, Op32, Op33, Op34, Op35, Op36, Op37, Op__, Op39, Op__, Op3B, Op__, Op__, Op3E, Op3F,
+       Op40, Op__, Op__, Op43, Op44, Op__, Op46, Op47, Op48, Op49, Op4A, Op__, Op4C, Op4D, Op__, Op4F,
+       Op50, Op__, Op__, Op53, Op54, Op__, Op56, Op57, Op58, Op59, Op5A, Op__, Op5C, Op5D, Op__, Op5F,
+       Op60, Op__, Op__, Op63, Op64, Op__, Op66, Op67, Op68, Op69, Op6A, Op__, Op6C, Op6D, Op6E, Op6F,
+       Op70, Op__, Op__, Op73, Op74, Op__, Op76, Op77, Op78, Op79, Op7A, Op__, Op7C, Op7D, Op7E, Op7F,
+       Op80, Op81, Op82, Op__, Op84, Op85, Op86, Op__, Op88, Op89, Op8A, Op8B, Op8C, Op8D, Op8E, Op__,
+       Op90, Op91, Op92, Op__, Op94, Op95, Op96, Op97, Op98, Op99, Op9A, Op9B, Op9C, Op__, Op9E, Op9F,
+       OpA0, OpA1, OpA2, Op__, OpA4, OpA5, OpA6, OpA7, OpA8, OpA9, OpAA, OpAB, OpAC, OpAD, OpAE, OpAF,
+       OpB0, OpB1, OpB2, Op__, OpB4, OpB5, OpB6, OpB7, OpB8, OpB9, OpBA, OpBB, OpBC, OpBD, OpBE, OpBF,
+       OpC0, OpC1, OpC2, Op__, OpC4, OpC5, OpC6, Op__, OpC8, OpC9, OpCA, OpCB, Op__, Op__, OpCE, Op__,
+       OpD0, OpD1, OpD2, Op__, OpD4, OpD5, OpD6, OpD7, OpD8, OpD9, OpDA, OpDB, Op__, Op__, OpDE, OpDF,
+       OpE0, OpE1, OpE2, Op__, OpE4, OpE5, OpE6, OpE7, OpE8, OpE9, OpEA, OpEB, Op__, Op__, OpEE, OpEF,
+       OpF0, OpF1, OpF2, Op__, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, Op__, Op__, OpFE, OpFF
+};
+
+
+//
+// Internal "memcpy" (so we don't have to link with any external libraries!)
+//
+static void myMemcpy(void * dst, void * src, uint32 size)
+{
+       uint8 * d = (uint8 *)dst, * s = (uint8 *)src;
+
+       for(uint32 i=0; i<size; i++)
+               d[i] = s[i];
+}
+
+#ifdef __DEBUG__
+//int instCount[256];
+static bool logGo = false;
+#endif
+//
+// Function to execute 6808 for "cycles" cycles
+//
+void Execute6808(V6808REGS * context, uint32 cycles)
+{
+#warning "V6808_STATE_WAI is not properly handled yet! !!! FIX !!!"
+#warning "Need to convert from destructive clock to non-destructive. !!! FIX !!!"
+
+       myMemcpy(&regs, context, sizeof(V6808REGS));
+       UNPACK_FLAGS;                                                           // Explode flags register into individual uint8s
+
+       // Execute here...
+       while (regs.clock < cycles)
+       {
+#ifdef __DEBUG__
+if (logGo)
+       Decode6808(regs.pc);
+#endif
+               uint8 opcode = regs.RdMem(regs.pc++);
+
+#ifdef __DEBUG__
+//if (!(regs.cpuFlags & V6808_STATE_ILLEGAL_INST))
+//instCount[opcode]++;
+#endif
+
+               exec_op[opcode]();                                              // Execute that opcode...
+               regs.clock += CPUCycles[opcode];
+#ifdef __DEBUG__
+if (logGo)
+//     WriteLog(" [PC=%04X, S=%04X, X=%04X, A=%02X, B=%02X, CC=%s%s%s%s%s%s%s%s]\n", regs.pc, regs.s, regs.x, regs.a, regs.b, (regs.cc & FLAG_E ? "E" : " "), (regs.cc & FLAG_F ? "F" : " "), (regs.cc & FLAG_H ? "H" : " "), (regs.cc & FLAG_I ? "I" : " "), (regs.cc & FLAG_N ? "N" : " "), (regs.cc & FLAG_Z ? "Z" : " "), (regs.cc & FLAG_V ? "V" : " "), (regs.cc & FLAG_C ? "C" : " "));
+       WriteLog(" [PC=%04X, S=%04X, X=%04X, A=%02X, B=%02X, CC=%s%s%s%s%s%s%s%s]\n", regs.pc, regs.s, regs.x, regs.a, regs.b, (regs.cc & FLAG_E ? "E" : " "), (regs.cc & FLAG_F ? "F" : " "), (flagH ? "H" : " "), (flagI ? "I" : " "), (flagN ? "N" : " "), (flagZ ? "Z" : " "), (flagV ? "V" : " "), (flagC ? "C" : " "));
+#endif
+
+               if (regs.cpuFlags & V6808_ASSERT_LINE_RESET)
+               {
+#ifdef __DEBUG__
+WriteLog("*** RESET LINE ASSERTED ***\n");
+#endif
+                       flagI = 1;                                                      // Set I
+                       regs.pc = RdMemW(0xFFFE);                       // And load PC with the RESET vector
+
+                       context->cpuFlags &= ~V6808_ASSERT_LINE_RESET;
+                       regs.cpuFlags &= ~V6808_ASSERT_LINE_RESET;
+               }
+               else if (regs.cpuFlags & V6808_ASSERT_LINE_NMI)
+               {
+#ifdef __DEBUG__
+WriteLog("*** NMI LINE ASSERTED ***\n");
+#endif
+                       regs.cc = PACK_FLAGS;                           // Mash flags back into the CC register
+                       PUSH16(regs.pc);                                        // Save all regs...
+                       PUSH16(regs.x);
+                       PUSH(regs.b);
+                       PUSH(regs.a);
+                       PUSH(regs.cc);
+                       regs.pc = RdMemW(0xFFFC);                       // And do it!
+
+#warning "# of clock cycles for NMI unknown. !!! FIX !!!"
+                       regs.clock += 0;                                                        // How many???
+                       context->cpuFlags &= ~V6808_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
+                       regs.cpuFlags &= ~V6808_ASSERT_LINE_NMI;        // Reset the asserted line (NMI)...
+               }
+               else if (regs.cpuFlags & V6808_ASSERT_LINE_IRQ)
+               {
+#ifdef __DEBUG__
+WriteLog("*** IRQ LINE ASSERTED ***\n");
+#endif
+//                     if (!(regs.cc & FLAG_I))                        // Process an interrupt (I=0)?
+                       if (!flagI)                                                     // Process an interrupt (I=0)?
+                       {
+#ifdef __DEBUG__
+WriteLog("    IRQ TAKEN!\n");
+logGo = true;
+#endif
+                               regs.cc = PACK_FLAGS;                   // Mash flags back into the CC register
+                               PUSH16(regs.pc);                                // Save all regs...
+                               PUSH16(regs.x);
+                               PUSH(regs.b);
+                               PUSH(regs.a);
+                               PUSH(regs.cc);
+                               regs.pc = RdMemW(0xFFF8);               // And do it!
+
+#warning "# of clock cycles for IRQ unknown. !!! FIX !!!"
+                               regs.clock += 0;                                // How many???
+#warning "IRQ/NMI lines should not be cleared here... !!! FIX !!!"
+                               context->cpuFlags &= ~V6808_ASSERT_LINE_IRQ;    // Reset the asserted line (IRQ)...
+                               regs.cpuFlags &= ~V6808_ASSERT_LINE_IRQ;        // Reset the asserted line (IRQ)...
+                       }
+               }
+       }
+
+       regs.cc = PACK_FLAGS;                                           // Mash flags back into the CC register
+       myMemcpy(context, &regs, sizeof(V6808REGS));
+}
+
+//
+// Get the clock of the currently executing CPU
+//
+uint64 GetCurrentV6808Clock(void)
+{
+       return regs.clock;
+}
diff --git a/src/v6808.h b/src/v6808.h
new file mode 100755 (executable)
index 0000000..2b25aee
--- /dev/null
@@ -0,0 +1,55 @@
+//
+// Virtual 6808 Header file
+//
+// by James L. Hammons
+//
+// (C) 2006 Underground Software
+//
+
+#ifndef __V6808_H__
+#define __V6808_H__
+
+#include "types.h"
+
+// Useful defines
+
+#define FLAG_E         0x80            // ??? Entire ??? [No.]
+#define FLAG_F         0x40            // ??? Fast IRQ ??? [No.]
+#define FLAG_H         0x20            // Half carry
+#define FLAG_I         0x10            // IRQ
+#define FLAG_N         0x08            // Negative
+#define FLAG_Z         0x04            // Zero
+#define FLAG_V         0x02            // oVerflow
+#define FLAG_C         0x01            // Carry
+
+#define V6808_ASSERT_LINE_RESET                0x0001          // v6808 RESET line
+#define V6808_ASSERT_LINE_IRQ          0x0002          // v6808 IRQ line
+#define V6808_ASSERT_LINE_NMI          0x0004          // v6808 NMI line
+#define V6808_STATE_WAI                                0x0008          // v6808 wait for IRQ line
+#define V6808_STATE_ILLEGAL_INST       0x0010          // Illegal instruction executed flag
+//#define V6809_START_DEBUG_LOG                0x0020          // Debug log go (temporary!)
+
+// Useful structs
+
+struct V6808REGS
+{
+       uint16 pc;                                              // 6808 PC register
+       uint16 x;                                               // 6808 X index register
+       uint16 s;                                               // 6808 System stack pointer
+       uint8 cc;                                               // 6808 Condition Code register
+       uint8 a;                                                // 6808 A register
+       uint8 b;                                                // 6808 B register
+       uint64 clock;                                   // 6808 clock
+       uint8 (* RdMem)(uint16);                // Address of uint8 read routine
+       void (* WrMem)(uint16, uint8);  // Address of uint8 write routine
+       uint32 cpuFlags;                                // v6808 IRQ/RESET flags
+       uint32 clockOverrun;                    // Amount of overflow between runs
+};
+
+// Function prototypes
+
+void Execute6808(V6808REGS *, uint32); // Function to execute 6808 instructions
+uint64 GetCurrentV6808Clock(void);             // Get the clock of the currently executing CPU
+//uint8 GetCCRegister(void);                           // Hmm.
+
+#endif // __V6808_H__