/*
 *  CPU_emulcycle.h - SC 6510/6502 emulation core (body of
 *                    EmulateCycle() function, the same for
 *                    both 6510 and 6502)
 *
 *  Frodo (C) 1994-1997,2002-2005 Christian Bauer
 *
 *  This program 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.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


/*
 *  Stack macros
 */

// Pop processor flags from the stack
#define pop_flags() \
	read_to(sp | 0x100, data); \
	n_flag = data; \
	v_flag = data & 0x40; \
	d_flag = data & 0x08; \
	i_flag = data & 0x04; \
	z_flag = !(data & 0x02); \
	c_flag = data & 0x01;

// Push processor flags onto the stack
#define push_flags(b_flag) \
	data = 0x20 | (n_flag & 0x80); \
	if (v_flag) data |= 0x40; \
	if (b_flag) data |= 0x10; \
	if (d_flag) data |= 0x08; \
	if (i_flag) data |= 0x04; \
	if (!z_flag) data |= 0x02; \
	if (c_flag) data |= 0x01; \
	write_byte(sp-- | 0x100, data);


/*
 *  Other macros
 */

// Branch (cycle 1)
#define Branch(flag) \
		read_to(pc++, data);  \
		if (flag) { \
			ar = pc + (int8)data; \
			if ((ar >> 8) != (pc >> 8)) { \
				if (data & 0x80) \
					state = O_BRANCH_BP; \
				else \
					state = O_BRANCH_FP; \
			} else \
				state = O_BRANCH_NP; \
		} else \
			state = 0; \
		break;

// Set N and Z flags according to byte
#define set_nz(x) (z_flag = n_flag = (x))

// Address fetch of RMW instruction done, now read and write operand
#define DoRMW state = RMW_DO_IT; break;

// Operand fetch done, now execute opcode
#define Execute state = OpTab[op]; break;

// Last cycle of opcode
#define Last state = 0; break;


/*
 *  EmulCycle() function
 */

	switch (state) {


		// Opcode fetch (cycle 0)
		case 0:
			read_to(pc++, op);
			state = ModeTab[op];
			break;


		// IRQ
		case 0x0008:
			read_idle(pc);
			state = 0x0009;
			break;
		case 0x0009:
			read_idle(pc);
			state = 0x000a;
			break;
		case 0x000a:
			write_byte(sp-- | 0x100, pc >> 8);
			state = 0x000b;
			break;
		case 0x000b:
			write_byte(sp-- | 0x100, pc);
			state = 0x000c;
			break;
		case 0x000c:
			push_flags(false);
			i_flag = true;
			state = 0x000d;
			break;
		case 0x000d:
			read_to(0xfffe, pc);
			state = 0x000e;
			break;
		case 0x000e:
			read_to(0xffff, data);
			pc |= data << 8;
			Last;


		// NMI
		case 0x0010:
			read_idle(pc);
			state = 0x0011;
			break;
		case 0x0011:
			read_idle(pc);
			state = 0x0012;
			break;
		case 0x0012:
			write_byte(sp-- | 0x100, pc >> 8);
			state = 0x0013;
			break;
		case 0x0013:
			write_byte(sp-- | 0x100, pc);
			state = 0x0014;
			break;
		case 0x0014:
			push_flags(false);
			i_flag = true;
			state = 0x0015;
			break;
		case 0x0015:
			read_to(0xfffa, pc);
			state = 0x0016;
			break;
		case 0x0016:
			read_to(0xfffb, data);
			pc |= data << 8;
			Last;


		// Addressing modes: Fetch effective address, no extra cycles (-> ar)
		case A_ZERO:
			read_to(pc++, ar);
			Execute;

		case A_ZEROX:
			read_to(pc++, ar);
			state = A_ZEROX1;
			break;
		case A_ZEROX1:
			read_idle(ar);
			ar = (ar + x) & 0xff;
			Execute;

		case A_ZEROY:
			read_to(pc++, ar);
			state = A_ZEROY1;
			break;
		case A_ZEROY1:
			read_idle(ar);
			ar = (ar + y) & 0xff;
			Execute;

		case A_ABS:
			read_to(pc++, ar);
			state = A_ABS1;
			break;
		case A_ABS1:
			read_to(pc++, data);
			ar = ar | (data << 8);
			Execute;

		case A_ABSX:
			read_to(pc++, ar);
			state = A_ABSX1;
			break;
		case A_ABSX1:
			read_to(pc++, ar2);	// Note: Some undocumented opcodes rely on the value of ar2
			if (ar+x < 0x100)
				state = A_ABSX2;
			else
				state = A_ABSX3;
			ar = ((ar + x) & 0xff) | (ar2 << 8);
			break;
		case A_ABSX2:	// No page crossed
			read_idle(ar);
			Execute;
		case A_ABSX3:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			Execute;

		case A_ABSY:
			read_to(pc++, ar);
			state = A_ABSY1;
			break;
		case A_ABSY1:
			read_to(pc++, ar2);	// Note: Some undocumented opcodes rely on the value of ar2
			if (ar+y < 0x100)
				state = A_ABSY2;
			else
				state = A_ABSY3;
			ar = ((ar + y) & 0xff) | (ar2 << 8);
			break;
		case A_ABSY2:	// No page crossed
			read_idle(ar);
			Execute;
		case A_ABSY3:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			Execute;

		case A_INDX:
			read_to(pc++, ar2);
			state = A_INDX1;
			break;
		case A_INDX1:
			read_idle(ar2);
			ar2 = (ar2 + x) & 0xff;
			state = A_INDX2;
			break;
		case A_INDX2:
			read_to(ar2, ar);
			state = A_INDX3;
			break;
		case A_INDX3:
			read_to((ar2 + 1) & 0xff, data);
			ar = ar | (data << 8);
			Execute;

		case A_INDY:
			read_to(pc++, ar2);
			state = A_INDY1;
			break;
		case A_INDY1:
			read_to(ar2, ar);
			state = A_INDY2;
			break;
		case A_INDY2:
			read_to((ar2 + 1) & 0xff, ar2);	// Note: Some undocumented opcodes rely on the value of ar2
			if (ar+y < 0x100)
				state = A_INDY3;
			else
				state = A_INDY4;
			ar = ((ar + y) & 0xff) | (ar2 << 8);
			break;
		case A_INDY3:	// No page crossed
			read_idle(ar);
			Execute;
		case A_INDY4:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			Execute;


		// Addressing modes: Fetch effective address, extra cycle on page crossing (-> ar)
		case AE_ABSX:
			read_to(pc++, ar);
			state = AE_ABSX1;
			break;
		case AE_ABSX1:
			read_to(pc++, data);
			if (ar+x < 0x100) {
				ar = ((ar + x) & 0xff) | (data << 8);
				Execute;
			} else {
				ar = ((ar + x) & 0xff) | (data << 8);
				state = AE_ABSX2;
			}
			break;
		case AE_ABSX2:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			Execute;

		case AE_ABSY:
			read_to(pc++, ar);
			state = AE_ABSY1;
			break;
		case AE_ABSY1:
			read_to(pc++, data);
			if (ar+y < 0x100) {
				ar = ((ar + y) & 0xff) | (data << 8);
				Execute;
			} else {
				ar = ((ar + y) & 0xff) | (data << 8);
				state = AE_ABSY2;
			}
			break;
		case AE_ABSY2:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			Execute;

		case AE_INDY:
			read_to(pc++, ar2);
			state = AE_INDY1;
			break;
		case AE_INDY1:
			read_to(ar2, ar);
			state = AE_INDY2;
			break;
		case AE_INDY2:
			read_to((ar2 + 1) & 0xff, data);
			if (ar+y < 0x100) {
				ar = ((ar + y) & 0xff) | (data << 8);
				Execute;
			} else {
				ar = ((ar + y) & 0xff) | (data << 8);
				state = AE_INDY3;
			}
			break;
		case AE_INDY3:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			Execute;


		// Addressing modes: Read operand, write it back, no extra cycles (-> ar, rdbuf)
		case M_ZERO:
			read_to(pc++, ar);
			DoRMW;

		case M_ZEROX:
			read_to(pc++, ar);
			state = M_ZEROX1;
			break;
		case M_ZEROX1:
			read_idle(ar);
			ar = (ar + x) & 0xff;
			DoRMW;

		case M_ZEROY:
			read_to(pc++, ar);
			state = M_ZEROY1;
			break;
		case M_ZEROY1:
			read_idle(ar);
			ar = (ar + y) & 0xff;
			DoRMW;

		case M_ABS:
			read_to(pc++, ar);
			state = M_ABS1;
			break;
		case M_ABS1:
			read_to(pc++, data);
			ar = ar | (data << 8);
			DoRMW;

		case M_ABSX:
			read_to(pc++, ar);
			state = M_ABSX1;
			break;
		case M_ABSX1:
			read_to(pc++, data);
			if (ar+x < 0x100)
				state = M_ABSX2;
			else
				state = M_ABSX3;
			ar = ((ar + x) & 0xff) | (data << 8);
			break;
		case M_ABSX2:	// No page crossed
			read_idle(ar);
			DoRMW;
		case M_ABSX3:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			DoRMW;

		case M_ABSY:
			read_to(pc++, ar);
			state = M_ABSY1;
			break;
		case M_ABSY1:
			read_to(pc++, data);
			if (ar+y < 0x100)
				state = M_ABSY2;
			else
				state = M_ABSY3;
			ar = ((ar + y) & 0xff) | (data << 8);
			break;
		case M_ABSY2:	// No page crossed
			read_idle(ar);
			DoRMW;
		case M_ABSY3:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			DoRMW;

		case M_INDX:
			read_to(pc++, ar2);
			state = M_INDX1;
			break;
		case M_INDX1:
			read_idle(ar2);
			ar2 = (ar2 + x) & 0xff;
			state = M_INDX2;
			break;
		case M_INDX2:
			read_to(ar2, ar);
			state = M_INDX3;
			break;
		case M_INDX3:
			read_to((ar2 + 1) & 0xff, data);
			ar = ar | (data << 8);
			DoRMW;

		case M_INDY:
			read_to(pc++, ar2);
			state = M_INDY1;
			break;
		case M_INDY1:
			read_to(ar2, ar);
			state = M_INDY2;
			break;
		case M_INDY2:
			read_to((ar2 + 1) & 0xff, data);
			if (ar+y < 0x100)
				state = M_INDY3;
			else
				state = M_INDY4;
			ar = ((ar + y) & 0xff) | (data << 8);
			break;
		case M_INDY3:	// No page crossed
			read_idle(ar);
			DoRMW;
		case M_INDY4:	// Page crossed
			read_idle(ar);
			ar += 0x100;
			DoRMW;

		case RMW_DO_IT:
			read_to(ar, rdbuf);
			state = RMW_DO_IT1;
			break;
		case RMW_DO_IT1:
			write_byte(ar, rdbuf);
			Execute;


		// Load group
		case O_LDA:
			read_to(ar, data);
			set_nz(a = data);
			Last;
		case O_LDA_I:
			read_to(pc++, data);
			set_nz(a = data);
			Last;

		case O_LDX:
			read_to(ar, data);
			set_nz(x = data);
			Last;
		case O_LDX_I:
			read_to(pc++, data);
			set_nz(x = data);
			Last;

		case O_LDY:
			read_to(ar, data);
			set_nz(y = data);
			Last;
		case O_LDY_I:
			read_to(pc++, data);
			set_nz(y = data);
			Last;


		// Store group
		case O_STA:
			write_byte(ar, a);
			Last;

		case O_STX:
			write_byte(ar, x);
			Last;

		case O_STY:
			write_byte(ar, y);
			Last;


		// Transfer group
		case O_TAX:
			read_idle(pc);
			set_nz(x = a);
			Last;

		case O_TXA:
			read_idle(pc);
			set_nz(a = x);
			Last;

		case O_TAY:
			read_idle(pc);
			set_nz(y = a);
			Last;

		case O_TYA:
			read_idle(pc);
			set_nz(a = y);
			Last;

		case O_TSX:
			read_idle(pc);
			set_nz(x = sp);
			Last;

		case O_TXS:
			read_idle(pc);
			sp = x;
			Last;


		// Arithmetic group
		case O_ADC:
			read_to(ar, data);
			do_adc(data);
			Last;
		case O_ADC_I:
			read_to(pc++, data);
			do_adc(data);
			Last;

		case O_SBC:
			read_to(ar, data);
			do_sbc(data);
			Last;
		case O_SBC_I:
			read_to(pc++, data);
			do_sbc(data);
			Last;


		// Increment/decrement group
		case O_INX:
			read_idle(pc);
			set_nz(++x);
			Last;

		case O_DEX:
			read_idle(pc);
			set_nz(--x);
			Last;

		case O_INY:
			read_idle(pc);
			set_nz(++y);
			Last;

		case O_DEY:
			read_idle(pc);
			set_nz(--y);
			Last;

		case O_INC:
			write_byte(ar, set_nz(rdbuf + 1));
			Last;

		case O_DEC:
			write_byte(ar, set_nz(rdbuf - 1));
			Last;


		// Logic group
		case O_AND:
			read_to(ar, data);
			set_nz(a &= data);
			Last;
		case O_AND_I:
			read_to(pc++, data);
			set_nz(a &= data);
			Last;

		case O_ORA:
			read_to(ar, data);
			set_nz(a |= data);
			Last;
		case O_ORA_I:
			read_to(pc++, data);
			set_nz(a |= data);
			Last;

		case O_EOR:
			read_to(ar, data);
			set_nz(a ^= data);
			Last;
		case O_EOR_I:
			read_to(pc++, data);
			set_nz(a ^= data);
			Last;

		// Compare group
		case O_CMP:
			read_to(ar, data);
			set_nz(ar = a - data);
			c_flag = ar < 0x100;
			Last;
		case O_CMP_I:
			read_to(pc++, data);
			set_nz(ar = a - data);
			c_flag = ar < 0x100;
			Last;

		case O_CPX:
			read_to(ar, data);
			set_nz(ar = x - data);
			c_flag = ar < 0x100;
			Last;
		case O_CPX_I:
			read_to(pc++, data);
			set_nz(ar = x - data);
			c_flag = ar < 0x100;
			Last;

		case O_CPY:
			read_to(ar, data);
			set_nz(ar = y - data);
			c_flag = ar < 0x100;
			Last;
		case O_CPY_I:
			read_to(pc++, data);
			set_nz(ar = y - data);
			c_flag = ar < 0x100;
			Last;


		// Bit-test group
		case O_BIT:
			read_to(ar, data);
			z_flag = a & data;
			n_flag = data;
			v_flag = data & 0x40;
			Last;


		// Shift/rotate group
		case O_ASL:
			c_flag = rdbuf & 0x80;
			write_byte(ar, set_nz(rdbuf << 1));
			Last;
		case O_ASL_A:
			read_idle(pc);
			c_flag = a & 0x80;
			set_nz(a <<= 1);
			Last;

		case O_LSR:
			c_flag = rdbuf & 0x01;
			write_byte(ar, set_nz(rdbuf >> 1));
			Last;
		case O_LSR_A:
			read_idle(pc);
			c_flag = a & 0x01;
			set_nz(a >>= 1);
			Last;

		case O_ROL:
			write_byte(ar, set_nz(c_flag ? (rdbuf << 1) | 0x01 : rdbuf << 1));
			c_flag = rdbuf & 0x80;
			Last;
		case O_ROL_A:
			read_idle(pc);
			data = a & 0x80;
			set_nz(a = c_flag ? (a << 1) | 0x01 : a << 1);
			c_flag = data;
			Last;

		case O_ROR:
			write_byte(ar, set_nz(c_flag ? (rdbuf >> 1) | 0x80 : rdbuf >> 1));
			c_flag = rdbuf & 0x01;
			Last;
		case O_ROR_A:
			read_idle(pc);
			data = a & 0x01;
			set_nz(a = (c_flag ? (a >> 1) | 0x80 : a >> 1));
			c_flag = data;
			Last;


		// Stack group
		case O_PHA:
			read_idle(pc);
			state = O_PHA1;
			break;
		case O_PHA1:
			write_byte(sp-- | 0x100, a);
			Last;

		case O_PLA:
			read_idle(pc);
			state = O_PLA1;
			break;
		case O_PLA1:
			read_idle(sp++ | 0x100);
			state = O_PLA2;
			break;
		case O_PLA2:
			read_to(sp | 0x100, data);
			set_nz(a = data);
			Last;

		case O_PHP:
			read_idle(pc);
			state = O_PHP1;
			break;
		case O_PHP1:
			push_flags(true);
			Last;

		case O_PLP:
			read_idle(pc);
			state = O_PLP1;
			break;
		case O_PLP1:
			read_idle(sp++ | 0x100);
			state = O_PLP2;
			break;
		case O_PLP2:
			pop_flags();
			Last;


		// Jump/branch group
		case O_JMP:
			read_to(pc++, ar);
			state = O_JMP1;
			break;
		case O_JMP1:
			read_to(pc, data);
			pc = (data << 8) | ar;
			Last;

		case O_JMP_I:
			read_to(ar, pc);
			state = O_JMP_I1;
			break;
		case O_JMP_I1:
			read_to(((ar + 1) & 0xff) | (ar & 0xff00), data);
			pc |= data << 8;
			Last;

		case O_JSR:
			read_to(pc++, ar);
			state = O_JSR1;
			break;
		case O_JSR1:
			read_idle(sp | 0x100);
			state = O_JSR2;
			break;
		case O_JSR2:
			write_byte(sp-- | 0x100, pc >> 8);
			state = O_JSR3;
			break;
		case O_JSR3:
			write_byte(sp-- | 0x100, pc);
			state = O_JSR4;
			break;
		case O_JSR4:
			read_to(pc++, data);
			pc = ar | (data << 8);
			Last;

		case O_RTS:
			read_idle(pc);
			state = O_RTS1;
			break;
		case O_RTS1:
			read_idle(sp++ | 0x100);
			state = O_RTS2;
			break;
		case O_RTS2:
			read_to(sp++ | 0x100, pc);
			state = O_RTS3;
			break;
		case O_RTS3:
			read_to(sp | 0x100, data);
			pc |= data << 8;
			state = O_RTS4;
			break;
		case O_RTS4:
			read_idle(pc++);
			Last;

		case O_RTI:
			read_idle(pc);
			state = O_RTI1;
			break;
		case O_RTI1:
			read_idle(sp++ | 0x100);
			state = O_RTI2;
			break;
		case O_RTI2:
			pop_flags();
			sp++;
			state = O_RTI3;
			break;
		case O_RTI3:
			read_to(sp++ | 0x100, pc);
			state = O_RTI4;
			break;
		case O_RTI4:
			read_to(sp | 0x100, data);
			pc |= data << 8;
			Last;

		case O_BRK:
			read_idle(pc++);
			state = O_BRK1;
			break;
		case O_BRK1:
			write_byte(sp-- | 0x100, pc >> 8);
			state = O_BRK2;
			break;
		case O_BRK2:
			write_byte(sp-- | 0x100, pc);
			state = O_BRK3;
			break;
		case O_BRK3:
			push_flags(true);
			i_flag = true;
#ifndef IS_CPU_1541
			if (interrupt.intr[INT_NMI]) {			// BRK interrupted by NMI?
				interrupt.intr[INT_NMI] = false;	// Simulate an edge-triggered input
				state = 0x0015;						// Jump to NMI sequence
				break;
			}
#endif
			state = O_BRK4;
			break;
		case O_BRK4:
#ifndef IS_CPU_1541
			first_nmi_cycle++;		// Delay NMI
#endif
			read_to(0xfffe, pc);
			state = O_BRK5;
			break;
		case O_BRK5:
			read_to(0xffff, data);
			pc |= data << 8;
			Last;

		case O_BCS:
			Branch(c_flag);

		case O_BCC:
			Branch(!c_flag);

		case O_BEQ:
			Branch(!z_flag);

		case O_BNE:
			Branch(z_flag);

		case O_BVS:
#ifndef IS_CPU_1541
			Branch(v_flag);
#else
			Branch((via2_pcr & 0x0e) == 0x0e ? 1 : v_flag);	// GCR byte ready flag
#endif

		case O_BVC:
#ifndef IS_CPU_1541
			Branch(!v_flag);
#else
			Branch(!((via2_pcr & 0x0e) == 0x0e) ? 0 : v_flag);	// GCR byte ready flag
#endif

		case O_BMI:
			Branch(n_flag & 0x80);

		case O_BPL:
			Branch(!(n_flag & 0x80));

		case O_BRANCH_NP:	// No page crossed
			first_irq_cycle++;	// Delay IRQ
#ifndef IS_CPU_1541
			first_nmi_cycle++;	// Delay NMI
#endif
			read_idle(pc);
			pc = ar;
			Last;
		case O_BRANCH_BP:	// Page crossed, branch backwards
			read_idle(pc);
			pc = ar;
			state = O_BRANCH_BP1;
			break;
		case O_BRANCH_BP1:
			read_idle(pc + 0x100);
			Last;
		case O_BRANCH_FP:	// Page crossed, branch forwards
			read_idle(pc);
			pc = ar;
			state = O_BRANCH_FP1;
			break;
		case O_BRANCH_FP1:
			read_idle(pc - 0x100);
			Last;


		// Flag group
		case O_SEC:
			read_idle(pc);
			c_flag = true;
			Last;

		case O_CLC:
			read_idle(pc);
			c_flag = false;
			Last;

		case O_SED:
			read_idle(pc);
			d_flag = true;
			Last;

		case O_CLD:
			read_idle(pc);
			d_flag = false;
			Last;

		case O_SEI:
			read_idle(pc);
			i_flag = true;
			Last;

		case O_CLI:
			read_idle(pc);
			i_flag = false;
			Last;

		case O_CLV:
			read_idle(pc);
			v_flag = false;
			Last;


		// NOP group
		case O_NOP:
			read_idle(pc);
			Last;


/*
 * Undocumented opcodes start here
 */

		// NOP group
		case O_NOP_I:
			read_idle(pc++);
			Last;

		case O_NOP_A:
			read_idle(ar);
			Last;


		// Load A/X group
		case O_LAX:
			read_to(ar, data);
			set_nz(a = x = data);
			Last;


		// Store A/X group
		case O_SAX:
			write_byte(ar, a & x);
			Last;


		// ASL/ORA group
		case O_SLO:
			c_flag = rdbuf & 0x80;
			rdbuf <<= 1;
			write_byte(ar, rdbuf);
			set_nz(a |= rdbuf);
			Last;


		// ROL/AND group
		case O_RLA:
			tmp = rdbuf & 0x80;
			rdbuf = c_flag ? (rdbuf << 1) | 0x01 : rdbuf << 1;
			c_flag = tmp;
			write_byte(ar, rdbuf);
			set_nz(a &= rdbuf);
			Last;


		// LSR/EOR group
		case O_SRE:
			c_flag = rdbuf & 0x01;
			rdbuf >>= 1;
			write_byte(ar, rdbuf);
			set_nz(a ^= rdbuf);
			Last;


		// ROR/ADC group
		case O_RRA:
			tmp = rdbuf & 0x01;
			rdbuf = c_flag ? (rdbuf >> 1) | 0x80 : rdbuf >> 1;
			c_flag = tmp;
			write_byte(ar, rdbuf);
			do_adc(rdbuf);
			Last;


		// DEC/CMP group
		case O_DCP:
			write_byte(ar, --rdbuf);
			set_nz(ar = a - rdbuf);
			c_flag = ar < 0x100;
			Last;


		// INC/SBC group
		case O_ISB:
			write_byte(ar, ++rdbuf);
			do_sbc(rdbuf);
			Last;


		// Complex functions
		case O_ANC_I:
			read_to(pc++, data);
			set_nz(a &= data);
			c_flag = n_flag & 0x80;
			Last;

		case O_ASR_I:
			read_to(pc++, data);
			a &= data;
			c_flag = a & 0x01;
			set_nz(a >>= 1);
			Last;

		case O_ARR_I:
			read_to(pc++, data);
			data &= a;
			a = (c_flag ? (data >> 1) | 0x80 : data >> 1);
			if (!d_flag) {
				set_nz(a);
				c_flag = a & 0x40;
				v_flag = (a & 0x40) ^ ((a & 0x20) << 1);
			} else {
				n_flag = c_flag ? 0x80 : 0;
				z_flag = a;
				v_flag = (data ^ a) & 0x40;
				if ((data & 0x0f) + (data & 0x01) > 5)
					a = (a & 0xf0) | ((a + 6) & 0x0f);
				if ((c_flag = ((data + (data & 0x10)) & 0x1f0) > 0x50) != 0)
					a += 0x60;
			}
			Last;

		case O_ANE_I:
			read_to(pc++, data);
			set_nz(a = (a | 0xee) & x & data);
			Last;

		case O_LXA_I:
			read_to(pc++, data);
			set_nz(a = x = (a | 0xee) & data);
			Last;

		case O_SBX_I:
			read_to(pc++, data);
			set_nz(x = ar = (x & a) - data);
			c_flag = ar < 0x100;
			Last;

		case O_LAS:
			read_to(ar, data);
			set_nz(a = x = sp = data & sp);
			Last;

		case O_SHS:		// ar2 contains the high byte of the operand address
			write_byte(ar, (ar2+1) & (sp = a & x));
			Last;

		case O_SHY:		// ar2 contains the high byte of the operand address
			write_byte(ar, y & (ar2+1));
			Last;

		case O_SHX:		// ar2 contains the high byte of the operand address
			write_byte(ar, x & (ar2+1));
			Last;

		case O_SHA:		// ar2 contains the high byte of the operand address
			write_byte(ar, a & x & (ar2+1));
			Last;
