/* * 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; }