rockbox/apps/codecs/libasap/acpu.c

1263 lines
27 KiB
C
Raw Normal View History

/*
* acpu.c - another 6502 CPU emulator
*
* Copyright (C) 2007-2008 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
*/
#include "asap_internal.h"
CONST_LOOKUP(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 */
};
#define DO_ADC \
if ((vdi & D_FLAG) == 0) { \
/* binary mode */ \
int tmp = a + data + c; \
c = tmp >> 8; \
vdi &= D_FLAG | I_FLAG; \
if (((a ^ data) & 0x80) == 0 && ((data ^ tmp) & 0x80) != 0) \
vdi += V_FLAG; \
nz = a = tmp & 0xff; \
} \
else { \
/* decimal mode */ \
int tmp = (a & 0x0f) + (data & 0x0f) + c; \
if (tmp >= 10) \
tmp = (tmp - 10) | 0x10; \
tmp += (a & 0xf0) + (data & 0xf0); \
nz = ((tmp & 0x80) << 1) + ((a + data + c) & 0xff); \
vdi &= D_FLAG | I_FLAG; \
if (((a ^ data) & 0x80) == 0 && ((data ^ tmp) & 0x80) != 0) \
vdi += V_FLAG; \
if (tmp > 0x9f) \
tmp += 0x60; \
c = (tmp > 0xff) ? 1 : 0; \
a = tmp & 0xff; \
}
#define DO_SBC \
if ((vdi & D_FLAG) == 0) { \
/* binary mode */ \
int tmp = a - data - 1 + c; \
c = (tmp >= 0) ? 1 : 0; \
vdi &= D_FLAG | I_FLAG; \
if (((a ^ tmp) & 0x80) != 0 && ((a ^ data) & 0x80) != 0) \
vdi += V_FLAG; \
nz = a = tmp & 0xff; \
} \
else { \
/* decimal mode */ \
int tmp = a - data - 1 + c; \
int al = (a & 0x0f) - (data & 0x0f) - 1 + c; \
int ah = (a >> 4) - (data >> 4); \
if ((al & 0x10) != 0) { \
al -= 6; \
ah--; \
} \
if ((ah & 0x10) != 0) \
ah -= 6; \
c = tmp >= 0 ? 1 : 0; \
vdi &= D_FLAG | I_FLAG; \
if (((a ^ tmp) & 0x80) != 0 && ((a ^ data) & 0x80) != 0) \
vdi += V_FLAG; \
nz = tmp & 0xff; \
a = ((ah & 0xf) << 4) + (al & 0x0f); \
}
#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(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); \
if (c == 0) { \
c = nz & 1; \
nz >>= 1; \
} \
else { \
c = nz & 1; \
nz = (nz >> 1) + 128; \
} \
PutByte(addr, nz)
#define ROR_ZP \
nz = dGetByte(addr); \
if (c == 0) { \
c = nz & 1; \
nz >>= 1; \
} \
else { \
c = nz & 1; \
nz = (nz >> 1) + 128; \
} \
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(FETCH); \
addr += pc; \
if (((addr ^ pc) & 0xff00) != 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; \
}
ASAP_FUNC void Cpu_RunScanlines(ASAP_State PTR ast, int scanlines)
{
int pc;
int nz;
int a;
int x;
int y;
int c;
int s;
int vdi;
int next_event_cycle;
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 (;;) {
int cycle;
int addr;
int data;
cycle = AST cycle;
if (cycle >= AST nearest_event_cycle) {
if (cycle >= AST next_scanline_cycle) {
if (++AST scanline_number == 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)
print_cpu_state(as, 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) % 312;
scanlines = 1;
AST cycle = cycle_limit;
break;
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 0x05: /* ORA ab */
ZPAGE;
ORA_ZP;
break;
case 0x06: /* ASL ab */
ZPAGE;
ASL_ZP;
break;
case 0x07: /* ASO ab [unofficial] */
ZPAGE;
ASO_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 0x0b: /* ANC #ab [unofficial] */
case 0x2b:
nz = a &= FETCH;
c = nz >> 7;
break;
case 0x0c: /* NOP abcd [unofficial] */
pc += 2;
break;
case 0x0d: /* ORA abcd */
ABSOLUTE;
ORA;
break;
case 0x0e: /* ASL abcd */
ABSOLUTE;
ASL;
break;
case 0x0f: /* ASO abcd [unofficial] */
ABSOLUTE;
ASO;
break;
case 0x10: /* BPL */
BRANCH(nz < 0x80);
case 0x11: /* ORA (ab),y */
INDIRECT_Y;
NCYCLES_Y;
ORA;
break;
case 0x13: /* ASO (ab),y [unofficial] */
INDIRECT_Y;
ASO;
break;
case 0x15: /* ORA ab,x */
ZPAGE_X;
ORA_ZP;
break;
case 0x16: /* ASL ab,x */
ZPAGE_X;
ASL_ZP;
break;
case 0x17: /* ASO ab,x [unofficial] */
ZPAGE_X;
ASO_ZP;
break;
case 0x18: /* CLC */
c = 0;
break;
case 0x19: /* ORA abcd,y */
ABSOLUTE_Y;
NCYCLES_Y;
ORA;
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 0x1d: /* ORA abcd,x */
ABSOLUTE_X;
NCYCLES_X;
ORA;
break;
case 0x1e: /* ASL abcd,x */
ABSOLUTE_X;
ASL;
break;
case 0x1f: /* ASO abcd,x [unofficial] */
ABSOLUTE_X;
ASO;
break;
case 0x20: /* JSR abcd */
addr = FETCH;
PHPC;
pc = addr + (PEEK << 8);
break;
case 0x21: /* AND (ab,x) */
INDIRECT_X;
AND;
break;
case 0x23: /* RLA (ab,x) [unofficial] */
INDIRECT_X;
RLA;
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 0x27: /* RLA ab [unofficial] */
ZPAGE;
RLA_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 0x2f: /* RLA abcd [unofficial] */
ABSOLUTE;
RLA;
break;
case 0x30: /* BMI */
BRANCH(nz >= 0x80);
case 0x31: /* AND (ab),y */
INDIRECT_Y;
NCYCLES_Y;
AND;
break;
case 0x33: /* RLA (ab),y [unofficial] */
INDIRECT_Y;
RLA;
break;
case 0x35: /* AND ab,x */
ZPAGE_X;
AND_ZP;
break;
case 0x36: /* ROL ab,x */
ZPAGE_X;
ROL_ZP;
break;
case 0x37: /* RLA ab,x [unofficial] */
ZPAGE_X;
RLA_ZP;
break;
case 0x38: /* SEC */
c = 1;
break;
case 0x39: /* AND abcd,y */
ABSOLUTE_Y;
NCYCLES_Y;
AND;
break;
case 0x3b: /* RLA abcd,y [unofficial] */
ABSOLUTE_Y;
RLA;
break;
case 0x3d: /* AND abcd,x */
ABSOLUTE_X;
NCYCLES_X;
AND;
break;
case 0x3e: /* ROL abcd,x */
ABSOLUTE_X;
ROL;
break;
case 0x3f: /* RLA abcd,x [unofficial] */
ABSOLUTE_X;
RLA;
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 0x43: /* LSE (ab,x) [unofficial] */
INDIRECT_X;
LSE;
break;
case 0x45: /* EOR ab */
ZPAGE;
EOR_ZP;
break;
case 0x46: /* LSR ab */
ZPAGE;
LSR_ZP;
break;
case 0x47: /* LSE ab [unofficial] */
ZPAGE;
LSE_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 0x4b: /* ALR #ab [unofficial] */
a &= FETCH;
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 0x4f: /* LSE abcd [unofficial] */
ABSOLUTE;
LSE;
break;
case 0x50: /* BVC */
BRANCH((vdi & V_FLAG) == 0);
case 0x51: /* EOR (ab),y */
INDIRECT_Y;
NCYCLES_Y;
EOR;
break;
case 0x53: /* LSE (ab),y [unofficial] */
INDIRECT_Y;
LSE;
break;
case 0x55: /* EOR ab,x */
ZPAGE_X;
EOR_ZP;
break;
case 0x56: /* LSR ab,x */
ZPAGE_X;
LSR_ZP;
break;
case 0x57: /* LSE ab,x [unofficial] */
ZPAGE_X;
LSE_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 0x5b: /* LSE abcd,y [unofficial] */
ABSOLUTE_Y;
LSE;
break;
case 0x5d: /* EOR abcd,x */
ABSOLUTE_X;
NCYCLES_X;
EOR;
break;
case 0x5e: /* LSR abcd,x */
ABSOLUTE_X;
LSR;
break;
case 0x5f: /* LSE abcd,x [unofficial] */
ABSOLUTE_X;
LSE;
break;
case 0x60: /* RTS */
PL(pc);
PL(addr);
pc += (addr << 8) + 1;
break;
case 0x61: /* ADC (ab,x) */
INDIRECT_X;
ADC;
break;
case 0x63: /* RRA (ab,x) [unofficial] */
INDIRECT_X;
RRA;
break;
case 0x65: /* ADC ab */
ZPAGE;
ADC_ZP;
break;
case 0x66: /* ROR ab */
ZPAGE;
ROR_ZP;
break;
case 0x67: /* RRA ab [unofficial] */
ZPAGE;
RRA_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 0x6b: /* ARR #ab [unofficial] */
data = a & FETCH;
nz = a = (data >> 1) + (c << 7);
vdi = (vdi & (D_FLAG | I_FLAG)) + ((a ^ data) & V_FLAG);
if ((vdi & D_FLAG) == 0)
c = data >> 7;
else {
if ((data & 0xf) + (data & 1) > 5)
a = (a & 0xf0) + ((a + 6) & 0xf);
if (data + (data & 0x10) >= 0x60) {
a += 0x60;
c = 1;
}
else
c = 0;
a &= 0xff;
}
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 0x6f: /* RRA abcd [unofficial] */
ABSOLUTE;
RRA;
break;
case 0x70: /* BVS */
BRANCH((vdi & V_FLAG) != 0);
case 0x71: /* ADC (ab),y */
INDIRECT_Y;
NCYCLES_Y;
ADC;
break;
case 0x73: /* RRA (ab),y [unofficial] */
INDIRECT_Y;
RRA;
break;
case 0x75: /* ADC ab,x */
ZPAGE_X;
ADC_ZP;
break;
case 0x76: /* ROR ab,x */
ZPAGE_X;
ROR_ZP;
break;
case 0x77: /* RRA ab,x [unofficial] */
ZPAGE_X;
RRA_ZP;
break;
case 0x78: /* SEI */
vdi |= I_FLAG;
break;
case 0x79: /* ADC abcd,y */
ABSOLUTE_Y;
NCYCLES_Y;
ADC;
break;
case 0x7b: /* RRA abcd,y [unofficial] */
ABSOLUTE_Y;
RRA;
break;
case 0x7d: /* ADC abcd,x */
ABSOLUTE_X;
NCYCLES_X;
ADC;
break;
case 0x7e: /* ROR abcd,x */
ABSOLUTE_X;
ROR;
break;
case 0x7f: /* RRA abcd,x [unofficial] */
ABSOLUTE_X;
RRA;
break;
case 0x81: /* STA (ab,x) */
INDIRECT_X;
STA;
break;
case 0x83: /* SAX (ab,x) [unofficial] */
INDIRECT_X;
SAX;
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 0x87: /* SAX ab [unofficial] */
ZPAGE;
SAX_ZP;
break;
case 0x88: /* DEY */
nz = y = (y - 1) & 0xff;
break;
case 0x8a: /* TXA */
nz = a = x;
break;
case 0x8b: /* ANE #ab [unofficial] */
data = FETCH;
a &= x;
nz = a & data;
a &= data | 0xef;
break;
case 0x8c: /* STY abcd */
ABSOLUTE;
STY;
break;
case 0x8d: /* STA abcd */
ABSOLUTE;
STA;
break;
case 0x8e: /* STX abcd */
ABSOLUTE;
STX;
break;
case 0x8f: /* SAX abcd [unofficial] */
ABSOLUTE;
SAX;
break;
case 0x90: /* BCC */
BRANCH(c == 0);
case 0x91: /* STA (ab),y */
INDIRECT_Y;
STA;
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 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 0x97: /* SAX ab,y [unofficial] */
ZPAGE_Y;
SAX_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 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 0x9d: /* STA abcd,x */
ABSOLUTE_X;
STA;
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 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 0xa3: /* LAX (ab,x) [unofficial] */
INDIRECT_X;
LAX;
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 0xa7: /* LAX ab [unofficial] */
ZPAGE;
LAX_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 0xab: /* ANX #ab [unofficial] */
nz = x = a &= FETCH;
break;
case 0xac: /* LDY abcd */
ABSOLUTE;
LDY;
break;
case 0xad: /* LDA abcd */
ABSOLUTE;
LDA;
break;
case 0xae: /* LDX abcd */
ABSOLUTE;
LDX;
break;
case 0xaf: /* LAX abcd [unofficial] */
ABSOLUTE;
LAX;
break;
case 0xb0: /* BCS */
BRANCH(c != 0);
case 0xb1: /* LDA (ab),y */
INDIRECT_Y;
NCYCLES_Y;
LDA;
break;
case 0xb3: /* LAX (ab),y [unofficial] */
INDIRECT_Y;
NCYCLES_Y;
LAX;
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 0xb7: /* LAX ab,y [unofficial] */
ZPAGE_Y;
LAX_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 0xbb: /* LAS abcd,y [unofficial] */
ABSOLUTE_Y;
NCYCLES_Y;
nz = x = a = s &= GetByte(addr);
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 0xbf: /* LAX abcd,y [unofficial] */
ABSOLUTE_Y;
NCYCLES_Y;
LAX;
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 0xc3: /* DCM (ab,x) [unofficial] */
INDIRECT_X;
DCM;
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 0xc7: /* DCM ab [unofficial] */
ZPAGE;
DCM_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 0xcb: /* SBX #ab [unofficial] */
nz = FETCH;
x &= a;
c = (x >= nz) ? 1 : 0;
nz = x = (x - nz) & 0xff;
break;
case 0xcc: /* CPY abcd */
ABSOLUTE;
CPY;
break;
case 0xcd: /* CMP abcd */
ABSOLUTE;
CMP;
break;
case 0xce: /* DEC abcd */
ABSOLUTE;
DEC;
break;
case 0xcf: /* DCM abcd [unofficial] */
ABSOLUTE;
DCM;
break;
case 0xd0: /* BNE */
BRANCH((nz & 0xff) != 0);
case 0xd1: /* CMP (ab),y */
INDIRECT_Y;
NCYCLES_Y;
CMP;
break;
case 0xd3: /* DCM (ab),y [unofficial] */
INDIRECT_Y;
DCM;
break;
case 0xd5: /* CMP ab,x */
ZPAGE_X;
CMP_ZP;
break;
case 0xd6: /* DEC ab,x */
ZPAGE_X;
DEC_ZP;
break;
case 0xd7: /* DCM ab,x [unofficial] */
ZPAGE_X;
DCM_ZP;
break;
case 0xd8: /* CLD */
vdi &= V_FLAG | I_FLAG;
break;
case 0xd9: /* CMP abcd,y */
ABSOLUTE_Y;
NCYCLES_Y;
CMP;
break;
case 0xdb: /* DCM abcd,y [unofficial] */
ABSOLUTE_Y;
DCM;
break;
case 0xdd: /* CMP abcd,x */
ABSOLUTE_X;
NCYCLES_X;
CMP;
break;
case 0xde: /* DEC abcd,x */
ABSOLUTE_X;
DEC;
break;
case 0xdf: /* DCM abcd,x [unofficial] */
ABSOLUTE_X;
DCM;
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 0xe3: /* INS (ab,x) [unofficial] */
INDIRECT_X;
INS;
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 0xe7: /* INS ab [unofficial] */
ZPAGE;
INS_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 0xef: /* INS abcd [unofficial] */
ABSOLUTE;
INS;
break;
case 0xf0: /* BEQ */
BRANCH((nz & 0xff) == 0);
case 0xf1: /* SBC (ab),y */
INDIRECT_Y;
NCYCLES_Y;
SBC;
break;
case 0xf3: /* INS (ab),y [unofficial] */
INDIRECT_Y;
INS;
break;
case 0xf5: /* SBC ab,x */
ZPAGE_X;
SBC_ZP;
break;
case 0xf6: /* INC ab,x */
ZPAGE_X;
INC_ZP;
break;
case 0xf7: /* INS ab,x [unofficial] */
ZPAGE_X;
INS_ZP;
break;
case 0xf8: /* SED */
vdi |= D_FLAG;
break;
case 0xf9: /* SBC abcd,y */
ABSOLUTE_Y;
NCYCLES_Y;
SBC;
break;
case 0xfb: /* INS abcd,y [unofficial] */
ABSOLUTE_Y;
INS;
break;
case 0xfd: /* SBC abcd,x */
ABSOLUTE_X;
NCYCLES_X;
SBC;
break;
case 0xfe: /* INC abcd,x */
ABSOLUTE_X;
INC;
break;
case 0xff: /* INS abcd,x */
ABSOLUTE_X;
INS;
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;
}