summaryrefslogtreecommitdiffstats
path: root/lib/rbcodec/codecs/libasap/acpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libasap/acpu.c')
-rw-r--r--lib/rbcodec/codecs/libasap/acpu.c1291
1 files changed, 1291 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libasap/acpu.c b/lib/rbcodec/codecs/libasap/acpu.c
new file mode 100644
index 0000000000..0fd5988b83
--- /dev/null
+++ b/lib/rbcodec/codecs/libasap/acpu.c
@@ -0,0 +1,1291 @@
+/*
+ * acpu.c - another 6502 CPU emulator
+ *
+ * Copyright (C) 2007-2010 Piotr Fusik
+ *
+ * This file is part of ASAP (Another Slight Atari Player),
+ * see http://asap.sourceforge.net
+ *
+ * ASAP is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * ASAP is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ASAP; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* How 6502 registers are stored in this emulator:
+ All variables are int, because modern processors (and Java bytecode)
+ tend to operate more effectively on these type than narrower ones.
+ pc is really an unsigned 16-bit integer.
+ a, x, y and s are unsigned 8-bit integers.
+ Flags are decomposed into three variables for improved performance.
+ c is either 0 or 1.
+ nz contains 6502 flags N and Z.
+ N is set if (nz >= 0x80). Z is set if ((nz & 0xff) == 0).
+ Usually nz is simply assigned the unsigned 8-bit operation result.
+ There are just a few operations (ADC in decimal mode, BIT, PLP and RTI)
+ where both N and Z may be set. In these cases, N is reflected by the 8th
+ (not 7th) bit of nz.
+ vdi contains rarely used flags V, D and I, as a combination
+ of V_FLAG, D_FLAG and I_FLAG. Other vdi bits are clear.
+
+ "Unofficial" opcodes are not documented as "legal" 6502 opcodes.
+ Their operation has been reverse-engineered on Atari 800XL and Atari 65XE.
+ Unofficial opcodes are identical to C64's 6510, except for 0x8b and 0xab.
+ The operation of "unstable" opcodes is partially uncertain.
+ Explanation is welcome.
+
+ Emulation of POKEY timer interrupts is included.
+
+ Two preprocessor symbols may be used to strip the size of this emulator.
+ Define ACPU_NO_DECIMAL to disable emulation of the BCD mode.
+ Define ACPU_NO_UNOFFICIAL to disable emulation of unofficial opcodes. */
+
+#include "asap_internal.h"
+
+CONST_ARRAY(int, opcode_cycles)
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0x */
+ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1x */
+ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2x */
+ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3x */
+ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4x */
+ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5x */
+ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6x */
+ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7x */
+ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8x */
+ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9x */
+ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* Ax */
+ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* Bx */
+ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* Cx */
+ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* Dx */
+ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* Ex */
+ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* Fx */
+END_CONST_ARRAY;
+
+#ifdef ACPU_NO_DECIMAL
+
+#define DO_ADC \
+ { \
+ /* binary mode */ \
+ V(int, tmp) = a + data + c; \
+ vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
+ c = tmp >> 8; \
+ nz = a = tmp & 0xff; \
+ }
+
+#define DO_SBC \
+ { \
+ /* binary mode */ \
+ V(int, tmp) = a - data - 1 + c; \
+ vdi = (vdi & (D_FLAG | I_FLAG)) + ((((data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
+ c = (tmp >= 0) ? 1 : 0; \
+ nz = a = tmp & 0xff; \
+ }
+
+#else /* ACPU_NO_DECIMAL */
+
+#define DO_ADC \
+ { \
+ V(int, tmp) = a + data + c; \
+ nz = tmp & 0xff; \
+ if ((vdi & D_FLAG) == 0) { \
+ /* binary mode */ \
+ vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
+ c = tmp >> 8; \
+ a = nz; \
+ } \
+ else { \
+ /* decimal mode */ \
+ V(int, al) = (a & 0x0f) + (data & 0x0f) + c; \
+ if (al >= 10) \
+ tmp += (al < 26) ? 6 : -10; \
+ nz = ((tmp & 0x80) << 1) + (nz != 0 ? 1 : 0); \
+ vdi = (vdi & (D_FLAG | I_FLAG)) + (((~(data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
+ if (tmp >= 0xa0) { \
+ c = 1; \
+ a = (tmp + 0x60) & 0xff; \
+ } \
+ else { \
+ c = 0; \
+ a = tmp; \
+ } \
+ } \
+ }
+
+#define DO_SBC \
+ {\
+ V(int, tmp) = a - data - 1 + c; \
+ V(int, al) = (a & 0x0f) - (data & 0x0f) - 1 + c; \
+ vdi = (vdi & (D_FLAG | I_FLAG)) + ((((data ^ a) & (a ^ tmp)) >> 1) & V_FLAG); \
+ c = (tmp >= 0) ? 1 : 0; \
+ nz = a = tmp & 0xff; \
+ if ((vdi & D_FLAG) != 0) { \
+ /* decimal mode */ \
+ if (al < 0) \
+ a += (al < -10) ? 10 : -6; \
+ if (c == 0) \
+ a = (a - 0x60) & 0xff; \
+ } \
+ }
+
+#endif /* ACPU_NO_DECIMAL */
+
+#define zGetByte(addr) dGetByte((addr) & 0xff)
+
+#define PEEK dGetByte(pc)
+#define FETCH dGetByte(pc++)
+
+#define ABSOLUTE addr = FETCH; addr += FETCH << 8
+#define ABSOLUTE_X addr = FETCH; addr = (addr + (FETCH << 8) + x) & 0xffff
+#define ABSOLUTE_Y addr = FETCH; addr = (addr + (FETCH << 8) + y) & 0xffff
+#define ZPAGE addr = FETCH
+#define ZPAGE_X addr = (FETCH + x) & 0xff
+#define ZPAGE_Y addr = (FETCH + y) & 0xff
+#define INDIRECT_X addr = (FETCH + x) & 0xff; addr = dGetByte(addr) + (zGetByte(addr + 1) << 8)
+#define INDIRECT_Y addr = FETCH; addr = (dGetByte(addr) + (zGetByte(addr + 1) << 8) + y) & 0xffff
+#define NCYCLES_X if ((addr & 0xff) < x) ast _ cycle++
+#define NCYCLES_Y if ((addr & 0xff) < y) ast _ cycle++
+
+#define PL(dest) s = (s + 1) & 0xff; dest = dGetByte(0x0100 + s)
+#define PLP PL(vdi); nz = ((vdi & 0x80) << 1) + (~vdi & Z_FLAG); c = vdi & 1; vdi &= V_FLAG | D_FLAG | I_FLAG
+#define PH(data) dPutByte(0x0100 + s, data); s = (s - 1) & 0xff
+#define PHW(data) PH((data) >> 8); PH(TO_BYTE(data))
+#define PHP(bflag) PH(((nz | (nz >> 1)) & 0x80) + vdi + ((nz & 0xff) == 0 ? Z_FLAG : 0) + c + bflag)
+#define PHPB0 PHP(0x20) /* push flags with B flag clear (NMI, IRQ) */
+#define PHPB1 PHP(0x30) /* push flags with B flag set (PHP, BRK) */
+#define PHPC PHW(pc)
+
+#define LDA nz = a = GetByte(addr)
+#define LDA_ZP nz = a = dGetByte(addr)
+#define LDX nz = x = GetByte(addr)
+#define LDX_ZP nz = x = dGetByte(addr)
+#define LDY nz = y = GetByte(addr)
+#define LDY_ZP nz = y = dGetByte(addr)
+#define LAX nz = x = a = GetByte(addr)
+#define LAX_ZP nz = x = a = dGetByte(addr)
+#define STA PutByte(addr, a)
+#define STA_ZP dPutByte(addr, a)
+#define STX PutByte(addr, x)
+#define STX_ZP dPutByte(addr, x)
+#define STY PutByte(addr, y)
+#define STY_ZP dPutByte(addr, y)
+#define SAX data = a & x; PutByte(addr, data)
+#define SAX_ZP data = a & x; dPutByte(addr, data)
+#define CMP nz = GetByte(addr); c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
+#define CMP_ZP nz = dGetByte(addr); c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
+#define CPX nz = GetByte(addr); c = (x >= nz) ? 1 : 0; nz = (x - nz) & 0xff
+#define CPX_ZP nz = dGetByte(addr); c = (x >= nz) ? 1 : 0; nz = (x - nz) & 0xff
+#define CPY nz = GetByte(addr); c = (y >= nz) ? 1 : 0; nz = (y - nz) & 0xff
+#define CPY_ZP nz = dGetByte(addr); c = (y >= nz) ? 1 : 0; nz = (y - nz) & 0xff
+#define AND nz = a &= GetByte(addr)
+#define AND_ZP nz = a &= dGetByte(addr)
+#define ORA nz = a |= GetByte(addr)
+#define ORA_ZP nz = a |= dGetByte(addr)
+#define EOR nz = a ^= GetByte(addr)
+#define EOR_ZP nz = a ^= dGetByte(addr)
+#define ADC data = GetByte(addr); DO_ADC
+#define ADC_ZP data = dGetByte(addr); DO_ADC
+#define SBC data = GetByte(addr); DO_SBC
+#define SBC_ZP data = dGetByte(addr); DO_SBC
+
+#define ASL RMW_GetByte(nz, addr); c = nz >> 7; nz = (nz << 1) & 0xff; PutByte(addr, nz)
+#define ASL_ZP nz = dGetByte(addr); c = nz >> 7; nz = (nz << 1) & 0xff; dPutByte(addr, nz)
+#define ROL RMW_GetByte(nz, addr); nz = (nz << 1) + c; c = nz >> 8; nz &= 0xff; PutByte(addr, nz)
+#define ROL_ZP nz = dGetByte(addr); nz = (nz << 1) + c; c = nz >> 8; nz &= 0xff; dPutByte(addr, nz)
+#define LSR RMW_GetByte(nz, addr); c = nz & 1; nz >>= 1; PutByte(addr, nz)
+#define LSR_ZP nz = dGetByte(addr); c = nz & 1; nz >>= 1; dPutByte(addr, nz)
+#define ROR RMW_GetByte(nz, addr); nz += c << 8; c = nz & 1; nz >>= 1; PutByte(addr, nz)
+#define ROR_ZP nz = dGetByte(addr) + (c << 8); c = nz & 1; nz >>= 1; dPutByte(addr, nz)
+#define DEC RMW_GetByte(nz, addr); nz = (nz - 1) & 0xff; PutByte(addr, nz)
+#define DEC_ZP nz = dGetByte(addr); nz = (nz - 1) & 0xff; dPutByte(addr, nz)
+#define INC RMW_GetByte(nz, addr); nz = (nz + 1) & 0xff; PutByte(addr, nz)
+#define INC_ZP nz = dGetByte(addr); nz = (nz + 1) & 0xff; dPutByte(addr, nz)
+
+#define ASO ASL; nz = a |= nz
+#define ASO_ZP ASL_ZP; nz = a |= nz
+#define RLA ROL; nz = a &= nz
+#define RLA_ZP ROL_ZP; nz = a &= nz
+#define LSE LSR; nz = a ^= nz
+#define LSE_ZP LSR_ZP; nz = a ^= nz
+#define RRA ROR; data = nz; DO_ADC
+#define RRA_ZP ROR_ZP; data = nz; DO_ADC
+#define DCM DEC; c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
+#define DCM_ZP DEC_ZP; c = (a >= nz) ? 1 : 0; nz = (a - nz) & 0xff
+#define INS INC; data = nz; DO_SBC
+#define INS_ZP INC_ZP; data = nz; DO_SBC
+
+#define BRANCH(cond) \
+ if (cond) { \
+ addr = SBYTE(PEEK); \
+ pc++; \
+ addr += pc; \
+ if ((addr ^ pc) >> 8 != 0) \
+ ast _ cycle++; \
+ ast _ cycle++; \
+ pc = addr; \
+ break; \
+ } \
+ pc++; \
+ break
+
+#define CHECK_IRQ \
+ if ((vdi & I_FLAG) == 0 && ast _ irqst != 0xff) { \
+ PHPC; \
+ PHPB0; \
+ vdi |= I_FLAG; \
+ pc = dGetWord(0xfffe); \
+ ast _ cycle += 7; \
+ }
+
+/* Runs 6502 emulation for the specified number of Atari scanlines.
+ Each scanline is 114 cycles of which 9 is taken by ANTIC for memory refresh. */
+FUNC(void, Cpu_RunScanlines, (P(ASAP_State PTR, ast), P(int, scanlines)))
+{
+ /* copy registers from ASAP_State to local variables for improved performance */
+ V(int, pc);
+ V(int, nz);
+ V(int, a);
+ V(int, x);
+ V(int, y);
+ V(int, c);
+ V(int, s);
+ V(int, vdi);
+ V(int, next_event_cycle);
+ V(int, cycle_limit);
+ pc = ast _ cpu_pc;
+ nz = ast _ cpu_nz;
+ a = ast _ cpu_a;
+ x = ast _ cpu_x;
+ y = ast _ cpu_y;
+ c = ast _ cpu_c;
+ s = ast _ cpu_s;
+ vdi = ast _ cpu_vdi;
+ ast _ next_scanline_cycle = 114;
+ next_event_cycle = 114;
+ cycle_limit = 114 * scanlines;
+ if (next_event_cycle > ast _ timer1_cycle)
+ next_event_cycle = ast _ timer1_cycle;
+ if (next_event_cycle > ast _ timer2_cycle)
+ next_event_cycle = ast _ timer2_cycle;
+ if (next_event_cycle > ast _ timer4_cycle)
+ next_event_cycle = ast _ timer4_cycle;
+ ast _ nearest_event_cycle = next_event_cycle;
+ for (;;) {
+ V(int, cycle);
+ V(int, addr);
+ V(int, data);
+ cycle = ast _ cycle;
+ if (cycle >= ast _ nearest_event_cycle) {
+ if (cycle >= ast _ next_scanline_cycle) {
+ if (++ast _ scanline_number == (ast _ module_info->ntsc ? 262 : 312))
+ ast _ scanline_number = 0;
+ ast _ cycle = cycle += 9;
+ ast _ next_scanline_cycle += 114;
+ if (--scanlines <= 0)
+ break;
+ }
+ next_event_cycle = ast _ next_scanline_cycle;
+#define CHECK_TIMER_IRQ(ch) \
+ if (cycle >= ast _ timer##ch##_cycle) { \
+ ast _ irqst &= ~ch; \
+ ast _ timer##ch##_cycle = NEVER; \
+ } \
+ else if (next_event_cycle > ast _ timer##ch##_cycle) \
+ next_event_cycle = ast _ timer##ch##_cycle;
+ CHECK_TIMER_IRQ(1);
+ CHECK_TIMER_IRQ(2);
+ CHECK_TIMER_IRQ(4);
+ ast _ nearest_event_cycle = next_event_cycle;
+ CHECK_IRQ;
+ }
+#ifdef ASAPSCAN
+ if (cpu_trace != 0)
+ trace_cpu(ast, pc, a, x, y, s, nz, vdi, c);
+#endif
+ data = FETCH;
+ ast _ cycle += opcode_cycles[data];
+ switch (data) {
+ case 0x00: /* BRK */
+ pc++;
+ PHPC;
+ PHPB1;
+ vdi |= I_FLAG;
+ pc = dGetWord(0xfffe);
+ break;
+ case 0x01: /* ORA (ab,x) */
+ INDIRECT_X;
+ ORA;
+ break;
+ case 0x02: /* CIM [unofficial] */
+ case 0x12:
+ case 0x22:
+ case 0x32:
+ case 0x42:
+ case 0x52:
+ case 0x62:
+ case 0x72:
+ case 0x92:
+ case 0xb2:
+ case 0xd2:
+ case 0xf2:
+ ast _ scanline_number = (ast _ scanline_number + scanlines - 1) % (ast _ module_info->ntsc ? 262 : 312);
+ scanlines = 1;
+ ast _ cycle = cycle_limit;
+ break;
+#ifndef ACPU_NO_UNOFFICIAL
+ case 0x03: /* ASO (ab,x) [unofficial] */
+ INDIRECT_X;
+ ASO;
+ break;
+ case 0x04: /* NOP ab [unofficial] */
+ case 0x44:
+ case 0x64:
+ case 0x14: /* NOP ab,x [unofficial] */
+ case 0x34:
+ case 0x54:
+ case 0x74:
+ case 0xd4:
+ case 0xf4:
+ case 0x80: /* NOP #ab [unofficial] */
+ case 0x82:
+ case 0x89:
+ case 0xc2:
+ case 0xe2:
+ pc++;
+ break;
+ case 0x07: /* ASO ab [unofficial] */
+ ZPAGE;
+ ASO_ZP;
+ break;
+ case 0x0b: /* ANC #ab [unofficial] */
+ case 0x2b:
+ nz = a &= FETCH;
+ c = nz >> 7;
+ break;
+ case 0x0c: /* NOP abcd [unofficial] */
+ pc += 2;
+ break;
+ case 0x0f: /* ASO abcd [unofficial] */
+ ABSOLUTE;
+ ASO;
+ break;
+ case 0x13: /* ASO (ab),y [unofficial] */
+ INDIRECT_Y;
+ ASO;
+ break;
+ case 0x17: /* ASO ab,x [unofficial] */
+ ZPAGE_X;
+ ASO_ZP;
+ break;
+ case 0x1b: /* ASO abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ ASO;
+ break;
+ case 0x1c: /* NOP abcd,x [unofficial] */
+ case 0x3c:
+ case 0x5c:
+ case 0x7c:
+ case 0xdc:
+ case 0xfc:
+ if (FETCH + x >= 0x100)
+ ast _ cycle++;
+ pc++;
+ break;
+ case 0x1f: /* ASO abcd,x [unofficial] */
+ ABSOLUTE_X;
+ ASO;
+ break;
+ case 0x23: /* RLA (ab,x) [unofficial] */
+ INDIRECT_X;
+ RLA;
+ break;
+ case 0x27: /* RLA ab [unofficial] */
+ ZPAGE;
+ RLA_ZP;
+ break;
+ case 0x2f: /* RLA abcd [unofficial] */
+ ABSOLUTE;
+ RLA;
+ break;
+ case 0x33: /* RLA (ab),y [unofficial] */
+ INDIRECT_Y;
+ RLA;
+ break;
+ case 0x37: /* RLA ab,x [unofficial] */
+ ZPAGE_X;
+ RLA_ZP;
+ break;
+ case 0x3b: /* RLA abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ RLA;
+ break;
+ case 0x3f: /* RLA abcd,x [unofficial] */
+ ABSOLUTE_X;
+ RLA;
+ break;
+ case 0x43: /* LSE (ab,x) [unofficial] */
+ INDIRECT_X;
+ LSE;
+ break;
+ case 0x47: /* LSE ab [unofficial] */
+ ZPAGE;
+ LSE_ZP;
+ break;
+ case 0x4b: /* ALR #ab [unofficial] */
+ a &= FETCH;
+ c = a & 1;
+ nz = a >>= 1;
+ break;
+ case 0x4f: /* LSE abcd [unofficial] */
+ ABSOLUTE;
+ LSE;
+ break;
+ case 0x53: /* LSE (ab),y [unofficial] */
+ INDIRECT_Y;
+ LSE;
+ break;
+ case 0x57: /* LSE ab,x [unofficial] */
+ ZPAGE_X;
+ LSE_ZP;
+ break;
+ case 0x5b: /* LSE abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ LSE;
+ break;
+ case 0x5f: /* LSE abcd,x [unofficial] */
+ ABSOLUTE_X;
+ LSE;
+ break;
+ case 0x63: /* RRA (ab,x) [unofficial] */
+ INDIRECT_X;
+ RRA;
+ break;
+ case 0x67: /* RRA ab [unofficial] */
+ ZPAGE;
+ RRA_ZP;
+ break;
+ case 0x6b: /* ARR #ab [unofficial] */
+ data = a & FETCH;
+ nz = a = (data >> 1) + (c << 7);
+ vdi = (vdi & (D_FLAG | I_FLAG)) + ((a ^ data) & V_FLAG);
+#ifdef ACPU_NO_DECIMAL
+ c = data >> 7;
+#else
+ if ((vdi & D_FLAG) == 0)
+ c = data >> 7;
+ else {
+ if ((data & 0xf) >= 5)
+ a = (a & 0xf0) + ((a + 6) & 0xf);
+ if (data >= 0x50) {
+ a = (a + 0x60) & 0xff;
+ c = 1;
+ }
+ else
+ c = 0;
+ }
+#endif
+ break;
+ case 0x6f: /* RRA abcd [unofficial] */
+ ABSOLUTE;
+ RRA;
+ break;
+ case 0x73: /* RRA (ab),y [unofficial] */
+ INDIRECT_Y;
+ RRA;
+ break;
+ case 0x77: /* RRA ab,x [unofficial] */
+ ZPAGE_X;
+ RRA_ZP;
+ break;
+ case 0x7b: /* RRA abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ RRA;
+ break;
+ case 0x7f: /* RRA abcd,x [unofficial] */
+ ABSOLUTE_X;
+ RRA;
+ break;
+ case 0x83: /* SAX (ab,x) [unofficial] */
+ INDIRECT_X;
+ SAX;
+ break;
+ case 0x87: /* SAX ab [unofficial] */
+ ZPAGE;
+ SAX_ZP;
+ break;
+ case 0x8b: /* ANE #ab [unofficial] */
+ data = FETCH;
+ a &= x;
+ nz = a & data;
+ a &= data | 0xef;
+ break;
+ case 0x8f: /* SAX abcd [unofficial] */
+ ABSOLUTE;
+ SAX;
+ break;
+ case 0x93: /* SHA (ab),y [unofficial, unstable] */
+ ZPAGE;
+ data = zGetByte(addr + 1);
+ addr = (dGetByte(addr) + (data << 8) + y) & 0xffff;
+ data = a & x & (data + 1);
+ PutByte(addr, data);
+ break;
+ case 0x97: /* SAX ab,y [unofficial] */
+ ZPAGE_Y;
+ SAX_ZP;
+ break;
+ case 0x9b: /* SHS abcd,y [unofficial, unstable] */
+ /* S seems to be stable, only memory values vary */
+ addr = FETCH;
+ data = FETCH;
+ addr = (addr + (data << 8) + y) & 0xffff;
+ s = a & x;
+ data = s & (data + 1);
+ PutByte(addr, data);
+ break;
+ case 0x9c: /* SHY abcd,x [unofficial] */
+ addr = FETCH;
+ data = FETCH;
+ addr = (addr + (data << 8) + x) & 0xffff;
+ data = y & (data + 1);
+ PutByte(addr, data);
+ break;
+ case 0x9e: /* SHX abcd,y [unofficial] */
+ addr = FETCH;
+ data = FETCH;
+ addr = (addr + (data << 8) + y) & 0xffff;
+ data = x & (data + 1);
+ PutByte(addr, data);
+ break;
+ case 0x9f: /* SHA abcd,y [unofficial, unstable] */
+ addr = FETCH;
+ data = FETCH;
+ addr = (addr + (data << 8) + y) & 0xffff;
+ data = a & x & (data + 1);
+ PutByte(addr, data);
+ break;
+ case 0xa3: /* LAX (ab,x) [unofficial] */
+ INDIRECT_X;
+ LAX;
+ break;
+ case 0xa7: /* LAX ab [unofficial] */
+ ZPAGE;
+ LAX_ZP;
+ break;
+ case 0xab: /* ANX #ab [unofficial] */
+ nz = x = a &= FETCH;
+ break;
+ case 0xaf: /* LAX abcd [unofficial] */
+ ABSOLUTE;
+ LAX;
+ break;
+ case 0xb3: /* LAX (ab),y [unofficial] */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ LAX;
+ break;
+ case 0xb7: /* LAX ab,y [unofficial] */
+ ZPAGE_Y;
+ LAX_ZP;
+ break;
+ case 0xbb: /* LAS abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ nz = x = a = s &= GetByte(addr);
+ break;
+ case 0xbf: /* LAX abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ LAX;
+ break;
+ case 0xc3: /* DCM (ab,x) [unofficial] */
+ INDIRECT_X;
+ DCM;
+ break;
+ case 0xc7: /* DCM ab [unofficial] */
+ ZPAGE;
+ DCM_ZP;
+ break;
+ case 0xcb: /* SBX #ab [unofficial] */
+ nz = FETCH;
+ x &= a;
+ c = (x >= nz) ? 1 : 0;
+ nz = x = (x - nz) & 0xff;
+ break;
+ case 0xcf: /* DCM abcd [unofficial] */
+ ABSOLUTE;
+ DCM;
+ break;
+ case 0xd3: /* DCM (ab),y [unofficial] */
+ INDIRECT_Y;
+ DCM;
+ break;
+ case 0xd7: /* DCM ab,x [unofficial] */
+ ZPAGE_X;
+ DCM_ZP;
+ break;
+ case 0xdb: /* DCM abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ DCM;
+ break;
+ case 0xdf: /* DCM abcd,x [unofficial] */
+ ABSOLUTE_X;
+ DCM;
+ break;
+ case 0xe3: /* INS (ab,x) [unofficial] */
+ INDIRECT_X;
+ INS;
+ break;
+ case 0xe7: /* INS ab [unofficial] */
+ ZPAGE;
+ INS_ZP;
+ break;
+ case 0xef: /* INS abcd [unofficial] */
+ ABSOLUTE;
+ INS;
+ break;
+ case 0xf3: /* INS (ab),y [unofficial] */
+ INDIRECT_Y;
+ INS;
+ break;
+ case 0xf7: /* INS ab,x [unofficial] */
+ ZPAGE_X;
+ INS_ZP;
+ break;
+ case 0xfb: /* INS abcd,y [unofficial] */
+ ABSOLUTE_Y;
+ INS;
+ break;
+ case 0xff: /* INS abcd,x [unofficial] */
+ ABSOLUTE_X;
+ INS;
+ break;
+#endif /* ACPU_NO_UNOFFICIAL */
+ case 0x05: /* ORA ab */
+ ZPAGE;
+ ORA_ZP;
+ break;
+ case 0x06: /* ASL ab */
+ ZPAGE;
+ ASL_ZP;
+ break;
+ case 0x08: /* PHP */
+ PHPB1;
+ break;
+ case 0x09: /* ORA #ab */
+ nz = a |= FETCH;
+ break;
+ case 0x0a: /* ASL */
+ c = a >> 7;
+ nz = a = (a << 1) & 0xff;
+ break;
+ case 0x0d: /* ORA abcd */
+ ABSOLUTE;
+ ORA;
+ break;
+ case 0x0e: /* ASL abcd */
+ ABSOLUTE;
+ ASL;
+ break;
+ case 0x10: /* BPL */
+ BRANCH(nz < 0x80);
+ case 0x11: /* ORA (ab),y */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ ORA;
+ break;
+ case 0x15: /* ORA ab,x */
+ ZPAGE_X;
+ ORA_ZP;
+ break;
+ case 0x16: /* ASL ab,x */
+ ZPAGE_X;
+ ASL_ZP;
+ break;
+ case 0x18: /* CLC */
+ c = 0;
+ break;
+ case 0x19: /* ORA abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ ORA;
+ break;
+ case 0x1d: /* ORA abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ ORA;
+ break;
+ case 0x1e: /* ASL abcd,x */
+ ABSOLUTE_X;
+ ASL;
+ break;
+ case 0x20: /* JSR abcd */
+ addr = FETCH;
+ PHPC;
+ pc = addr + (PEEK << 8);
+ break;
+ case 0x21: /* AND (ab,x) */
+ INDIRECT_X;
+ AND;
+ break;
+ case 0x24: /* BIT ab */
+ ZPAGE;
+ nz = dGetByte(addr);
+ vdi = (vdi & (D_FLAG | I_FLAG)) + (nz & V_FLAG);
+ nz = ((nz & 0x80) << 1) + (nz & a);
+ break;
+ case 0x25: /* AND ab */
+ ZPAGE;
+ AND_ZP;
+ break;
+ case 0x26: /* ROL ab */
+ ZPAGE;
+ ROL_ZP;
+ break;
+ case 0x28: /* PLP */
+ PLP;
+ CHECK_IRQ;
+ break;
+ case 0x29: /* AND #ab */
+ nz = a &= FETCH;
+ break;
+ case 0x2a: /* ROL */
+ a = (a << 1) + c;
+ c = a >> 8;
+ nz = a &= 0xff;
+ break;
+ case 0x2c: /* BIT abcd */
+ ABSOLUTE;
+ nz = GetByte(addr);
+ vdi = (vdi & (D_FLAG | I_FLAG)) + (nz & V_FLAG);
+ nz = ((nz & 0x80) << 1) + (nz & a);
+ break;
+ case 0x2d: /* AND abcd */
+ ABSOLUTE;
+ AND;
+ break;
+ case 0x2e: /* ROL abcd */
+ ABSOLUTE;
+ ROL;
+ break;
+ case 0x30: /* BMI */
+ BRANCH(nz >= 0x80);
+ case 0x31: /* AND (ab),y */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ AND;
+ break;
+ case 0x35: /* AND ab,x */
+ ZPAGE_X;
+ AND_ZP;
+ break;
+ case 0x36: /* ROL ab,x */
+ ZPAGE_X;
+ ROL_ZP;
+ break;
+ case 0x38: /* SEC */
+ c = 1;
+ break;
+ case 0x39: /* AND abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ AND;
+ break;
+ case 0x3d: /* AND abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ AND;
+ break;
+ case 0x3e: /* ROL abcd,x */
+ ABSOLUTE_X;
+ ROL;
+ break;
+ case 0x40: /* RTI */
+ PLP;
+ PL(pc);
+ PL(addr);
+ pc += addr << 8;
+ CHECK_IRQ;
+ break;
+ case 0x41: /* EOR (ab,x) */
+ INDIRECT_X;
+ EOR;
+ break;
+ case 0x45: /* EOR ab */
+ ZPAGE;
+ EOR_ZP;
+ break;
+ case 0x46: /* LSR ab */
+ ZPAGE;
+ LSR_ZP;
+ break;
+ case 0x48: /* PHA */
+ PH(a);
+ break;
+ case 0x49: /* EOR #ab */
+ nz = a ^= FETCH;
+ break;
+ case 0x4a: /* LSR */
+ c = a & 1;
+ nz = a >>= 1;
+ break;
+ case 0x4c: /* JMP abcd */
+ addr = FETCH;
+ pc = addr + (PEEK << 8);
+ break;
+ case 0x4d: /* EOR abcd */
+ ABSOLUTE;
+ EOR;
+ break;
+ case 0x4e: /* LSR abcd */
+ ABSOLUTE;
+ LSR;
+ break;
+ case 0x50: /* BVC */
+ BRANCH((vdi & V_FLAG) == 0);
+ case 0x51: /* EOR (ab),y */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ EOR;
+ break;
+ case 0x55: /* EOR ab,x */
+ ZPAGE_X;
+ EOR_ZP;
+ break;
+ case 0x56: /* LSR ab,x */
+ ZPAGE_X;
+ LSR_ZP;
+ break;
+ case 0x58: /* CLI */
+ vdi &= V_FLAG | D_FLAG;
+ CHECK_IRQ;
+ break;
+ case 0x59: /* EOR abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ EOR;
+ break;
+ case 0x5d: /* EOR abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ EOR;
+ break;
+ case 0x5e: /* LSR abcd,x */
+ ABSOLUTE_X;
+ LSR;
+ break;
+ case 0x60: /* RTS */
+ PL(pc);
+ PL(addr);
+ pc += (addr << 8) + 1;
+ break;
+ case 0x61: /* ADC (ab,x) */
+ INDIRECT_X;
+ ADC;
+ break;
+ case 0x65: /* ADC ab */
+ ZPAGE;
+ ADC_ZP;
+ break;
+ case 0x66: /* ROR ab */
+ ZPAGE;
+ ROR_ZP;
+ break;
+ case 0x68: /* PLA */
+ PL(a);
+ nz = a;
+ break;
+ case 0x69: /* ADC #ab */
+ data = FETCH;
+ DO_ADC;
+ break;
+ case 0x6a: /* ROR */
+ nz = (c << 7) + (a >> 1);
+ c = a & 1;
+ a = nz;
+ break;
+ case 0x6c: /* JMP (abcd) */
+ ABSOLUTE;
+ if ((addr & 0xff) == 0xff)
+ pc = (dGetByte(addr - 0xff) << 8) + dGetByte(addr);
+ else
+ pc = dGetWord(addr);
+ break;
+ case 0x6d: /* ADC abcd */
+ ABSOLUTE;
+ ADC;
+ break;
+ case 0x6e: /* ROR abcd */
+ ABSOLUTE;
+ ROR;
+ break;
+ case 0x70: /* BVS */
+ BRANCH((vdi & V_FLAG) != 0);
+ case 0x71: /* ADC (ab),y */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ ADC;
+ break;
+ case 0x75: /* ADC ab,x */
+ ZPAGE_X;
+ ADC_ZP;
+ break;
+ case 0x76: /* ROR ab,x */
+ ZPAGE_X;
+ ROR_ZP;
+ break;
+ case 0x78: /* SEI */
+ vdi |= I_FLAG;
+ break;
+ case 0x79: /* ADC abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ ADC;
+ break;
+ case 0x7d: /* ADC abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ ADC;
+ break;
+ case 0x7e: /* ROR abcd,x */
+ ABSOLUTE_X;
+ ROR;
+ break;
+ case 0x81: /* STA (ab,x) */
+ INDIRECT_X;
+ STA;
+ break;
+ case 0x84: /* STY ab */
+ ZPAGE;
+ STY_ZP;
+ break;
+ case 0x85: /* STA ab */
+ ZPAGE;
+ STA_ZP;
+ break;
+ case 0x86: /* STX ab */
+ ZPAGE;
+ STX_ZP;
+ break;
+ case 0x88: /* DEY */
+ nz = y = (y - 1) & 0xff;
+ break;
+ case 0x8a: /* TXA */
+ nz = a = x;
+ break;
+ case 0x8c: /* STY abcd */
+ ABSOLUTE;
+ STY;
+ break;
+ case 0x8d: /* STA abcd */
+ ABSOLUTE;
+ STA;
+ break;
+ case 0x8e: /* STX abcd */
+ ABSOLUTE;
+ STX;
+ break;
+ case 0x90: /* BCC */
+ BRANCH(c == 0);
+ case 0x91: /* STA (ab),y */
+ INDIRECT_Y;
+ STA;
+ break;
+ case 0x94: /* STY ab,x */
+ ZPAGE_X;
+ STY_ZP;
+ break;
+ case 0x95: /* STA ab,x */
+ ZPAGE_X;
+ STA_ZP;
+ break;
+ case 0x96: /* STX ab,y */
+ ZPAGE_Y;
+ STX_ZP;
+ break;
+ case 0x98: /* TYA */
+ nz = a = y;
+ break;
+ case 0x99: /* STA abcd,y */
+ ABSOLUTE_Y;
+ STA;
+ break;
+ case 0x9a: /* TXS */
+ s = x;
+ break;
+ case 0x9d: /* STA abcd,x */
+ ABSOLUTE_X;
+ STA;
+ break;
+ case 0xa0: /* LDY #ab */
+ nz = y = FETCH;
+ break;
+ case 0xa1: /* LDA (ab,x) */
+ INDIRECT_X;
+ LDA;
+ break;
+ case 0xa2: /* LDX #ab */
+ nz = x = FETCH;
+ break;
+ case 0xa4: /* LDY ab */
+ ZPAGE;
+ LDY_ZP;
+ break;
+ case 0xa5: /* LDA ab */
+ ZPAGE;
+ LDA_ZP;
+ break;
+ case 0xa6: /* LDX ab */
+ ZPAGE;
+ LDX_ZP;
+ break;
+ case 0xa8: /* TAY */
+ nz = y = a;
+ break;
+ case 0xa9: /* LDA #ab */
+ nz = a = FETCH;
+ break;
+ case 0xaa: /* TAX */
+ nz = x = a;
+ break;
+ case 0xac: /* LDY abcd */
+ ABSOLUTE;
+ LDY;
+ break;
+ case 0xad: /* LDA abcd */
+ ABSOLUTE;
+ LDA;
+ break;
+ case 0xae: /* LDX abcd */
+ ABSOLUTE;
+ LDX;
+ break;
+ case 0xb0: /* BCS */
+ BRANCH(c != 0);
+ case 0xb1: /* LDA (ab),y */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ LDA;
+ break;
+ case 0xb4: /* LDY ab,x */
+ ZPAGE_X;
+ LDY_ZP;
+ break;
+ case 0xb5: /* LDA ab,x */
+ ZPAGE_X;
+ LDA_ZP;
+ break;
+ case 0xb6: /* LDX ab,y */
+ ZPAGE_Y;
+ LDX_ZP;
+ break;
+ case 0xb8: /* CLV */
+ vdi &= D_FLAG | I_FLAG;
+ break;
+ case 0xb9: /* LDA abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ LDA;
+ break;
+ case 0xba: /* TSX */
+ nz = x = s;
+ break;
+ case 0xbc: /* LDY abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ LDY;
+ break;
+ case 0xbd: /* LDA abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ LDA;
+ break;
+ case 0xbe: /* LDX abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ LDX;
+ break;
+ case 0xc0: /* CPY #ab */
+ nz = FETCH;
+ c = (y >= nz) ? 1 : 0;
+ nz = (y - nz) & 0xff;
+ break;
+ case 0xc1: /* CMP (ab,x) */
+ INDIRECT_X;
+ CMP;
+ break;
+ case 0xc4: /* CPY ab */
+ ZPAGE;
+ CPY_ZP;
+ break;
+ case 0xc5: /* CMP ab */
+ ZPAGE;
+ CMP_ZP;
+ break;
+ case 0xc6: /* DEC ab */
+ ZPAGE;
+ DEC_ZP;
+ break;
+ case 0xc8: /* INY */
+ nz = y = (y + 1) & 0xff;
+ break;
+ case 0xc9: /* CMP #ab */
+ nz = FETCH;
+ c = (a >= nz) ? 1 : 0;
+ nz = (a - nz) & 0xff;
+ break;
+ case 0xca: /* DEX */
+ nz = x = (x - 1) & 0xff;
+ break;
+ case 0xcc: /* CPY abcd */
+ ABSOLUTE;
+ CPY;
+ break;
+ case 0xcd: /* CMP abcd */
+ ABSOLUTE;
+ CMP;
+ break;
+ case 0xce: /* DEC abcd */
+ ABSOLUTE;
+ DEC;
+ break;
+ case 0xd0: /* BNE */
+ BRANCH((nz & 0xff) != 0);
+ case 0xd1: /* CMP (ab),y */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ CMP;
+ break;
+ case 0xd5: /* CMP ab,x */
+ ZPAGE_X;
+ CMP_ZP;
+ break;
+ case 0xd6: /* DEC ab,x */
+ ZPAGE_X;
+ DEC_ZP;
+ break;
+ case 0xd8: /* CLD */
+ vdi &= V_FLAG | I_FLAG;
+ break;
+ case 0xd9: /* CMP abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ CMP;
+ break;
+ case 0xdd: /* CMP abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ CMP;
+ break;
+ case 0xde: /* DEC abcd,x */
+ ABSOLUTE_X;
+ DEC;
+ break;
+ case 0xe0: /* CPX #ab */
+ nz = FETCH;
+ c = (x >= nz) ? 1 : 0;
+ nz = (x - nz) & 0xff;
+ break;
+ case 0xe1: /* SBC (ab,x) */
+ INDIRECT_X;
+ SBC;
+ break;
+ case 0xe4: /* CPX ab */
+ ZPAGE;
+ CPX_ZP;
+ break;
+ case 0xe5: /* SBC ab */
+ ZPAGE;
+ SBC_ZP;
+ break;
+ case 0xe6: /* INC ab */
+ ZPAGE;
+ INC_ZP;
+ break;
+ case 0xe8: /* INX */
+ nz = x = (x + 1) & 0xff;
+ break;
+ case 0xe9: /* SBC #ab */
+ case 0xeb: /* SBC #ab [unofficial] */
+ data = FETCH;
+ DO_SBC;
+ break;
+ case 0xea: /* NOP */
+ case 0x1a: /* NOP [unofficial] */
+ case 0x3a:
+ case 0x5a:
+ case 0x7a:
+ case 0xda:
+ case 0xfa:
+ break;
+ case 0xec: /* CPX abcd */
+ ABSOLUTE;
+ CPX;
+ break;
+ case 0xed: /* SBC abcd */
+ ABSOLUTE;
+ SBC;
+ break;
+ case 0xee: /* INC abcd */
+ ABSOLUTE;
+ INC;
+ break;
+ case 0xf0: /* BEQ */
+ BRANCH((nz & 0xff) == 0);
+ case 0xf1: /* SBC (ab),y */
+ INDIRECT_Y;
+ NCYCLES_Y;
+ SBC;
+ break;
+ case 0xf5: /* SBC ab,x */
+ ZPAGE_X;
+ SBC_ZP;
+ break;
+ case 0xf6: /* INC ab,x */
+ ZPAGE_X;
+ INC_ZP;
+ break;
+ case 0xf8: /* SED */
+ vdi |= D_FLAG;
+ break;
+ case 0xf9: /* SBC abcd,y */
+ ABSOLUTE_Y;
+ NCYCLES_Y;
+ SBC;
+ break;
+ case 0xfd: /* SBC abcd,x */
+ ABSOLUTE_X;
+ NCYCLES_X;
+ SBC;
+ break;
+ case 0xfe: /* INC abcd,x */
+ ABSOLUTE_X;
+ INC;
+ break;
+ }
+ }
+ ast _ cpu_pc = pc;
+ ast _ cpu_nz = nz;
+ ast _ cpu_a = a;
+ ast _ cpu_x = x;
+ ast _ cpu_y = y;
+ ast _ cpu_c = c;
+ ast _ cpu_s = s;
+ ast _ cpu_vdi = vdi;
+ ast _ cycle -= cycle_limit;
+ if (ast _ timer1_cycle != NEVER)
+ ast _ timer1_cycle -= cycle_limit;
+ if (ast _ timer2_cycle != NEVER)
+ ast _ timer2_cycle -= cycle_limit;
+ if (ast _ timer4_cycle != NEVER)
+ ast _ timer4_cycle -= cycle_limit;
+}