ftp.nice.ch/pub/next/tools/emulators/vice.0.15.0.NeXT.sd.tgz#/vice-0.15.0/src/6510core.c

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.