This is 6510core.c in view mode; [Download] [Up]
/* * 6510core.c - MOS6510 emulation core. * * Written by * Ettore Perazzoli (ettore@comm2000.it) * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * * 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. * */ #ifdef __1541__ #define CPU_STR "1541 CPU" #else #define CPU_STR "Main CPU" #endif #if 0 #define UNDOC_WARNING() printf(CPU_STR " Warning: undocumented $%02X\n", p0); #else #define UNDOC_WARNING() #endif #define IRQ_CYCLES 7 #define NMI_CYCLES 7 #define RESET_CYCLES 6 /* ------------------------------------------------------------------------- */ #define LOCAL_SET_NZ(val) (flag_z = flag_n = (val)) #if defined __1541__ #define LOCAL_SET_OVERFLOW(val) \ do { \ if (!(val)) true1541_set_byte_ready(0); \ ((val) ? (reg_p |= P_OVERFLOW) \ : (reg_p &= ~P_OVERFLOW)); \ } while (0) #else #define LOCAL_SET_OVERFLOW(val) ((val) ? (reg_p |= P_OVERFLOW) \ : (reg_p &= ~P_OVERFLOW)) #endif #define LOCAL_SET_BREAK(val) ((val) ? (reg_p |= P_BREAK) \ : (reg_p &= ~P_BREAK)) #define LOCAL_SET_DECIMAL(val) ((val) ? (reg_p |= P_DECIMAL) \ : (reg_p &= ~P_DECIMAL)) #define LOCAL_SET_INTERRUPT(val) ((val) ? (reg_p |= P_INTERRUPT) \ : (reg_p &= ~P_INTERRUPT)) #define LOCAL_SET_CARRY(val) ((val) ? (reg_p |= P_CARRY) \ : (reg_p &= ~P_CARRY)) #define LOCAL_SET_SIGN(val) (flag_n = (val) ? 0x80 : 0) #define LOCAL_SET_ZERO(val) (flag_z = !(val)) #define LOCAL_SET_STATUS(val) (reg_p = ((val) & ~(P_ZERO | P_SIGN)), \ LOCAL_SET_ZERO((val) & P_ZERO), \ flag_n = (val)) #define LOCAL_OVERFLOW() (reg_p & P_OVERFLOW) #define LOCAL_BREAK() (reg_p & P_BREAK) #define LOCAL_DECIMAL() (reg_p & P_DECIMAL) #define LOCAL_INTERRUPT() (reg_p & P_INTERRUPT) #define LOCAL_CARRY() (reg_p & P_CARRY) #define LOCAL_SIGN() (flag_n & 0x80) #define LOCAL_ZERO() (!flag_z) #define LOCAL_STATUS() (reg_p | (flag_n & 0x80) | P_UNUSED \ | (LOCAL_ZERO() ? P_ZERO : 0)) /* Additional debugging. */ #if 1 /* def __1541__ */ #define DO_DEBUG(ab) while(0) #else #define DO_DEBUG(ab) \ do { \ if (app_resources.debugFlag) \ printf("CPU " ab " at clk=%d, PC=%04x\n", clk, reg_pc); \ } while(0) #endif #ifdef LAST_OPCODE_INFO /* If requested, gather some info about the last executed opcode for timing purposes. */ /* Remember the number of the last opcode. By default, the opcode does not delay interrupt and does not change the I flag. */ #define SET_LAST_OPCODE(x) \ OPINFO_SET(LAST_OPCODE_INFO, (x), 0, 0, 0) /* Remember that the last opcode delayed a pending IRQ or NMI by one cycle. */ #define OPCODE_DELAYS_INTERRUPT() \ OPINFO_SET_DELAYS_INTERRUPT(LAST_OPCODE_INFO, 1) /* Remember that the last opcode changed the I flag from 0 to 1, so we have to dispatch an IRQ even if the I flag is 0 when we check it. */ #define OPCODE_DISABLES_IRQ() \ OPINFO_SET_DISABLES_IRQ(LAST_OPCODE_INFO, 1) /* Remember that the last opcode changed the I flag from 1 to 0, so we must not dispatch an IRQ even if the I flag is 1 when we check it. */ #define OPCODE_ENABLES_IRQ() \ OPINFO_SET_ENABLES_IRQ(LAST_OPCODE_INFO, 1) #else /* Info about the last opcode is not needed. */ #define SET_LAST_OPCODE(x) #define OPCODE_DELAYS_INTERRUPT() #define OPCODE_DISABLES_IRQ() #define OPCODE_ENABLES_IRQ() #endif #ifndef __1541__ /* Export the local version of the registers. */ #define EXPORT_REGISTERS() \ do { \ GLOBAL_REGS.reg_pc = reg_pc; \ GLOBAL_REGS.reg_a = reg_a; \ GLOBAL_REGS.reg_x = reg_x; \ GLOBAL_REGS.reg_y = reg_y; \ GLOBAL_REGS.reg_sp = reg_sp; \ GLOBAL_REGS.reg_p = reg_p; \ GLOBAL_REGS.flag_n = flag_n; \ GLOBAL_REGS.flag_z = flag_z; \ } while (0) /* Import the public version of the registers. */ #define IMPORT_REGISTERS() \ do { \ reg_pc = GLOBAL_REGS.reg_pc; \ reg_a = GLOBAL_REGS.reg_a; \ reg_x = GLOBAL_REGS.reg_x; \ reg_y = GLOBAL_REGS.reg_y; \ reg_sp = GLOBAL_REGS.reg_sp; \ reg_p = GLOBAL_REGS.reg_p; \ flag_n = GLOBAL_REGS.flag_n; \ flag_z = GLOBAL_REGS.flag_z; \ } while (0) #else /* __1541__ */ #define IMPORT_REGISTERS() #define EXPORT_REGISTERS() #endif /* !__1541__ */ /* Stack operations. */ #define PUSH(val) ((PAGE_ONE)[(reg_sp--)] = (val)) #define PULL() ((PAGE_ONE)[(++reg_sp)]) /* Perform the interrupts in `int_kind'. If we have both NMI and IRQ, execute NMI. */ #ifdef TRACE #define TRACE_NMI() do { if (TRACEFLG) puts("*** NMI"); } while (0) #define TRACE_IRQ() do { if (TRACEFLG) puts("*** IRQ"); } while (0) #else #define TRACE_NMI() #define TRACE_IRQ() #endif #define DO_INTERRUPT(int_kind) \ do { \ BYTE ik = (int_kind); \ \ if (ik & (IK_IRQ | IK_NMI)) { \ if ((ik & IK_NMI) \ && check_nmi_delay(&CPU_INT_STATUS, CLK)) { \ TRACE_NMI(); \ ack_nmi(&CPU_INT_STATUS); \ LOCAL_SET_BREAK(0); \ PUSH(reg_pc >> 8); \ PUSH(reg_pc & 0xff); \ PUSH(LOCAL_STATUS()); \ LOCAL_SET_INTERRUPT(1); \ JUMP(LOAD_ADDR(0xfffa)); \ SET_LAST_OPCODE(0); \ CLK += NMI_CYCLES; \ } else if ((ik & IK_IRQ) \ && (!LOCAL_INTERRUPT() \ || OPINFO_DISABLES_IRQ(LAST_OPCODE_INFO)) \ && check_irq_delay(&CPU_INT_STATUS, CLK)) { \ TRACE_IRQ(); \ LOCAL_SET_BREAK(0); \ PUSH(reg_pc >> 8); \ PUSH(reg_pc & 0xff); \ PUSH(LOCAL_STATUS()); \ LOCAL_SET_INTERRUPT(1); \ JUMP(LOAD_ADDR(0xfffe)); \ SET_LAST_OPCODE(0); \ CLK += IRQ_CYCLES; \ } \ } \ if (ik & (IK_TRAP | IK_RESET)) { \ if (ik & IK_TRAP) { \ EXPORT_REGISTERS(); \ do_trap(&CPU_INT_STATUS, (ADDRESS) reg_pc); \ IMPORT_REGISTERS(); \ } \ if (ik & IK_RESET) { \ ack_reset(&CPU_INT_STATUS); \ reset(); \ JUMP(LOAD_ADDR(0xfffc)); \ } \ } \ if (ik & (IK_MONITOR)) { \ caller_space = CALLER; \ if (mon_force_import(CALLER)) \ IMPORT_REGISTERS(); \ if (mon_mask[CALLER]) \ EXPORT_REGISTERS(); \ if (mon_mask[CALLER] & (MI_BREAK)) { \ if (check_breakpoints(CALLER, (ADDRESS) reg_pc)) { \ mon((ADDRESS) reg_pc); \ IMPORT_REGISTERS(); \ } \ } \ if (mon_mask[CALLER] & (MI_STEP)) { \ mon_check_icount((ADDRESS) reg_pc); \ IMPORT_REGISTERS(); \ } \ if (mon_mask[CALLER] & (MI_WATCH)) { \ mon_check_watchpoints((ADDRESS) reg_pc); \ IMPORT_REGISTERS(); \ } \ } \ } while (0) /* ------------------------------------------------------------------------- */ /* Addressing modes. For convenience, page boundary crossing cycles and ``idle'' memory reads are handled here as well. */ #define LOAD_ABS(addr) \ LOAD(addr) #define LOAD_ABS_X(addr) \ ((((addr) & 0xff) + reg_x) > 0xff \ ? (LOAD(((addr) & 0xff00) | (((addr) + reg_x) & 0xff)), \ CLK++, \ LOAD((addr) + reg_x)) \ : LOAD((addr) + reg_x)) #define LOAD_ABS_X_RMW(addr) \ (LOAD(((addr) & 0xff00) | (((addr) + reg_x) & 0xff)), \ CLK++, \ LOAD((addr) + reg_x)) #define LOAD_ABS_Y(addr) \ ((((addr) & 0xff) + reg_y) > 0xff \ ? (LOAD(((addr) & 0xff00) | (((addr) + reg_y) & 0xff)), \ CLK++, \ LOAD((addr) + reg_y)) \ : LOAD((addr) + reg_y)) #define LOAD_ABS_Y_RMW(addr) \ (LOAD(((addr) & 0xff00) | (((addr) + reg_y) & 0xff)), \ CLK++, \ LOAD((addr) + reg_y)) #define LOAD_IND_X(addr) \ (LOAD(LOAD_ZERO_ADDR((addr) + reg_x))) #define LOAD_IND_Y(addr) \ (((LOAD_ZERO_ADDR((addr)) & 0xff) + reg_y) > 0xff \ ? (LOAD((LOAD_ZERO_ADDR((addr)) & 0xff00) \ | ((LOAD_ZERO_ADDR((addr)) + reg_y) & 0xff)), \ CLK++, \ LOAD(LOAD_ZERO_ADDR((addr)) + reg_y)) \ : LOAD(LOAD_ZERO_ADDR((addr)) + reg_y)) #define LOAD_ZERO_X(addr) \ (LOAD_ZERO((addr) + reg_x)) #define LOAD_ZERO_Y(addr) \ (LOAD_ZERO((addr) + reg_y)) #define STORE_ABS(addr, value, inc) \ do { \ CLK += (inc); \ STORE((addr), (value)); \ } while (0) #define STORE_ABS_X(addr, value, inc) \ do { \ CLK += (inc) - 2; \ LOAD((((addr) + reg_x) & 0xff) | ((addr) & 0xff00)); \ CLK += 2; \ STORE((addr) + reg_x, (value)); \ } while (0) #define STORE_ABS_X_RMW(addr, value, inc) \ do { \ CLK += (inc); \ STORE((addr) + reg_x, (value)); \ } while (0) \ #define STORE_ABS_Y(addr, value, inc) \ do { \ CLK += (inc) - 2; \ LOAD((((addr) + reg_y) & 0xff) | ((addr) & 0xff00)); \ CLK += 2; \ STORE((addr) + reg_y, (value)); \ } while (0) #define STORE_ABS_Y_RMW(addr, value, inc) \ do { \ CLK += (inc); \ STORE((addr) + reg_y, (value)); \ } while (0) #define INC_PC(value) (reg_pc += (value)) /* ------------------------------------------------------------------------- */ /* Opcodes. */ /* A couple of caveats about PC: - the VIC-II emulation requires PC to be incremented before the first write access (this is not (very) important when writing to the zero page); - `p0', `p1' and `p2' can only be used *before* incrementing PC: some machines (eg. the C128) might depend on this. */ #define ADC(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp_value; \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp_value = (value); \ CLK += (clk_inc2); \ \ if (LOCAL_DECIMAL()) { \ tmp = (reg_a & 0xf) + (tmp_value & 0xf) + (reg_p & 0x1); \ if (tmp > 0x9) \ tmp += 0x6; \ if (tmp <= 0x0f) \ tmp = (tmp & 0xf) + (reg_a & 0xf0) + (tmp_value & 0xf0); \ else \ tmp = (tmp & 0xf) + (reg_a & 0xf0) + (tmp_value & 0xf0) + 0x10; \ LOCAL_SET_ZERO(!((reg_a + tmp_value + (reg_p & 0x1)) & 0xff)); \ LOCAL_SET_SIGN(tmp & 0x80); \ LOCAL_SET_OVERFLOW(((reg_a ^ tmp) & 0x80) \ && !((reg_a ^ tmp_value) & 0x80)); \ if ((tmp & 0x1f0) > 0x90) \ tmp += 0x60; \ LOCAL_SET_CARRY((tmp & 0xff0) > 0xf0); \ } else { \ tmp = tmp_value + reg_a + (reg_p & P_CARRY); \ LOCAL_SET_NZ(tmp & 0xff); \ LOCAL_SET_OVERFLOW(!((reg_a ^ tmp_value) & 0x80) \ && ((reg_a ^ tmp) & 0x80)); \ LOCAL_SET_CARRY(tmp > 0xff); \ } \ reg_a = tmp; \ INC_PC(pc_inc); \ } while (0) #define ANC(value, clk_inc1, clk_inc2, pc_inc) \ do { \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ reg_a &= (value); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ LOCAL_SET_CARRY(LOCAL_SIGN()); \ INC_PC(pc_inc); \ } while (0) #define AND(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK += (clk_inc1); \ reg_a &= (value); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define ANE(value, clk_inc1, clk_inc2, pc_inc) \ do { \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ reg_a = ((reg_a | 0xee) & reg_x & (value)); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) /* The fanciest opcode ever... ARR! */ #define ARR(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ tmp = reg_a & (value); \ CLK += (clk_inc2); \ if (LOCAL_DECIMAL()) { \ int tmp_2 = tmp; \ tmp_2 |= (reg_p & P_CARRY) << 8; \ tmp_2 >>= 1; \ LOCAL_SET_SIGN(LOCAL_CARRY()); \ LOCAL_SET_ZERO(!tmp_2); \ LOCAL_SET_OVERFLOW((tmp_2 ^ tmp) & 0x40); \ if (((tmp & 0xf) + (tmp & 0x1)) > 0x5) \ tmp_2 = (tmp_2 & 0xf0) | ((tmp_2 + 0x6) & 0xf); \ if (((tmp & 0xf0) + (tmp & 0x10)) > 0x50) { \ tmp_2 = (tmp_2 & 0x0f) | ((tmp_2 + 0x60) & 0xf0); \ LOCAL_SET_CARRY(1); \ } else \ LOCAL_SET_CARRY(0); \ reg_a = tmp_2; \ } else { \ tmp |= (reg_p & P_CARRY) << 8; \ tmp >>= 1; \ LOCAL_SET_NZ(tmp); \ LOCAL_SET_CARRY(tmp & 0x40); \ LOCAL_SET_OVERFLOW((tmp & 0x40) ^ ((tmp & 0x20) << 1)); \ reg_a = tmp; \ } \ INC_PC(pc_inc); \ } while (0) #define ASL(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int tmp_value, tmp_addr; \ \ tmp_addr = (addr); \ CLK += (clk_inc1); \ tmp_value = load_func(tmp_addr); \ LOCAL_SET_CARRY(tmp_value & 0x80); \ tmp_value = (tmp_value << 1) & 0xff; \ LOCAL_SET_NZ(tmp_value); \ RMW_FLAG = 1; \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp_value, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define ASL_A() \ do { \ CLK += 2; \ LOCAL_SET_CARRY(reg_a & 0x80); \ reg_a <<= 1; \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) #define ASR(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ tmp = reg_a & (value); \ CLK += (clk_inc2); \ LOCAL_SET_CARRY(tmp & 0x01); \ reg_a = tmp >> 1; \ LOCAL_SET_NZ(reg_a); \ INC_PC(pc_inc); \ } while (0) #define BIT(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp = (value); \ CLK += (clk_inc2); \ LOCAL_SET_SIGN(tmp & 0x80); \ LOCAL_SET_OVERFLOW(tmp & 0x40); \ LOCAL_SET_ZERO(!(tmp & reg_a)); \ INC_PC(pc_inc); \ } while (0) #define BRANCH(cond, value) \ do { \ if (cond) { \ unsigned int dest_addr = reg_pc + 2 + (signed char)(value); \ \ if (((reg_pc + 2) ^ dest_addr) & 0xff00) { \ CLK += 4; \ } else { \ CLK += 3; \ OPCODE_DELAYS_INTERRUPT(); \ } \ reg_pc = dest_addr & 0xffff; \ } else { \ CLK += 2; \ INC_PC(2); \ } \ } while (0) /* The BRK opcode is also used to patch the ROM. The function trap_handler() returns nonzero if this is not a patch, but a `real' BRK instruction. */ #define BRK() \ do { \ CLK += 7; \ EXPORT_REGISTERS(); \ if (!ROM_TRAP_ALLOWED() || ROM_TRAP_HANDLER()) { \ INC_PC(2); \ LOCAL_SET_BREAK(1); \ PUSH(reg_pc >> 8); \ PUSH(reg_pc & 0xff); \ PUSH(LOCAL_STATUS()); \ LOCAL_SET_INTERRUPT(1); \ JUMP(LOAD_ADDR(0xfffe)); \ } else { \ IMPORT_REGISTERS(); \ } \ } while (0) #define CLC() \ do { \ CLK += 2; \ INC_PC(1); \ LOCAL_SET_CARRY(0); \ } while (0) #define CLD() \ do { \ CLK += 2; \ INC_PC(1); \ LOCAL_SET_DECIMAL(0); \ } while (0) #define CLI() \ do { \ CLK += 2; \ INC_PC(1); \ if (LOCAL_INTERRUPT()) \ OPCODE_ENABLES_IRQ(); \ LOCAL_SET_INTERRUPT(0); \ } while (0) #define CLV() \ do { \ CLK += 2; \ INC_PC(1); \ LOCAL_SET_OVERFLOW(0); \ } while (0) #define CMP(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp = reg_a - (value); \ LOCAL_SET_CARRY(tmp < 0x100); \ LOCAL_SET_NZ(tmp & 0xff); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define CPX(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp = reg_x - (value); \ LOCAL_SET_CARRY(tmp < 0x100); \ LOCAL_SET_NZ(tmp & 0xff); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define CPY(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp = reg_y - (value); \ LOCAL_SET_CARRY(tmp < 0x100); \ LOCAL_SET_NZ(tmp & 0xff); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define DCP(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int tmp, tmp_addr; \ \ tmp_addr = (addr); \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += (clk_inc1); \ tmp = load_func(tmp_addr); \ tmp = (tmp - 1) & 0xff; \ LOCAL_SET_CARRY(reg_a >= tmp); \ LOCAL_SET_NZ((reg_a - tmp)); \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp, (clk_inc2)); \ RMW_FLAG = 0; \ } while (0) #define DCP_IND_Y(addr) \ do { \ unsigned int tmp; \ unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += 5; \ LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y) & 0xff)); \ CLK++; \ tmp_addr += reg_y; \ tmp = LOAD(tmp_addr); \ tmp = (tmp - 1) & 0xff; \ LOCAL_SET_CARRY(reg_a >= tmp); \ LOCAL_SET_NZ((reg_a - tmp)); \ INC_PC(2); \ STORE_ABS(tmp_addr, tmp, 2); \ RMW_FLAG = 0; \ } while (0) #define DEC(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int tmp, tmp_addr; \ \ tmp_addr = (addr); \ CLK += (clk_inc1); \ tmp = load_func(tmp_addr); \ tmp = (tmp - 1) & 0xff; \ LOCAL_SET_NZ(tmp); \ RMW_FLAG = 1; \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp, (clk_inc2)); \ RMW_FLAG = 0; \ } while (0) #define DEX() \ do { \ CLK += 2; \ reg_x--; \ LOCAL_SET_NZ(reg_x); \ INC_PC(1); \ } while (0) #define DEY() \ do { \ CLK += 2; \ reg_y--; \ LOCAL_SET_NZ(reg_y); \ INC_PC(1); \ } while (0) #define EOR(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK += (clk_inc1); \ reg_a ^= (value); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define INC(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int tmp, tmp_addr; \ \ tmp_addr = (addr); \ CLK += (clk_inc1); \ tmp = (load_func(tmp_addr) + 1) & 0xff; \ LOCAL_SET_NZ(tmp); \ RMW_FLAG = 1; \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp, (clk_inc2)); \ RMW_FLAG = 0; \ } while (0) #define INX() \ do { \ CLK += 2; \ reg_x++; \ LOCAL_SET_NZ(reg_x); \ INC_PC(1); \ } while (0) #define INY() \ do { \ CLK += 2; \ reg_y++; \ LOCAL_SET_NZ(reg_y); \ INC_PC(1); \ } while (0) #define ISB(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ BYTE my_src; \ int my_addr = (addr); \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += (clk_inc1); \ my_src = load_func(my_addr); \ my_src = (my_src + 1) & 0xff; \ SBC(my_src, 0, 0, 0); \ INC_PC(pc_inc); \ store_func(my_addr, my_src, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define ISB_IND_Y(addr) \ do { \ BYTE my_src; \ int my_addr = LOAD_ZERO_ADDR(addr); \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += 5; \ LOAD((my_addr & 0xff00) | ((my_addr + reg_y) & 0xff)); \ CLK++; \ my_addr += reg_y; \ my_src = LOAD(my_addr); \ my_src = (my_src + 1) & 0xff; \ SBC(my_src, 0, 0, 0); \ INC_PC(2); \ STORE_ABS(my_addr, my_src, 2); \ RMW_FLAG = 0; \ } while (0) #define JMP(addr, clk_inc1, clk_inc2) \ do { \ CLK += (clk_inc1); \ JUMP(addr); \ CLK += (clk_inc2); \ } while (0) #define JSR(addr, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp_addr; \ \ CLK += (clk_inc1); \ tmp_addr = (addr); \ CLK += (clk_inc2); \ PUSH(((reg_pc + (pc_inc) - 1) >> 8) & 0xff); \ PUSH((reg_pc + (pc_inc) - 1) & 0xff); \ JUMP(tmp_addr); \ } while (0) #define LAS(value, clk_inc1, clk_inc2, pc_inc) \ do { \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ reg_a = reg_x = reg_sp = reg_sp & (value); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define LAX(value, clk_inc1, clk_inc2, pc_inc) \ do { \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ reg_a = reg_x = (value); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define LDA(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK += (clk_inc1); \ reg_a = (value); \ CLK += (clk_inc2); \ LOCAL_SET_NZ(reg_a); \ INC_PC(pc_inc); \ } while (0) #define LDX(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK += (clk_inc1); \ reg_x = (value); \ LOCAL_SET_NZ(reg_x); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define LDY(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK += (clk_inc1); \ reg_y = (value); \ LOCAL_SET_NZ(reg_y); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define LSR(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int tmp, tmp_addr; \ \ tmp_addr = (addr); \ RMW_FLAG = 1; \ CLK += (clk_inc1); \ tmp = load_func(tmp_addr); \ INC_PC(pc_inc); \ LOCAL_SET_CARRY(tmp & 0x01); \ tmp >>= 1; \ LOCAL_SET_NZ(tmp); \ store_func(tmp_addr, tmp, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define LSR_A() \ do { \ CLK += 2; \ LOCAL_SET_CARRY(reg_a & 0x01); \ reg_a >>= 1; \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) /* Note: this is not always exact, as this opcode can be quite unstable! Moreover, the behavior is different from the one described in 64doc. */ #define LXA(value, clk_inc1, clk_inc2, pc_inc) \ do { \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ reg_a = reg_x = ((reg_a | 0xee) & (value)); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define ORA(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK += (clk_inc1); \ reg_a |= (value); \ LOCAL_SET_NZ(reg_a); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define NOOP(clk_inc, pc_inc) \ (CLK += (clk_inc), INC_PC(pc_inc)) #define NOOP_ABS() \ do { \ CLK += 3; \ LOAD(p2); \ CLK++; \ INC_PC(3); \ } while (0) #define NOOP_ABS_X() \ do { \ CLK += 3; \ LOAD_ABS_X(p2); \ CLK++; \ INC_PC(3); \ } while (0) #define NOP() NOOP(2, 1) #define PHA() \ do { \ CLK += 3; \ PUSH(reg_a); \ INC_PC(1); \ } while (0) #define PHP() \ do { \ CLK += 3; \ PUSH(LOCAL_STATUS() | P_BREAK); \ INC_PC(1); \ } while (0) #define PLA() \ do { \ CLK += 4; \ reg_a = PULL(); \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) #define PLP() \ do { \ BYTE s = PULL(); \ \ if (!(s & P_INTERRUPT) && LOCAL_INTERRUPT()) \ OPCODE_ENABLES_IRQ(); \ else if ((s & P_INTERRUPT) && !LOCAL_INTERRUPT()) \ OPCODE_DISABLES_IRQ(); \ CLK += 4; \ LOCAL_SET_STATUS(s); \ INC_PC(1); \ } while (0) #define RLA(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int tmp, tmp_addr; \ \ tmp_addr = (addr); \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += (clk_inc1); \ tmp = ((load_func(tmp_addr) << 1) | (reg_p & P_CARRY)); \ LOCAL_SET_CARRY(tmp & 0x100); \ reg_a &= tmp; \ LOCAL_SET_NZ(reg_a); \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define RLA_IND_Y(addr) \ do { \ unsigned int tmp; \ unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += 5; \ LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y) & 0xff)); \ CLK++; \ tmp_addr += reg_y; \ tmp = ((LOAD(tmp_addr) << 1) | (reg_p & P_CARRY)); \ LOCAL_SET_CARRY(tmp & 0x100); \ reg_a &= tmp; \ LOCAL_SET_NZ(reg_a); \ INC_PC(2); \ STORE_ABS(tmp_addr, tmp, 2); \ RMW_FLAG = 1; \ } while (0) #define ROL(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int tmp, tmp_addr; \ \ tmp_addr = (addr); \ CLK += (clk_inc1); \ tmp = load_func(tmp_addr); \ tmp = (tmp << 1) | (reg_p & P_CARRY); \ LOCAL_SET_CARRY(tmp & 0x100); \ LOCAL_SET_NZ(tmp & 0xff); \ RMW_FLAG = 1; \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define ROL_A() \ do { \ unsigned int tmp = reg_a << 1; \ \ CLK += 2; \ reg_a = tmp | (reg_p & P_CARRY); \ LOCAL_SET_CARRY(tmp & 0x100); \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) #define ROR(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ unsigned int src, tmp_addr; \ \ tmp_addr = (addr); \ RMW_FLAG = 1; \ CLK += (clk_inc1); \ src = load_func(tmp_addr); \ if (reg_p & P_CARRY) \ src |= 0x100; \ LOCAL_SET_CARRY(src & 0x01); \ src >>= 1; \ LOCAL_SET_NZ(src); \ INC_PC(pc_inc); \ store_func(tmp_addr, src, (clk_inc2)); \ RMW_FLAG = 0; \ } while (0) #define ROR_A() \ do { \ BYTE tmp = reg_a; \ \ CLK += 2; \ reg_a = (reg_a >> 1) | (reg_p << 7); \ LOCAL_SET_CARRY(tmp & 0x01); \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) #define RRA(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ BYTE src; \ unsigned int my_temp, tmp_addr; \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += (clk_inc1); \ tmp_addr = (addr); \ src = load_func(tmp_addr); \ INC_PC(pc_inc); \ my_temp = src >> 1; \ if (reg_p & P_CARRY) \ my_temp |= 0x80; \ LOCAL_SET_CARRY(src & 0x1); \ ADC(my_temp, 0, 0, 0); \ store_func(tmp_addr, my_temp, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define RRA_IND_Y(addr) \ do { \ BYTE src; \ unsigned int my_tmp_addr; \ unsigned int my_temp; \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += 5; \ my_tmp_addr = LOAD_ZERO_ADDR(addr); \ LOAD((my_tmp_addr & 0xff00) | ((my_tmp_addr + reg_y) & 0xff)); \ CLK++; \ my_tmp_addr += reg_y; \ src = LOAD(my_tmp_addr); \ INC_PC(2); \ my_temp = src >> 1; \ if (reg_p & P_CARRY) \ my_temp |= 0x80; \ LOCAL_SET_CARRY(src & 0x1); \ ADC(my_temp, 0, 0, 0); \ STORE_ABS(my_tmp_addr, my_temp, 2); \ RMW_FLAG = 0; \ } while (0) /* RTI does must not use `OPCODE_ENABLES_IRQ()' even if the I flag changes from 1 to 0 because the value of I is set 3 cycles before the end of the opcode, and thus the 6510 has enough time to call the interrupt routine as soon as the opcode ends, if necessary. */ #define RTI() \ do { \ WORD tmp; \ \ CLK += 6; \ tmp = (WORD) PULL(); \ LOCAL_SET_STATUS((BYTE) tmp); \ tmp = (WORD) PULL(); \ tmp |= (WORD) PULL() << 8; \ JUMP(tmp); \ } while (0) #define RTS() \ do { \ WORD tmp; \ \ CLK += 6; \ tmp = PULL(); \ tmp = (tmp | (PULL() << 8)) + 1; \ JUMP(tmp); \ } while (0) #define SAX(addr, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ tmp = (addr); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ STORE(tmp, reg_a & reg_x); \ } while (0) #define SAX_ZERO(addr, clk_inc, pc_inc) \ do { \ UNDOC_WARNING(); \ CLK += (clk_inc); \ INC_PC(pc_inc); \ STORE_ZERO((addr), reg_a & reg_x); \ } while (0) #define SBC(value, clk_inc1, clk_inc2, pc_inc) \ do { \ WORD src, tmp; \ \ CLK += (clk_inc1); \ src = (value); \ CLK += (clk_inc2); \ tmp = reg_a - src - ((reg_p & P_CARRY) ? 0 : 1); \ if (reg_p & P_DECIMAL) { \ unsigned int tmp_a; \ tmp_a = (reg_a & 0xf) - (src & 0xf) - ((reg_p & P_CARRY) ? 0 : 1); \ if (tmp_a & 0x10) \ tmp_a = ((tmp_a - 6) & 0xf) \ | ((reg_a & 0xf0) - (src & 0xf0) - 0x10); \ else \ tmp_a = (tmp_a & 0xf) | ((reg_a & 0xf0) - (src & 0xf0)); \ if (tmp_a & 0x100) \ tmp_a -= 0x60; \ LOCAL_SET_CARRY(tmp < 0x100); \ LOCAL_SET_NZ(tmp & 0xff); \ LOCAL_SET_OVERFLOW(((reg_a ^ tmp) & 0x80) \ && ((reg_a ^ src) & 0x80)); \ reg_a = (BYTE) tmp_a; \ } else { \ LOCAL_SET_NZ(tmp & 0xff); \ LOCAL_SET_CARRY(tmp < 0x100); \ LOCAL_SET_OVERFLOW(((reg_a ^ tmp) & 0x80) \ && ((reg_a ^ src) & 0x80)); \ reg_a = (BYTE) tmp; \ } \ INC_PC(pc_inc); \ } \ while (0) #define SBX(value, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ tmp = (value); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ tmp = (reg_a & reg_x) - tmp; \ LOCAL_SET_CARRY(tmp < 0x100); \ reg_x = tmp & 0xff; \ LOCAL_SET_NZ(reg_x); \ } while (0) #undef SEC /* defined in time.h on SunOS. */ #define SEC() \ do { \ CLK += 2; \ LOCAL_SET_CARRY(1); \ INC_PC(1); \ } while (0) #define SED() \ do { \ CLK += 2; \ LOCAL_SET_DECIMAL(1); \ INC_PC(1); \ } while (0) #define SEI() \ do { \ CLK += 2; \ if (!LOCAL_INTERRUPT()) \ OPCODE_DISABLES_IRQ(); \ LOCAL_SET_INTERRUPT(1); \ INC_PC(1); \ } while (0) #define SHA_ABS_Y(addr) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ tmp = (addr); \ INC_PC(3); \ STORE_ABS_Y(tmp, reg_a & reg_x & (((tmp + reg_y) >> 8) + 1), 5); \ } while (0) #define SHA_IND_Y(addr) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ CLK += 5; \ tmp = LOAD_ZERO_ADDR(addr); \ LOAD((tmp & 0xff00) | ((tmp + reg_y) & 0xff)); \ CLK++; \ tmp += reg_y; \ INC_PC(2); \ STORE(tmp, reg_a & reg_x & ((tmp >> 8) + 1)); \ } while (0) #define SHX_ABS_Y(addr) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ tmp = (addr); \ INC_PC(3); \ STORE_ABS_Y(tmp, reg_x & (((tmp + reg_y) >> 8) + 1), 5); \ } while (0) #define SHY_ABS_X(addr) \ do { \ unsigned int tmp; \ \ UNDOC_WARNING(); \ tmp = (addr); \ INC_PC(3); \ STORE_ABS_X(tmp, reg_y & (((tmp + reg_x) >> 8) + 1), 5); \ } while (0) #define SHS_ABS_Y(addr) \ do { \ int tmp = (addr); \ \ UNDOC_WARNING(); \ INC_PC(3); \ STORE_ABS_Y(tmp, reg_a & reg_x & (((tmp + reg_y) >> 8) + 1), 5); \ reg_sp = reg_a & reg_x; \ } while (0) #define SLO(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ BYTE tmp_value; \ int tmp_addr; \ \ UNDOC_WARNING(); \ CLK += (clk_inc1); \ tmp_addr = (addr); \ tmp_value = load_func(tmp_addr); \ RMW_FLAG = 1; \ LOCAL_SET_CARRY(tmp_value & 0x80); \ tmp_value <<= 1; \ reg_a |= tmp_value; \ LOCAL_SET_NZ(reg_a); \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp_value, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define SLO_IND_Y(addr) \ do { \ BYTE tmp_value; \ unsigned int tmp_addr; \ \ UNDOC_WARNING(); \ CLK += 5; \ tmp_addr = LOAD_ZERO_ADDR(addr); \ LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y) & 0xff)); \ CLK++; \ tmp_addr += reg_y; \ tmp_value = LOAD(tmp_addr); \ RMW_FLAG = 1; \ LOCAL_SET_CARRY(tmp_value & 0x80); \ tmp_value <<= 1; \ reg_a |= tmp_value; \ LOCAL_SET_NZ(reg_a); \ INC_PC(2); \ STORE_ABS(tmp_addr, tmp_value, 2); \ RMW_FLAG = 0; \ } while (0) #define SRE(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ do { \ BYTE tmp; \ unsigned int tmp_addr; \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += (clk_inc1); \ tmp_addr = (addr); \ tmp = load_func(tmp_addr); \ LOCAL_SET_CARRY(tmp & 0x01); \ tmp >>= 1; \ reg_a ^= tmp; \ LOCAL_SET_NZ(reg_a); \ INC_PC(pc_inc); \ store_func(tmp_addr, tmp, clk_inc2); \ RMW_FLAG = 0; \ } while (0) #define SRE_IND_Y(addr) \ do { \ BYTE tmp; \ unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ \ UNDOC_WARNING(); \ RMW_FLAG = 1; \ CLK += 5; \ LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y) & 0xff)); \ CLK++; \ tmp_addr += reg_y; \ tmp = LOAD(tmp_addr); \ LOCAL_SET_CARRY(tmp & 0x01); \ tmp >>= 1; \ reg_a ^= tmp; \ LOCAL_SET_NZ(reg_a); \ INC_PC(2); \ STORE_ABS(tmp_addr, tmp, 2); \ RMW_FLAG = 0; \ } while (0) #define STA(addr, clk_inc1, clk_inc2, pc_inc, store_func) \ do { \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp = (addr); \ INC_PC(pc_inc); \ store_func(tmp, reg_a, clk_inc2); \ } while (0) #define STA_ZERO(addr, clk_inc, pc_inc) \ do { \ CLK += (clk_inc); \ STORE_ZERO((addr), reg_a); \ INC_PC(pc_inc); \ } while (0) #define STA_IND_Y(addr) \ do { \ unsigned int tmp; \ \ CLK += 5; \ tmp = LOAD_ZERO_ADDR(addr); \ LOAD((tmp & 0xff00) | ((tmp + reg_y) & 0xff)); \ CLK++; \ INC_PC(2); \ STORE(tmp + reg_y, reg_a); \ } while (0) #define STX(addr, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp = (addr); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ STORE(tmp, reg_x); \ } while (0) #define STX_ZERO(addr, clk_inc, pc_inc) \ do { \ CLK += (clk_inc); \ STORE_ZERO((addr), reg_x); \ INC_PC(pc_inc); \ } while (0) #define STY(addr, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ \ CLK += (clk_inc1); \ tmp = (addr); \ CLK += (clk_inc2); \ INC_PC(pc_inc); \ STORE(tmp, reg_y); \ } while (0) #define STY_ZERO(addr, clk_inc, pc_inc) \ do { \ CLK += (clk_inc); \ STORE_ZERO((addr), reg_y); \ INC_PC(pc_inc); \ } while (0) #define TAX() \ do { \ CLK += 2; \ reg_x = reg_a; \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) #define TAY() \ do { \ CLK += 2; \ reg_y = reg_a; \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) #define TSX() \ do { \ CLK += 2; \ reg_x = reg_sp; \ LOCAL_SET_NZ(reg_sp); \ INC_PC(1); \ } while (0) #define TXA() \ do { \ CLK += 2; \ reg_a = reg_x; \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) #define TXS() \ do { \ reg_sp = reg_x; \ CLK += 2; \ INC_PC(1); \ } while (0) #define TYA() \ do { \ CLK += 2; \ reg_a = reg_y; \ LOCAL_SET_NZ(reg_a); \ INC_PC(1); \ } while (0) /* ------------------------------------------------------------------------- */ #if !defined FETCH_OPCODE # if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS # define opcode_t DWORD # define FETCH_OPCODE(o) ((o) = (bank_base \ ? (*((DWORD *)(bank_base + reg_pc)) \ & 0xffffff) \ : (LOAD(reg_pc) \ | (LOAD(reg_pc + 1) << 8) \ | (LOAD(reg_pc + 2) << 16)))) # define p0 (opcode & 0xff) # define p1 ((opcode >> 8) & 0xff) # define p2 (opcode >> 8) # else /* WORDS_BIGENDIAN || ALLOW_UNALIGNED_ACCESS */ # define opcode_t \ struct { \ BYTE ins; \ union { \ BYTE op8[2]; \ WORD op16; \ } op; \ } # define FETCH_OPCODE(o) \ (bank_base ? ((o).ins = *(bank_base + reg_pc), \ (o).op.op16 = (*(bank_base + reg_pc + 1) \ | (*(bank_base + reg_pc + 2) << 8))) \ : ((o).ins = LOAD(reg_pc), \ (o).op.op16 = (LOAD(reg_pc + 1) \ | (LOAD(reg_pc + 2) << 8)))) # define p0 (opcode.ins) # define p2 (opcode.op.op16) # ifdef WORDS_BIGENDIAN # define p1 (opcode.op.op8[1]) # else # define p1 (opcode.op.op8[0]) # endif # endif /* !WORDS_BIGENDIAN */ #endif /* !FETCH_OPCODE */ /* ------------------------------------------------------------------------ */ /* Here, the CPU is emulated. */ { while (CLK >= next_alarm_clk(&CPU_INT_STATUS)) serve_next_alarm(&CPU_INT_STATUS, CLK); { enum cpu_int pending_interrupt; pending_interrupt = check_pending_interrupt(&CPU_INT_STATUS); if (pending_interrupt != IK_NONE) { DO_INTERRUPT(pending_interrupt); while (CLK >= next_alarm_clk(&CPU_INT_STATUS)) serve_next_alarm(&CPU_INT_STATUS, CLK); } } #ifdef EXECUTE_EXTERN EXECUTE_EXTERN(); #endif { opcode_t opcode; FETCH_OPCODE(opcode); #if defined(TRACE) #ifdef __1541__ if (TRACEFLG) { BYTE op = p0; BYTE lo = p1; BYTE hi = p2 >> 8; printf("1541: .%04X\t%ld\t%s\n", reg_pc, (long)true1541_clk, sprint_disassembled(reg_pc, op, lo, hi, 1)); } #else if (TRACEFLG) printf(".%04X\t%ld\t%s\tA=$%02X X=$%02X Y=$%02X\n", reg_pc, (long)clk, sprint_opcode(reg_pc, 1), reg_a, reg_x, reg_y); #endif #endif SET_LAST_OPCODE(p0); switch (p0) { #ifndef ONLY_LDA_BNE case 0x00: /* BRK */ BRK(); break; case 0x01: /* ORA ($nn,X) */ ORA(LOAD_IND_X(p1), 2, 4, 2); break; case 0x02: /* JAM */ JAM(); break; case 0x03: /* SLO ($nn,X) */ SLO(LOAD_ZERO_ADDR(p1 + reg_x), 2, 6, 2, LOAD_ABS, STORE_ABS); break; case 0x04: /* NOOP $nn */ NOOP(3, 2); break; case 0x05: /* ORA $nn */ ORA(LOAD_ZERO(p1), 2, 1, 2); break; case 0x06: /* ASL $nn */ ASL(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x07: /* SLO $nn */ SLO(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x08: /* PHP */ #ifdef __1541__ if (true1541_byte_ready()) LOCAL_SET_OVERFLOW(1); #endif PHP(); break; case 0x09: /* ORA #$nn */ ORA(p1, 2, 0, 2); break; case 0x0a: /* ASL A */ ASL_A(); break; case 0x0b: /* ANC #$nn */ ANC(p1, 2, 0, 2); break; case 0x0c: /* NOOP $nnnn */ NOOP_ABS(); break; case 0x0d: /* ORA $nnnn */ ORA(LOAD(p2), 3, 1, 3); break; case 0x0e: /* ASL $nnnn */ ASL(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x0f: /* SLO $nnnn */ SLO(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x10: /* BPL $nnnn */ BRANCH(!LOCAL_SIGN(), p1); break; case 0x11: /* ORA ($nn),Y */ ORA(LOAD_IND_Y(p1), 2, 3, 2); break; case 0x12: /* JAM */ JAM(); break; case 0x13: /* SLO ($nn),Y */ SLO_IND_Y(p1); break; case 0x14: /* NOOP $nn,X */ NOOP(4, 2); break; case 0x15: /* ORA $nn,X */ ORA(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0x16: /* ASL $nn,X */ ASL((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x17: /* SLO $nn,X */ SLO((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x18: /* CLC */ CLC(); break; case 0x19: /* ORA $nnnn,Y */ ORA(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0x1a: /* NOOP */ NOOP(2, 1); break; case 0x1b: /* SLO $nnnn,Y */ SLO(p2, 3, 3, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); break; case 0x1c: /* NOOP $nnnn,X */ NOOP_ABS_X(); break; case 0x1d: /* ORA $nnnn,X */ ORA(LOAD_ABS_X(p2), 3, 1, 3); break; case 0x1e: /* ASL $nnnn,X */ ASL(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x1f: /* SLO $nnnn,X */ SLO(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x20: /* JSR $nnnn */ JSR(p2, 3, 3, 3); break; case 0x21: /* AND ($nn,X) */ AND(LOAD_IND_X(p1), 2, 4, 2); break; case 0x22: /* JAM */ JAM(); break; case 0x23: /* RLA ($nn,X) */ RLA(LOAD_ZERO_ADDR(p1 + reg_x), 2, 6, 2, LOAD_ABS, STORE_ABS); break; case 0x24: /* BIT $nn */ BIT(LOAD_ZERO(p1), 2, 1, 2); break; case 0x25: /* AND $nn */ AND(LOAD_ZERO(p1), 2, 1, 2); break; case 0x26: /* ROL $nn */ ROL(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x27: /* RLA $nn */ RLA(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x28: /* PLP */ PLP(); break; case 0x29: /* AND #$nn */ AND(p1, 2, 0, 2); break; case 0x2a: /* ROL A */ ROL_A(); break; case 0x2b: /* ANC #$nn */ ANC(p1, 2, 0, 2); break; case 0x2c: /* BIT $nnnn */ BIT(LOAD(p2), 3, 1, 3); break; case 0x2d: /* AND $nnnn */ AND(LOAD(p2), 3, 1, 3); break; case 0x2e: /* ROL $nnnn */ ROL(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x2f: /* RLA $nnnn */ RLA(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x30: /* BMI $nnnn */ BRANCH(LOCAL_SIGN(), p1); break; case 0x31: /* AND ($nn),Y */ AND(LOAD_IND_Y(p1), 2, 3, 2); break; case 0x32: /* JAM */ JAM(); break; case 0x33: /* RLA ($nn),Y */ RLA_IND_Y(p1); break; case 0x34: /* NOOP */ NOOP(4, 2); break; case 0x35: /* AND $nn,X */ AND(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0x36: /* ROL $nn,X */ ROL((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x37: /* RLA $nn,X */ RLA((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x38: /* SEC */ SEC(); break; case 0x39: /* AND $nnnn,Y */ AND(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0x3a: /* NOOP */ NOOP(2, 1); break; case 0x3b: /* RLA $nnnn,Y */ RLA(p2, 3, 3, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); break; case 0x3c: /* NOOP $nnnn,X */ NOOP_ABS_X(); break; case 0x3d: /* AND $nnnn,X */ AND(LOAD_ABS_X(p2), 3, 1, 3); break; case 0x3e: /* ROL $nnnn,X */ ROL(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x3f: /* RLA $nnnn,X */ RLA(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x40: /* RTI */ RTI(); break; case 0x41: /* EOR ($nn,X) */ EOR(LOAD_IND_X(p1), 2, 4, 2); break; case 0x42: /* JAM */ JAM(); break; case 0x43: /* SRE ($nn,X) */ SRE(LOAD_ZERO_ADDR(p1 + reg_x), 2, 6, 2, LOAD_ABS, STORE_ABS); break; case 0x44: /* NOOP $nn */ NOOP(3, 2); break; case 0x45: /* EOR $nn */ EOR(LOAD_ZERO(p1), 2, 1, 2); break; case 0x46: /* LSR $nn */ LSR(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x47: /* SRE $nn */ SRE(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x48: /* PHA */ PHA(); break; case 0x49: /* EOR #$nn */ EOR(p1, 2, 0, 2); break; case 0x4a: /* LSR A */ LSR_A(); break; case 0x4b: /* ASR #$nn */ ASR(p1, 2, 0, 2); break; case 0x4c: /* JMP $nnnn */ JMP(p2, 3, 0); break; case 0x4d: /* EOR $nnnn */ EOR(LOAD(p2), 3, 1, 3); break; case 0x4e: /* LSR $nnnn */ LSR(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x4f: /* SRE $nnnn */ SRE(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x50: /* BVC $nnnn */ #ifndef __1541__ BRANCH(!LOCAL_OVERFLOW(), p1); #else if (true1541_byte_ready()) LOCAL_SET_OVERFLOW(1); BRANCH(!LOCAL_OVERFLOW(), p1); #endif break; case 0x51: /* EOR ($nn),Y */ EOR(LOAD_IND_Y(p1), 2, 3, 2); break; case 0x52: /* JAM */ JAM(); break; case 0x53: /* SRE ($nn),Y */ SRE_IND_Y(p1); break; case 0x54: /* NOOP $nn,X */ NOOP(4, 2); break; case 0x55: /* EOR $nn,X */ EOR(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0x56: /* LSR $nn,X */ LSR((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x57: /* SRE $nn,X */ SRE((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x58: /* CLI */ CLI(); break; case 0x59: /* EOR $nnnn,Y */ EOR(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0x5a: /* NOOP */ NOOP(2, 1); break; case 0x5b: /* SRE $nnnn,Y */ SRE(p2, 3, 3, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); break; case 0x5c: /* NOOP $nnnn,X */ NOOP_ABS_X(); break; case 0x5d: /* EOR $nnnn,X */ EOR(LOAD_ABS_X(p2), 3, 1, 3); break; case 0x5e: /* LSR $nnnn,X */ LSR(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x5f: /* SRE $nnnn,X */ SRE(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x60: /* RTS */ RTS(); break; case 0x61: /* ADC ($nn,X) */ ADC(LOAD_IND_X(p1), 2, 4, 2); break; case 0x62: /* JAM */ JAM(); break; case 0x63: /* RRA ($nn,X) */ RRA(LOAD_ZERO_ADDR(p1 + reg_x), 2, 6, 2, LOAD_ABS, STORE_ABS); break; case 0x64: /* NOOP $nn */ NOOP(3, 2); break; case 0x65: /* ADC $nn */ ADC(LOAD_ZERO(p1), 2, 1, 2); break; case 0x66: /* ROR $nn */ ROR(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x67: /* RRA $nn */ RRA(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0x68: /* PLA */ PLA(); break; case 0x69: /* ADC #$nn */ ADC(p1, 2, 0, 2); break; case 0x6a: /* ROR A */ ROR_A(); break; case 0x6b: /* ARR #$nn */ ARR(p1, 2, 0, 2); break; case 0x6c: /* JMP ($nnnn) */ /* FIXME: This is not correct (timing-wise). */ JMP(LOAD(p2) | (LOAD((p2 & 0xff00) | ((p2 + 1) & 0xff)) << 8), 3, 2); break; case 0x6d: /* ADC $nnnn */ ADC(LOAD(p2), 3, 1, 3); break; case 0x6e: /* ROR $nnnn */ ROR(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x6f: /* RRA $nnnn */ RRA(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0x70: /* BVS $nnnn */ #ifndef __1541__ BRANCH(LOCAL_OVERFLOW(), p1); #else if (true1541_byte_ready()) LOCAL_SET_OVERFLOW(1); BRANCH(LOCAL_OVERFLOW(), p1); #endif break; case 0x71: /* ADC ($nn),Y */ ADC(LOAD_IND_Y(p1), 2, 3, 2); break; case 0x72: /* JAM */ JAM(); break; case 0x73: /* RRA ($nn),Y */ RRA_IND_Y(p1); break; case 0x74: /* NOOP $nn,X */ NOOP(4, 2); break; case 0x75: /* ADC $nn,X */ ADC(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0x76: /* ROR $nn,X */ ROR((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x77: /* RRA $nn,X */ RRA((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0x78: /* SEI */ SEI(); break; case 0x79: /* ADC $nnnn,Y */ ADC(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0x7a: /* NOOP */ NOOP(2, 1); break; case 0x7b: /* RRA $nnnn,Y */ RRA(p2, 3, 3, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); break; case 0x7c: /* NOOP $nnnn,X */ NOOP_ABS_X(); break; case 0x7d: /* ADC $nnnn,X */ ADC(LOAD_ABS_X(p2), 3, 1, 3); break; case 0x7e: /* ROR $nnnn,X */ ROR(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x7f: /* RRA $nnnn,X */ RRA(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0x80: /* NOOP #$nn */ NOOP(2, 2); break; case 0x81: /* STA ($nn,X) */ STA(LOAD_ZERO_ADDR(p1 + reg_x), 2, 4, 2, STORE_ABS); break; case 0x82: /* NOOP #$nn */ NOOP(2, 2); break; case 0x83: /* SAX ($nn,X) */ SAX(LOAD_ZERO_ADDR(p1 + reg_x), 2, 4, 2); break; case 0x84: /* STY $nn */ STY_ZERO(p1, 3, 2); break; case 0x85: /* STA $nn */ STA_ZERO(p1, 3, 2); break; case 0x86: /* STX $nn */ STX_ZERO(p1, 3, 2); break; case 0x87: /* SAX $nn */ SAX_ZERO(p1, 3, 2); break; case 0x88: /* DEY */ DEY(); break; case 0x89: /* NOOP #$nn */ NOOP(2, 2); break; case 0x8a: /* TXA */ TXA(); break; case 0x8b: /* ANE #$nn */ ANE(p1, 2, 0, 2); break; case 0x8c: /* STY $nnnn */ STY(p2, 3, 1, 3); break; case 0x8d: /* STA $nnnn */ STA(p2, 3, 1, 3, STORE_ABS); break; case 0x8e: /* STX $nnnn */ STX(p2, 3, 1, 3); break; case 0x8f: /* SAX $nnnn */ SAX(p2, 3, 1, 3); break; case 0x90: /* BCC $nnnn */ BRANCH(!LOCAL_CARRY(), p1); break; case 0x91: /* STA ($nn),Y */ STA_IND_Y(p1); break; case 0x92: /* JAM */ JAM(); break; case 0x93: /* SHA ($nn),Y */ SHA_IND_Y(p1); break; case 0x94: /* STY $nn,X */ STY_ZERO(p1 + reg_x, 4, 2); break; case 0x95: /* STA $nn,X */ STA_ZERO(p1 + reg_x, 4, 2); break; case 0x96: /* STX $nn,Y */ STX_ZERO(p1 + reg_y, 4, 2); break; case 0x97: /* SAX $nn,Y */ SAX((p1 + reg_y) & 0xff, 2, 2, 2); break; case 0x98: /* TYA */ TYA(); break; case 0x99: /* STA $nnnn,Y */ STA(p2, 3, 2, 3, STORE_ABS_Y); break; case 0x9a: /* TXS */ TXS(); break; case 0x9b: /* SHS $nnnn,Y */ SHS_ABS_Y(p2); break; case 0x9c: /* SHY $nnnn,X */ SHY_ABS_X(p2); break; case 0x9d: /* STA $nnnn,X */ STA(p2, 3, 2, 3, STORE_ABS_X); break; case 0x9e: /* SHX $nnnn,Y */ SHX_ABS_Y(p2); break; case 0x9f: /* SHA $nnnn,Y */ SHA_ABS_Y(p2); break; case 0xa0: /* LDY #$nn */ LDY(p1, 2, 0, 2); break; case 0xa1: /* LDA ($nn,X) */ LDA(LOAD_IND_X(p1), 2, 4, 2); break; case 0xa2: /* LDX #$nn */ LDX(p1, 2, 0, 2); break; case 0xa3: /* LAX ($nn,X) */ LAX(LOAD_IND_X(p1), 2, 4, 2); break; case 0xa4: /* LDY $nn */ LDY(LOAD_ZERO(p1), 2, 1, 2); break; case 0xa5: /* LDA $nn */ LDA(LOAD_ZERO(p1), 2, 1, 2); break; case 0xa6: /* LDX $nn */ LDX(LOAD_ZERO(p1), 2, 1, 2); break; case 0xa7: /* LAX $nn */ LAX(LOAD_ZERO(p1), 2, 1, 2); break; case 0xa8: /* TAY */ TAY(); break; case 0xa9: /* LDA #$nn */ LDA(p1, 2, 0, 2); break; case 0xaa: /* TAX */ TAX(); break; case 0xab: /* LXA #$nn */ LXA(p1, 2, 0, 2); break; case 0xac: /* LDY $nnnn */ LDY(LOAD(p2), 3, 1, 3); break; #endif /* !ONLY_LDA_BNE */ case 0xad: /* LDA $nnnn */ LDA(LOAD(p2), 3, 1, 3); break; #ifndef ONLY_LDA_BNE case 0xae: /* LDX $nnnn */ LDX(LOAD(p2), 3, 1, 3); break; case 0xaf: /* LAX $nnnn */ LAX(LOAD(p2), 3, 1, 3); break; case 0xb0: /* BCS $nnnn */ BRANCH(LOCAL_CARRY(), p1); break; case 0xb1: /* LDA ($nn),Y */ LDA(LOAD_IND_Y(p1), 2, 3, 2); break; case 0xb2: /* JAM */ JAM(); break; case 0xb3: /* LAX ($nn),Y */ LAX(LOAD_IND_Y(p1), 2, 3, 2); break; case 0xb4: /* LDY $nn,X */ LDY(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0xb5: /* LDA $nn,X */ LDA(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0xb6: /* LDX $nn,Y */ LDX(LOAD_ZERO_Y(p1), 2, 2, 2); break; case 0xb7: /* LAX $nn,Y */ LAX(LOAD_ZERO_Y(p1), 2, 2, 2); break; case 0xb8: /* CLV */ CLV(); break; case 0xb9: /* LDA $nnnn,Y */ LDA(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0xba: /* TSX */ TSX(); break; case 0xbb: /* LAS $nnnn,Y */ LAS(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0xbc: /* LDY $nnnn,X */ LDY(LOAD_ABS_X(p2), 3, 1, 3); break; case 0xbd: /* LDA $nnnn,X */ LDA(LOAD_ABS_X(p2), 3, 1, 3); break; case 0xbe: /* LDX $nnnn,Y */ LDX(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0xbf: /* LAX $nnnn,Y */ LAX(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0xc0: /* CPY #$nn */ CPY(p1, 2, 0, 2); break; case 0xc1: /* CMP ($nn,X) */ CMP(LOAD_IND_X(p1), 2, 4, 2); break; case 0xc2: /* NOOP #$nn */ NOOP(2, 2); break; case 0xc3: /* DCP ($nn,X) */ DCP(LOAD_ZERO_ADDR(p1 + reg_x), 2, 6, 2, LOAD_ABS, STORE_ABS); break; case 0xc4: /* CPY $nn */ CPY(LOAD_ZERO(p1), 2, 1, 2); break; case 0xc5: /* CMP $nn */ CMP(LOAD_ZERO(p1), 2, 1, 2); break; case 0xc6: /* DEC $nn */ DEC(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0xc7: /* DCP $nn */ DCP(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0xc8: /* INY */ INY(); break; case 0xc9: /* CMP #$nn */ CMP(p1, 2, 0, 2); break; case 0xca: /* DEX */ DEX(); break; case 0xcb: /* SBX #$nn */ SBX(p1, 2, 0, 2); break; case 0xcc: /* CPY $nnnn */ CPY(LOAD(p2), 3, 1, 3); break; case 0xcd: /* CMP $nnnn */ CMP(LOAD(p2), 3, 1, 3); break; case 0xce: /* DEC $nnnn */ DEC(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0xcf: /* DCP $nnnn */ DCP(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; #endif /* !ONLY_LDA_BNE */ case 0xd0: /* BNE $nnnn */ BRANCH(!LOCAL_ZERO(), p1); break; #ifndef ONLY_LDA_BNE case 0xd1: /* CMP ($nn),Y */ CMP(LOAD_IND_Y(p1), 2, 3, 2); break; case 0xd2: /* JAM */ JAM(); break; case 0xd3: /* DCP ($nn),Y */ DCP_IND_Y(p1); break; case 0xd4: /* NOOP $nn,X */ NOOP(4, 2); break; case 0xd5: /* CMP $nn,X */ CMP(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0xd6: /* DEC $nn,X */ DEC((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ABS, STORE_ABS); break; case 0xd7: /* DCP $nn,X */ DCP((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ABS, STORE_ABS); break; case 0xd8: /* CLD */ CLD(); break; case 0xd9: /* CMP $nnnn,Y */ CMP(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0xda: /* NOOP */ NOOP(2, 1); break; case 0xdb: /* DCP $nnnn,Y */ DCP(p2, 3, 3, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); break; case 0xdc: /* NOOP $nnnn,X */ NOOP_ABS_X(); break; case 0xdd: /* CMP $nnnn,X */ CMP(LOAD_ABS_X(p2), 3, 1, 3); break; case 0xde: /* DEC $nnnn,X */ DEC(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0xdf: /* DCP $nnnn,X */ DCP(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0xe0: /* CPX #$nn */ CPX(p1, 2, 0, 2); break; case 0xe1: /* SBC ($nn,X) */ SBC(LOAD_IND_X(p1), 2, 4, 2); break; case 0xe2: /* NOOP #$nn */ NOOP(2, 2); break; case 0xe3: /* ISB ($nn,X) */ ISB(LOAD_ZERO_ADDR(p1 + reg_x), 2, 6, 2, LOAD_ABS, STORE_ABS); break; case 0xe4: /* CPX $nn */ CPX(LOAD_ZERO(p1), 2, 1, 2); break; case 0xe5: /* SBC $nn */ SBC(LOAD_ZERO(p1), 2, 1, 2); break; case 0xe6: /* INC $nn */ INC(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0xe7: /* ISB $nn */ ISB(p1, 2, 3, 2, LOAD_ZERO, STORE_ABS); break; case 0xe8: /* INX */ INX(); break; case 0xe9: /* SBC #$nn */ SBC(p1, 2, 0, 2); break; case 0xea: /* NOP */ NOP(); break; case 0xeb: /* USBC #$nn (same as SBC) */ SBC(p1, 2, 0, 2); break; case 0xec: /* CPX $nnnn */ CPX(LOAD(p2), 3, 1, 3); break; case 0xed: /* SBC $nnnn */ SBC(LOAD(p2), 3, 1, 3); break; case 0xee: /* INC $nnnn */ INC(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0xef: /* ISB $nnnn */ ISB(p2, 3, 3, 3, LOAD_ABS, STORE_ABS); break; case 0xf0: /* BEQ $nnnn */ BRANCH(LOCAL_ZERO(), p1); break; case 0xf1: /* SBC ($nn),Y */ SBC(LOAD_IND_Y(p1), 2, 3, 2); break; case 0xf2: /* JAM */ JAM(); break; case 0xf3: /* ISB ($nn),Y */ ISB_IND_Y(p1); break; case 0xf4: /* NOOP ($nn,X) */ NOOP(4, 2); break; case 0xf5: /* SBC $nn,X */ SBC(LOAD_ZERO_X(p1), 2, 2, 2); break; case 0xf6: /* INC $nn,X */ INC((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0xf7: /* ISB $nn,X */ ISB((p1 + reg_x) & 0xff, 2, 4, 2, LOAD_ZERO, STORE_ABS); break; case 0xf8: /* SED */ SED(); break; case 0xf9: /* SBC $nnnn,Y */ SBC(LOAD_ABS_Y(p2), 3, 1, 3); break; case 0xfa: /* NOOP */ NOOP(2, 1); break; case 0xfb: /* ISB $nnnn,Y */ ISB(p2, 3, 3, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); break; case 0xfc: /* NOOP $nnnn,X */ NOOP_ABS_X(); break; case 0xfd: /* SBC $nnnn,X */ SBC(LOAD_ABS_X(p2), 3, 1, 3); break; case 0xfe: /* INC $nnnn,X */ INC(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; case 0xff: /* ISB $nnnn,X */ ISB(p2, 3, 3, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); break; #endif /* !ONLY_LDA_BNE */ } } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.