diff options
Diffstat (limited to 'lib/rbcodec/codecs/libasap/acpu.c')
-rw-r--r-- | lib/rbcodec/codecs/libasap/acpu.c | 1291 |
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; +} |