/* m68k_cpu.c: 68k-CPU simulator

   Copyright (c) 2009-2010 Holger Veit

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   Holger Veit BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Holger Veit et al shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Holger Veit et al.

   04-Oct-09    HV      Initial version
   25-Apr-10    HV      Fixed LSR.W and ROXR.B instructions
   26-Jun-10    HV      Incomplete decoding of BCHG d,d instruction
   15-Jul-10    HV      IRQ logic loses lower prio interrupts
   17-Jul-10    HV      Implement Call/Exit Tracing with symbol table lookup
   17-Jul-10    HV      Mustn't grant interrupt at level == IPL
   18-Jul-10    HV      Broken address calculation for AIDX and EA_W_RMW, wonder why this didn't pop up earlier.
   20-Jul-10    HV      Corrected ADDQ.W/SUBQ.W for EA_ADIR, EOR.[WL]
   23-Jul-10    HV      Broken C code sequence in lsl.l
   23-Jul-10    HV      RTE didn't set/reset S bit 
*/

#include "m68k_cpu.h"

/* status reg flags */
#define FLAG_C          0x0001
#define FLAG_V          0x0002
#define FLAG_Z          0x0004
#define FLAG_N          0x0008
#define FLAG_X          0x0010
#define FLAG_I0         0x0100
#define FLAG_I1         0x0200
#define FLAG_I2         0x0400
#define FLAG_IPL_MASK   (FLAG_I0|FLAG_I1|FLAG_I2)
#define FLAG_S          0x2000
#define FLAG_T          0x8000
#define FLAG_T1         FLAG_T
#define FLAG_T0         0x4000

#define BIT7            0x80
#define BIT8            0x100
#define BIT15           0x8000
#define BIT16           0x10000
#define BIT31           0x80000000
#define BIT32           0x100000000LL

#define MASK_0(x)       ((x) & 1)
#define MASK_8U(x)      ((x) & 0xffffff00)
#define MASK_8L(x)      ((x) & 0x000000ff)
#define MASK_8SGN(x)    ((x) & BIT7)
#define MASK_9(x)       ((x) & BIT8)
#define MASK_16U(x)     ((x) & 0xffff0000)
#define MASK_16L(x)     ((x) & 0x0000ffff)
#define MASK_16SGN(x)   ((x) & BIT15)
#define MASK_17(x)      ((x) & BIT16)
#define MASK_32U(x)     (0)
#define MASK_32L(x)     ((x) & 0xffffffff)
#define MASK_32SGN(x)   ((x) & BIT31)
#define MASK_33(x64)    ((x64) & BIT32)

#define COMBINE8(tgt,src)  (MASK_8U(tgt) | MASK_8L(src))
#define COMBINE16(tgt,src) (MASK_16U(tgt) | MASK_16L(src))
#define COMBINE32(tgt,src) MASK_32L(src)

extern t_addr addrmask;

static t_addr addrmasks[] = {
    0x00ffffff,     /*68000*/
    0x000fffff,     /*68008*/
    0x00ffffff,     /*68010*/
    0xffffffff,     /*68020*/
    0xffffffff      /*68030*/
};

int16 cputype = CPU_TYPE_68000 >> UNIT_CPU_V_TYPE;

/* CPU data structures 
 * m68kcpu_dev      CPU device descriptor
 * m68kcpu_unit     CPU unit descriptor
 * m68kcpu_reg      CPU register list
 * m68kcpu_mod      CPU modifiers list
 */

UNIT *m68kcpu_unit;  /* must be set elsewhere */
DEVICE *m68kcpu_dev; /* must be set elsewhere */

void (*m68kcpu_trapcallback)(DEVICE* dptr,int trapnum) = 0;

/* register set */
int32   DR[8];
#define D0  DR[0]
#define D1  DR[1]
#define D2  DR[2]
#define D3  DR[3]
#define D4  DR[4]
#define D5  DR[5]
#define D6  DR[6]
#define D7  DR[7]
t_addr  AR[8];
#define A0  AR[0]
#define A1  AR[1]
#define A2  AR[2]
#define A3  AR[3]
#define A4  AR[4]
#define A5  AR[5]
#define A6  AR[6]
#define A7  AR[7]
t_addr  USP;
t_addr  *cur_sp;

uint16  SR;
#define CCR_C   (SR & FLAG_C)
#define CCR_V   (SR & FLAG_V)
#define CCR_Z   (SR & FLAG_Z)
#define CCR_N   (SR & FLAG_N)
#define CCR_X   (SR & FLAG_X)
#define SR_IPL  ((SR & FLAG_IPL_MASK)>>8)
#define SR_S    (SR & FLAG_S)
#define SR_T    (SR & FLAG_T)
#define SR_T0   (SR & FLAG_T0)
#define SR_T1   (SR & FLAG_T1)

#define ONEF(flag) SR |= (flag)
#define CLRF(flag) SR &= ~(flag)
#define SETF(cond,flag) if (cond) SR |= (flag); else SR &= ~(flag)
#define SETZ8(cond) if (MASK_8L(cond)) SR &= ~FLAG_Z; else SR |= FLAG_Z
#define SETZ16(cond) if (MASK_16L(cond)) SR &= ~FLAG_Z; else SR |= FLAG_Z
#define SETZ32(cond) if (MASK_32L(cond)) SR &= ~FLAG_Z; else SR |= FLAG_Z
#define SETNZ8(cond) SETZ8(cond); if (MASK_8SGN(cond)) SR |= FLAG_N; else SR &= ~FLAG_N
#define SETNZ16(cond) SETZ16(cond); if (MASK_16SGN(cond)) SR |= FLAG_N; else SR &= ~FLAG_N
#define SETNZ32(cond) SETZ32(cond); if (MASK_32SGN(cond)) SR |= FLAG_N; else SR &= ~FLAG_N
#define SETV_ADD8(a1,a2,r)  SETF(MASK_8SGN(((a1)^(r))&((a2)^(r))),FLAG_V);
#define SETV_ADD16(a1,a2,r) SETF(MASK_16SGN(((a1)^(r))&((a2)^(r))),FLAG_V);
#define SETV_ADD32(a1,a2,r) SETF(MASK_32SGN(((a1)^(r))&((a2)^(r))),FLAG_V);
#define SETV_SUB8(s,d,r)    SETF(MASK_8SGN(((s)^(d))&((r)^(d))),FLAG_V)
#define SETV_SUB16(s,d,r)   SETF(MASK_16SGN(((s)^(d))&((r)^(d))),FLAG_V)
#define SETV_SUB32(s,d,r)   SETF(MASK_32SGN(((s)^(d))&((r)^(d))),FLAG_V)

#define ASSERT_PRIV() if (!SR_S) { rc = STOP_PRVIO; break; }
#define ASSERT_OK(func) if ((rc=(func)) != SCPE_OK) break
#define ASSERT_OKRET(func) if ((rc=(func)) != SCPE_OK) return rc

#define AREG(r) (r==7 ? cur_sp : &AR[r])

uint16  SFC;
uint16  DFC;
uint32  VBR;
t_addr  saved_PC;
static t_bool intpending;
static int m68k_sublevel;

REG m68kcpu_reg[] = {
    { HRDATA (D0,       DR[0],      32)                 },
    { HRDATA (D1,       DR[1],      32)                 },
    { HRDATA (D2,       DR[2],      32)                 },
    { HRDATA (D3,       DR[3],      32)                 },
    { HRDATA (D4,       DR[4],      32)                 },
    { HRDATA (D5,       DR[5],      32)                 },
    { HRDATA (D6,       DR[6],      32)                 },
    { HRDATA (D7,       DR[7],      32)                 },
    { HRDATA (A0,       AR[0],      32)                 },
    { HRDATA (A1,       AR[1],      32)                 },
    { HRDATA (A2,       AR[2],      32)                 },
    { HRDATA (A3,       AR[3],      32)                 },
    { HRDATA (A4,       AR[4],      32)                 },
    { HRDATA (A5,       AR[5],      32)                 },
    { HRDATA (A6,       AR[6],      32)                 },
    { HRDATA (A7,       AR[7],      32)                 },
    { HRDATA (SSP,      AR[7],      32)                 },
    { HRDATA (USP,      USP,        32)                 },
    { HRDATA (PC,       saved_PC,   32)                 },
    { HRDATA (SR,       SR,         16)                 },
    { HRDATA (CCR,      SR,         8)                  },
    { FLDATA (C,        SR,         0)                  },
    { FLDATA (V,        SR,         1)                  },
    { FLDATA (Z,        SR,         2)                  },
    { FLDATA (N,        SR,         3)                  },
    { FLDATA (X,        SR,         4)                  },
    { GRDATA (IPL,      SR,         8,  3,  8)          },
    { FLDATA (S,        SR,         13)                 },
    { FLDATA (T,        SR,         15)                 },
    { HRDATA (SFC,      SFC,        3),     REG_HIDDEN  },
    { HRDATA (DFC,      DFC,        3),     REG_HIDDEN  },
    { HRDATA (VBR,      VBR,        32),    REG_RO      },
    { FLDATA (IRQPEN,   intpending, 0),     REG_HIDDEN  },
    { NULL }
};

DEBTAB m68kcpu_dt[] = {
    { "EXC",    DBG_CPU_EXC    },
    { "PC",     DBG_CPU_PC     },
    { "INT",    DBG_CPU_INT    },
    { "CTRACE", DBG_CPU_CTRACE },
    { "BTRACE", DBG_CPU_BTRACE },
    { NULL,     0              }
};

static const char *condnames[] = {
        "RA", "SR", "HI", "LS", "CC", "CS", "NE", "EQ", "VC", "VS", "PL", "MI", "GE", "LT", "GT", "LE"
};

#if 0
/* sample code */
static MTAB m68kcpu_mod[] = {
    M68KCPU_STDMOD,
    { 0 }
};

DEVICE m68kcpu_dev = {
    "CPU", &m68kcpu_unit, m68kcpu_reg, m68kcpu_mod,
    1, 16, 32, 2, 16, 16,
    &m68kcpu_ex, &m68kcpu_dep, &m68kcpu_reset,
    &m68kcpu_boot, NULL, NULL,
    NULL, DEV_DEBUG, 0,
    m68kcpu_dt, NULL, NULL
};
#endif

static DEVICE* cpudev_self = 0;

t_stat m68kcpu_peripheral_reset()
{
    t_stat rc;
    DEVICE** devs = sim_devices;
    DEVICE* dptr;
    
    while ((dptr = *devs) != NULL) {
        if (dptr != cpudev_self) { 
            ASSERT_OKRET(dptr->reset(dptr));
        }
        devs++;
    }
    return SCPE_OK;
}

/* simple prefetch I cache */
#define CACHE_SIZE 16
#define CACHE_MASK 0x0f

static t_addr cache_pc;
static uint8 cache_line[CACHE_SIZE];

static t_stat ReadICache(t_addr tpc)
{
    int i;
    t_stat rc;
    uint8* mem;

    ASSERT_OKRET(Mem((tpc+CACHE_SIZE-1)&addrmask,&mem));
    
    /* 68000/08/10 do not like unaligned access */
    if (cputype < 3 && (tpc & 1)) return STOP_ERRADR;
    
    for (i=CACHE_SIZE-1; i>=0; i--) {
        cache_line[i] = *mem--; 
    }
//  for (i=0; i<16; i++) printf("icache[%d]=0x%08x\n",i,cache_line[i]);
    return SCPE_OK;
}

static t_stat ReadInstr(t_addr pc,uint32* inst)
{
    t_stat rc;
    t_addr tpc;
    IOHANDLER* ioh;
    
    if ((rc=TranslateAddr(pc & ~CACHE_MASK,&tpc,&ioh,MEM_READ,FALSE,FALSE)) != SCPE_OK)
        return rc==SIM_ISIO ? STOP_PCIO : rc;
    if (tpc != cache_pc) {
        ASSERT_OKRET(ReadICache(tpc));
    }
    pc &= CACHE_MASK;
    *inst = (cache_line[pc]<<8) | cache_line[pc+1];
    return SCPE_OK;
}

static t_stat ReadInstrInc(t_addr* pc,uint32* inst)
{
    t_stat rc;
    ASSERT_OKRET(ReadInstr(*pc,inst));
    *pc += 2;
    return SCPE_OK;
}

static t_stat ReadInstrLongInc(t_addr* pc,uint32* inst)
{
    t_stat rc;
    uint32 val1,val2;
    ASSERT_OKRET(ReadInstr(*pc,&val1));
    *pc += 2;
    ASSERT_OKRET(ReadInstr(*pc,&val2));
    *pc += 2;
    *inst = COMBINE16(val1<<16,val2);
    return SCPE_OK;
}


void m68k_set_s(t_bool tf)
{
    if (tf) {
        SR |= FLAG_S;
        cur_sp = &A7;
    } else {
        SR &= ~FLAG_S;
        cur_sp = &USP;
    }
}

void m68k_setipl(int ipl)
{
//  printf("set ipl to %d\n",ipl);
    SR &= ~FLAG_IPL_MASK;
    SR |= (ipl & 7) << 8;
}

/* interrupt logic */
static int intvectors[8];

static t_stat m68k_irqinit()
{
    int i;
    for (i=0; i<8; i++) intvectors[i] = 0;
    intpending = 0;
    return SCPE_OK;
}

t_stat m68k_raise_vectorint(int level,int vector)
{
    int mask = 1<<level;
    IFDEBUG(DBG_CPU_INT,fprintf(sim_deb,"CPU : [0x%08x] Interrupt: request level=%d, IPL=%d, vec=%d, pending=%x\n",
            saved_PC,level,SR_IPL,vector,intpending));
    if ((intpending & mask) == 0) {
        intvectors[level] = vector;
        intpending |= mask;
    }
    return SCPE_OK;
}

t_stat m68k_raise_autoint(int level)
{
    return m68k_raise_vectorint(level,level+24);
}

static void m68k_nocallback(DEVICE* dev,int trapnum)
{
    /* do nothing */
}

/* reset and boot */
t_stat m68kcpu_reset(DEVICE* dptr) 
{
    t_stat rc;
    uint32 dummy;
    
    cpudev_self = dptr;

    sim_brk_types = SWMASK('E')|SWMASK('R')|SWMASK('W');
    sim_brk_dflt = SWMASK('E');
    
    addrmask = addrmasks[cputype];

    ASSERT_OKRET(m68k_alloc_mem());
    ASSERT_OKRET(m68k_ioinit());

    m68kcpu_trapcallback = &m68k_nocallback;
    
    m68k_sublevel = 0;
    
    /* TODO: 68010 VBR */
    ReadPL(0,&A7);
    ReadPL(4,&saved_PC);
    ReadInstr(saved_PC,&dummy); /* fill prefetch cache */
    m68k_irqinit();             /* reset interrupt flags */
    m68k_set_s(TRUE);           /* reset to supervisor mode */
    return SCPE_OK;
}

t_stat m68kcpu_boot(int32 unitno,DEVICE* dptr)
{
    return dptr->reset(dptr);
}

/* for instruction decoder */
#define IR_1512     (IR&0170000)
#define IR_1109     (IR&0007000)
#define IR_1108     (IR&0007400)
#define IR_1106     (IR&0007700)
#define IR_1103     (IR&0007770)
#define IR_08       (IR&0000400)
#define IR_0806     (IR&0000700)
#define IR_0803     (IR&0000770)
#define IR_0706     (IR&0000300)
#define IR_0703     (IR&0000370)
#define IR_0503     (IR&0000070)
#define IR_080403   (IR&0000430)
#define IR_08060403 (IR&0000730)
#define IR_0200     (IR&0000007)
#define IR_EAMOD    (IR&0000070)
#define IR_0503     (IR&0000070)
#define IR_COND     (IR&0007400)
#define IR_EA       (IR&0000077)
#define IR_EAM12    (IR&0000060)
#define IR_EAREG    (IR&0000007)
#define IR_DISP     (IR&0000377)
#define IR_EATGT   ((IR&0000700)>>3)
#define IR_REGX    ((IR&0007000)>>9)
#define IR_REGY     (IR&0000007)
#define IR_TRAP     (IR&0000017)
#define IR_SIZE    ((IR&0000300)>>6)
#define IR_DATA     (IR&0000377)
#define IRE_DA      (IRE&0100000)
#define IRE_REG    ((IRE&0070000)>>12)
#define IRE_WL      (IRE&0004000)
#define IRE_DISP    (IRE&0000377)

/* EA modes */
#define EA_DDIR     0000
#define EA_ADIR     0010
#define EA_AIND     0020
#define EA_API      0030
#define EA_APD      0040
#define EA_AIDX     0050
#define EA_AXIDX    0060
#define EA_EXT      0070
#define EA_IMM      0074
#define EAX_AW      000
#define EAX_AL      001
#define EAX_PCIDX   002
#define EAX_PCXIDX  003
#define EAX_IMM     004

#define EXTB(x)     ((int32)((int8)((x)&0xff)))
#define EXTW(x)     ((int32)((int16)((x)&0xffff)))

#define DRX         DR[IR_REGX]
#define DRY         DR[IR_REGY]

static uint32 quickarg[] = { 8,1,2,3,4,5,6,7 };
static int32  shmask8[]  = { 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
static int32  shmask16[] = { 0x0000,
                             0x8000,0xc000,0xe000,0xf000,0xf800,0xfc00,0xfe00,0xff00,
                             0xff80,0xffc0,0xffe0,0xfff0,0xff80,0xffc0,0xffe0,0xffff,
                             0xffff };
static int32  shmask32[] = { 0x00000000,
                             0x80000000,0xc0000000,0xe0000000,0xf0000000,
                             0xf8000000,0xfc000000,0xfe000000,0xff000000,
                             0xff800000,0xffc00000,0xffe00000,0xfff00000,
                             0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,
                             0xffff8000,0xffffc000,0xffffe000,0xfffff000,
                             0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,
                             0xffffff80,0xffffffc0,0xffffffe0,0xfffffff0,
                             0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff,
                             0xffffffff };
static int32  bitmask[]  = { 0x00000000,
                             0x00000001,0x00000002,0x00000004,0x00000008,
                             0x00000010,0x00000020,0x00000040,0x00000080,
                             0x00000100,0x00000200,0x00000400,0x00000800,
                             0x00001000,0x00002000,0x00004000,0x00000800,
                             0x00010000,0x00020000,0x00040000,0x00008000,
                             0x00100000,0x00200000,0x00400000,0x00080000,
                             0x01000000,0x02000000,0x04000000,0x00800000,
                             0x10000000,0x20000000,0x40000000,0x80000000,
                             0x00000000 };

static t_addr saved_ea;

static t_stat ea_src_b(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc)
{
    t_stat rc = SCPE_OK;
    uint32 reg, regno, IRE;
    t_addr *areg;
//  printf("src eamod=%x eareg=%x\n",eamod,eareg);
    switch (eamod) {
    case EA_DDIR:
        *val = MASK_8L(DR[eareg]);
        return SCPE_OK;
    case EA_ADIR:
        *val = MASK_8L(*AREG(eareg));
        return SCPE_OK;
    case EA_AIND:
        return ReadVB(saved_ea = *AREG(eareg),val);
    case EA_API:
        areg = AREG(eareg);
        rc = ReadVB(saved_ea = *areg,val);
        *areg += (eareg==7 ? 2 : 1);
        return rc;
    case EA_APD:
        areg = AREG(eareg);
        *areg -= (eareg==7 ? 2 : 1);
        return ReadVB(saved_ea = *areg,val);
    case EA_AIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        return ReadVB(saved_ea = *AREG(eareg)+EXTW(IRE),val);
    case EA_AXIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        regno = IRE_REG;
        reg = IRE_DA ? *AREG(regno) : DR[regno];
        if (!IRE_WL) reg = EXTW(reg);
        return ReadVB(saved_ea = *AREG(eareg) + EXTW(IRE_DISP) + reg, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            saved_ea = EXTW(IRE);
            rc = ReadVB(saved_ea, val);
            return rc;
        case EAX_AL:
            ASSERT_OKRET(ReadPL(*pc,&IRE));
            *pc += 4;
            return ReadVB(saved_ea = IRE, val);
        case EAX_PCIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return ReadVB(saved_ea = *pc-2 + EXTW(IRE), val);
        case EAX_PCXIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            regno = IRE_REG;
            reg = (IRE_DA) ? *AREG(regno) : DR[regno];
            if (!IRE_WL) reg = EXTW(reg);
            return ReadVB(saved_ea = *pc-2 + EXTW(IRE_DISP) + reg, val);
        case EAX_IMM:
            ASSERT_OKRET(ReadInstrInc(pc,val));
            *val = MASK_8L(*val);
            return SCPE_OK;
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_src_bs(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc)
{
    if (eamod==EA_EXT && eareg==EAX_IMM) {
        *val = MASK_8L(SR);
        return SCPE_OK;
    }
    return ea_src_b(eamod,eareg,val,pc);
}

static t_stat ea_src_w(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc)
{
    t_stat rc = SCPE_OK;
    uint32 reg, regno, IRE;
    t_addr *areg;

    switch (eamod) {
    case EA_DDIR:
        *val = MASK_16L(DR[eareg]);
        return SCPE_OK;
    case EA_ADIR:
        *val = MASK_16L(*AREG(eareg));
        return SCPE_OK;
    case EA_AIND:
        return ReadVW(saved_ea = *AREG(eareg), val);
    case EA_API:
        areg = AREG(eareg);
        rc = ReadVW(saved_ea = *areg, val);
        *areg += 2;
        return rc;
    case EA_APD:
        areg = AREG(eareg);
        *areg -= 2;
        return ReadVW(saved_ea = *areg, val);
    case EA_AIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        return ReadVW(saved_ea = *AREG(eareg) + EXTW(IRE), val);
    case EA_AXIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        regno = IRE_REG;
        reg = IRE_DA ? *AREG(regno) : DR[regno];
        if (!IRE_WL) reg = EXTW(reg);
        return ReadVW(saved_ea = *AREG(eareg) + EXTW(IRE_DISP) + reg, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return ReadVW(saved_ea = EXTW(IRE), val);
        case EAX_AL:
            ASSERT_OKRET(ReadPL(*pc,&IRE));
            *pc += 4;
            return ReadVW(saved_ea = IRE, val);
        case EAX_PCIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return ReadVW(saved_ea = *pc-2 + EXTW(IRE), val);
        case EAX_PCXIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            regno = IRE_REG;
            reg = (IRE_DA) ? *AREG(regno) : DR[regno];
            if (!IRE_WL) reg = EXTW(reg);
            return ReadVW(saved_ea = *pc-2 + EXTW(IRE_DISP) + reg, val);
        case EAX_IMM:
            return ReadInstrInc(pc,val);
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_src_ws(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc)
{
    if (eamod==EA_EXT && eareg==EAX_IMM) {
        *val = SR;
        return SCPE_OK;
    }
    return ea_src_w(eamod,eareg,val,pc);
}

/* non dereferencing version of ea_src_l, only accepts ea category control */
static t_stat ea_src_l_nd(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc)
{
    t_stat rc = SCPE_OK;
    uint32 reg, regno, IRE;

    switch (eamod) {
    case EA_AIND:
        *val = *AREG(eareg);
        return SCPE_OK;
    case EA_AIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        *val = *AREG(eareg) + EXTW(IRE);
        return SCPE_OK;
    case EA_AXIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        regno = IRE_REG;
        reg = IRE_DA ? *AREG(regno) : DR[regno];
        if (!IRE_WL) reg = EXTW(reg);
        *val = *AREG(eareg) + EXTW(IRE_DISP) + reg;
        return SCPE_OK;
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            *val = EXTW(IRE);
            return SCPE_OK;
        case EAX_AL:
            ASSERT_OKRET(ReadPL(*pc,val));
            *pc += 4;
            return SCPE_OK;
        case EAX_PCIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            *val = *pc-2 + EXTW(IRE);
            return SCPE_OK;
        case EAX_PCXIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            regno = IRE_REG;
            reg = (IRE_DA) ? *AREG(regno) : DR[regno];
            if (!IRE_WL) reg = EXTW(reg);
            *val = *pc-2 + EXTW(IRE_DISP) + reg;
            return SCPE_OK;
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_src_l(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc)
{
    t_stat rc = SCPE_OK;
    uint32 reg, regno, IRE;
    t_addr *areg;

    switch (eamod) {
    case EA_DDIR:
        *val = DR[eareg];
        return SCPE_OK;
    case EA_ADIR:
        *val = *AREG(eareg);
        return SCPE_OK;
    case EA_AIND:
        return ReadVL(saved_ea = *AREG(eareg), val);
    case EA_API:
        areg = AREG(eareg);
        rc = ReadVL(saved_ea = *areg, val);
        *areg += 4;
        return rc;
    case EA_APD:
        areg = AREG(eareg);
        *areg -= 4;
        return ReadVL(saved_ea = *areg, val);
    case EA_AIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        return ReadVL(saved_ea = *AREG(eareg) + EXTW(IRE), val);
    case EA_AXIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        regno = IRE_REG;
        reg = IRE_DA ? *AREG(regno) : DR[regno];
        if (!IRE_WL) reg = EXTW(reg);
        return ReadVL(saved_ea = *AREG(eareg) + EXTW(IRE_DISP) + reg, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return ReadVL(saved_ea = EXTW(IRE), val);
        case EAX_AL:
            ASSERT_OKRET(ReadPL(*pc,&IRE));
            *pc += 4;
            return ReadVL(saved_ea = IRE, val);
        case EAX_PCIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return ReadVL(saved_ea = *pc-2 + EXTW(IRE), val);
        case EAX_PCXIDX:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            regno = IRE_REG;
            reg = (IRE_DA) ? *AREG(regno) : DR[regno];
            if (!IRE_WL) reg = EXTW(reg);
            return ReadVL(saved_ea = *pc-2 + EXTW(IRE_DISP) + reg, val);
        case EAX_IMM:
            ASSERT_OKRET(ReadVL(*pc,val));
            *pc += 4;
            return SCPE_OK;
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_src_l64(uint32 eamod,uint32 eareg,t_uint64* val64,t_addr* pc)
{
    uint32 val32;
    t_stat rc = ea_src_l(eamod,eareg,&val32,pc);
    *val64 = (t_uint64)val32;
    return rc;
}

t_stat ea_src(uint32 eamod,uint32 eareg,uint32* val,int sz,t_addr* pc)
{
    switch (sz) {
    case SZ_BYTE:
        return ea_src_b(eamod,eareg,val,pc);
    case SZ_WORD:
        return ea_src_w(eamod,eareg,val,pc);
    case SZ_LONG:
        return ea_src_l(eamod,eareg,val,pc);
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_dst_b(uint32 eamod,uint32 eareg,uint32 val,t_addr* pc)
{
    t_stat rc;
    uint32 IRE,reg,regno;
    t_addr *areg;

//  printf("dst: eamod=%x eareg=%x\n",eamod,eareg);
//  printf("val=%x\n",val);
    switch (eamod) {
    case EA_DDIR:
        DR[eareg] = COMBINE8(DR[eareg],val);
        return SCPE_OK;
    case EA_AIND:
        return WriteVB(*AREG(eareg), val);
    case EA_API:
        areg = AREG(eareg);
        rc = WriteVB(*areg, val);
        *areg += (eareg==7 ? 2 : 1);
        return rc;
    case EA_APD:
        areg = AREG(eareg);
        *areg -= (eareg==7 ? 2 : 1);
        return WriteVB(*areg, val);
    case EA_AIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        return WriteVB(*AREG(eareg) + EXTW(IRE), val);
    case EA_AXIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        regno = IRE_REG;
        reg = IRE_DA ? *AREG(regno) : DR[regno];
        if (!IRE_WL) reg = EXTW(reg);
        return WriteVB(*AREG(eareg) + EXTW(IRE_DISP) + reg, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return WriteVB(EXTW(IRE), val);
        case EAX_AL:
            ASSERT_OKRET(ReadPL(*pc,&IRE));
            *pc += 4;
            return WriteVB(IRE, val);
        default:
            return STOP_ERROP;
        }
    case EA_ADIR:
    default:
        return STOP_ERROP;
    }
}

t_stat ea_dst_b_rmw(uint32 eamod,uint32 eareg,uint32 val)
{
    switch (eamod) {
    case EA_DDIR:
        DR[eareg] = COMBINE8(DR[eareg],val);
        return SCPE_OK;
    case EA_AIND:
    case EA_API:
    case EA_APD:
    case EA_AIDX:
    case EA_AXIDX:
        return WriteVB(saved_ea, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
        case EAX_AL:
            return WriteVB(saved_ea, val);
        case EAX_IMM:
            SR = COMBINE8(SR,val);
            return SCPE_OK;
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_dst_w(uint32 eamod,uint32 eareg,uint32 val,t_addr* pc)
{
    t_stat rc;
    uint32 IRE,reg,regno;
    t_addr *areg;

    switch (eamod) {
    case EA_DDIR:
        DR[eareg] = COMBINE16(DR[eareg],val);
        return SCPE_OK;
    case EA_ADIR:
        *AREG(eareg) = COMBINE16(*AREG(eareg),val);
//      *AREG(eareg) = EXTW(val);
        return SCPE_OK;
    case EA_AIND:
        return WriteVW(*AREG(eareg), val);
    case EA_API:
        areg = AREG(eareg);
        rc = WriteVW(*areg, val);
        *areg += 2;
        return rc;
    case EA_APD:
        areg = AREG(eareg);
        *areg -= 2;
        return WriteVW(*areg, val);
    case EA_AIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        return WriteVW(*AREG(eareg) + EXTW(IRE), val);
    case EA_AXIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        regno = IRE_REG;
        reg = IRE_DA ? *AREG(regno) : DR[regno];
        if (!IRE_WL) reg = EXTW(reg);
        return WriteVW(*AREG(eareg) + EXTW(IRE_DISP) + reg, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return WriteVW(EXTW(IRE), val);
        case EAX_AL:
            ASSERT_OKRET(ReadPL(*pc,&IRE));
            *pc += 4;
            return WriteVW(IRE, val);
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_dst_w_rmw(uint32 eamod,uint32 eareg,uint32 val)
{
    switch (eamod) {
    case EA_DDIR:
        DR[eareg] = COMBINE16(DR[eareg],val);
        return SCPE_OK;
    case EA_ADIR:
        printf("ea_dst_w_rmw EA_ADIR: pc=%x\n",saved_PC);
        *AREG(eareg) = val; /* use full 32 bits even for word operand */
        return SCPE_OK;
    case EA_AIND:
    case EA_API:
    case EA_APD:
    case EA_AIDX:
    case EA_AXIDX:
        return WriteVW(saved_ea, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
        case EAX_AL:
            return WriteVW(saved_ea, val);
        case EAX_IMM:
            SR = val;
            return SCPE_OK;
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

static t_stat ea_dst_l(uint32 eamod,uint32 eareg,uint32 val,t_addr* pc)
{
    t_stat rc;
    uint32 IRE,reg,regno;
    t_addr *areg;

    switch (eamod) {
    case EA_DDIR:
        DR[eareg] = val;
        return SCPE_OK;
    case EA_ADIR:
        *AREG(eareg) = val;
        return SCPE_OK;
    case EA_AIND:
        return WriteVL(*AREG(eareg), val);
    case EA_API:
        areg = AREG(eareg);
        rc = WriteVL(*areg, val);
        *areg += 4;
        return rc;
    case EA_APD:
        areg = AREG(eareg);
        *areg -= 4;
        return WriteVL(*areg, val);
    case EA_AIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        return WriteVL(*AREG(eareg) + EXTW(IRE), val);
    case EA_AXIDX:
        ASSERT_OKRET(ReadInstrInc(pc,&IRE));
        regno = IRE_REG;
        reg = IRE_DA ? *AREG(regno) : DR[regno];
        if (!IRE_WL) reg = EXTW(reg);
        return WriteVL(*AREG(eareg) + EXTW(IRE_DISP) + reg, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
            ASSERT_OKRET(ReadInstrInc(pc,&IRE));
            return WriteVL(EXTW(IRE), val);
        case EAX_AL:
            ASSERT_OKRET(ReadPL(*pc,&IRE));
            *pc += 4;
            return WriteVL(IRE, val);
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

t_stat ea_dst_l_rmw(uint32 eamod,uint32 eareg,uint32 val)
{

    switch (eamod) {
    case EA_DDIR:
        DR[eareg] = val;
        return SCPE_OK;
    case EA_ADIR:
        *AREG(eareg) = val;
        return SCPE_OK;
    case EA_AIND:
    case EA_API:
    case EA_APD:
    case EA_AIDX:
    case EA_AXIDX:
        return WriteVL(saved_ea, val);
    case EA_EXT:
        switch (eareg) {
        case EAX_AW:
        case EAX_AL:
            return WriteVL(saved_ea, val);
        default:
            return STOP_ERROP;
        }
    default:
        return STOP_ERROP;
    }
}

t_stat ea_dst(uint32 eamod,uint32 eareg,uint32 val,int sz,t_addr* pc)
{
    switch (sz) {
    case SZ_BYTE:
        return ea_dst_b(eamod,eareg,val,pc);
    case SZ_WORD:
        return ea_dst_w(eamod,eareg,val,pc);
    case SZ_LONG:
        return ea_dst_l(eamod,eareg,val,pc);
    default:
        return STOP_ERROP;
    }
}

static t_bool testcond(uint32 c)
{
    int n,v;
    
    switch (c) {
    case 0x0000: /*T*/
        return TRUE;
    case 0x0100: /*F*/
        return FALSE;
    case 0x0200: /*HI*/
        return !(CCR_C || CCR_Z);
    case 0x0300: /*LS*/
        return CCR_C || CCR_Z;
    case 0x0400: /*CC*/
        return !CCR_C;
    case 0x0500: /*CS*/
        return CCR_C;
    case 0x0600: /*NE*/
        return !CCR_Z;
    case 0x0700: /*EQ*/
        return CCR_Z;
    case 0x0800: /*VC*/
        return !CCR_V;
    case 0x0900: /*VS*/
        return CCR_V;
    case 0x0a00: /*PL*/
        return !CCR_N;
    case 0x0b00: /*MI*/
        return CCR_N;
    case 0x0c00: /*GE*/
        n = CCR_N; v = CCR_V;
        return (n && v) || !(n || v); 
    case 0x0d00: /*LT*/
        n = CCR_N; v = CCR_V;
        return (n && !v) || (!n && v); 
    case 0x0e00: /*GT*/
        n = CCR_N; v = CCR_V;
        return !CCR_Z && (n || !v) && (!n || v);
    case 0x0f00: /*LE*/
        n = CCR_N; v = CCR_V;
        return CCR_Z || (!n && v) || (n && !v);
    default: /*notreached*/
        return FALSE;
    }
}

/* push/pop on supervisor sp */
static t_stat m68k_push16(uint32 data)
{
    A7 -= 2;
    return WriteVW(A7,data);
}

static t_stat m68k_push32(uint32 data)
{
    A7 -= 4;
    return WriteVL(A7,data);
}

static t_stat m68k_pop16(uint32* data)
{
    A7 += 2;
    return ReadVW(A7-2,data);
}

static t_stat m68k_pop32(uint32* data)
{
    A7 += 4;
    return ReadVL(A7-4,data);
}

/* push/pop on current sp */
t_stat m68k_cpush16(uint32 data)
{
    *cur_sp -= 2;
    return WriteVW(*cur_sp,data);
}

static t_stat m68k_cpush32(uint32 data)
{
    *cur_sp -= 4;
    return WriteVL(*cur_sp,data);
}

static t_stat m68k_cpop16(uint32* data)
{
    *cur_sp += 2;
    return ReadVW(*cur_sp-2,data);
}

static t_stat m68k_cpop32(uint32* data)
{
    *cur_sp += 4;
    return ReadVL(*cur_sp-4,data);
}

t_stat m68k_gen_exception(int vecno,t_addr* pc)
{
    t_stat rc;
    uint32 dummy;
    t_addr oldpc = *pc;
    char out[20];
    
    /* @TODO VBR! */
    if (cputype<2) {
        ASSERT_OKRET(m68k_push32(*pc));
        ASSERT_OKRET(m68k_push16(SR));
        m68k_set_s(TRUE);
        CLRF(FLAG_T0|FLAG_T1);
    } else {
        /* no support for 68010 and above yet */
        return STOP_IMPL;
    }

    /* set the new PC */
    ASSERT_OKRET(ReadPL(vecno<<2,pc));
    IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: vec=%d to %s\n",oldpc,vecno,m68k_getsym(*pc,XFMT,out)));
    return ReadInstr(*pc,&dummy); /* fill prefetch cache */
}

static uint32 m68k_add8(uint32 src1,uint32 src2,uint32 x)
{
    uint32 res = MASK_8L(src1) + MASK_8L(src2) + x;
    SETNZ8(res);
    SETF(MASK_9(res),FLAG_C|FLAG_X);
    SETV_ADD8(src1,src2,res);
    return res;
}

static uint32 m68k_add16(uint32 src1,uint32 src2,uint32 x,t_bool chgflags)
{
    uint32 res = MASK_16L(src1) + MASK_16L(src2) + x;
    if (chgflags) {
        SETNZ16(res);
        SETF(MASK_17(res),FLAG_C|FLAG_X);
        SETV_ADD16(src1,src2,res);
    }
    return res;
}

static uint32 m68k_add32(t_uint64 src1,t_uint64 src2,t_uint64 x,t_bool chgflags)
{
    t_uint64 resx = MASK_32L(src1) + MASK_32L(src2) + x;
    if (chgflags) {
        SETNZ32(resx);
        SETF(MASK_33(resx),FLAG_C|FLAG_X);
        SETV_ADD32(src1,src2,resx);
    }
    return (uint32)resx;
}

static uint32 m68k_sub8(uint32 dst,uint32 src,uint32 x)
{
    uint32 res = MASK_8L(dst) - MASK_8L(src) - x;
    SETNZ8(res);
    SETF(MASK_9(res),FLAG_C|FLAG_X);
    SETV_SUB8(src,dst,res);
    return res;
}

static uint32 m68k_sub16(uint32 dst,uint32 src,uint32 x,t_bool chgflags)
{
    uint32 res = MASK_16L(dst) - MASK_16L(src) - x;
    if (chgflags) {
        SETNZ16(res);
        SETF(MASK_17(res),FLAG_C|FLAG_X);
        SETV_SUB16(src,dst,res);
    }
    return res;
}

static uint32 m68k_sub32(t_uint64 dst,t_uint64 src, t_uint64 x,t_bool chgflags)
{
    t_uint64 resx = MASK_32L(dst) - MASK_32L(src) - x;
    if (chgflags) {
        SETNZ32(resx);
        SETF(MASK_33(resx),FLAG_C|FLAG_X);
        SETV_SUB32(src,dst,resx);
    }
    return (uint32)resx;
}

static uint32* movem_regs[] = {
        (uint32*)&D0, (uint32*)&D1, (uint32*)&D2, (uint32*)&D3, (uint32*)&D4, (uint32*)&D5, (uint32*)&D6, (uint32*)&D7,
        (uint32*)&A0, (uint32*)&A1, (uint32*)&A2, (uint32*)&A3, (uint32*)&A4, (uint32*)&A5, (uint32*)&A6, 0
};

static t_stat m68k_movem_r_pd(t_addr* areg,uint32 regs,t_bool sz)
{
    int i;
    t_stat rc;
    t_addr ea = *areg;
    movem_regs[15] = cur_sp;
    for (i=0; i<16; i++) {
        if (regs & (1<<i)) {
            if (sz) {
                ea -= 4;
                ASSERT_OK(WriteVL(ea, *movem_regs[15-i]));
            } else {
                ea -= 2;
                ASSERT_OK(WriteVW(ea, *movem_regs[15-i]));
            }
        }
    }
    *areg = ea;
    return SCPE_OK;
}

static t_stat m68k_movem_r_ea(t_addr ea,uint32 regs,t_bool sz)
{
    int i;
    t_stat rc;
    movem_regs[15] = cur_sp;
    for (i=0; i<16; i++) {
        if (regs & (1<<i)) {
            if (sz) {
                ASSERT_OK(WriteVL(ea, *movem_regs[i]));
                ea += 4;
            } else {
                ASSERT_OK(WriteVW(ea, *movem_regs[i]));
                ea += 2;
            }
        }
    }
    return SCPE_OK;
}

static t_stat m68k_movem_pi_r(t_addr* areg,uint32 regs,t_bool sz)
{
    int i;
    t_addr ea = *areg;
    uint32 src;
    t_stat rc;
    movem_regs[15] = cur_sp;
    for (i=0; i<16; i++) {
        if (regs & (1<<i)) {
            if (sz) {
                ASSERT_OK(ReadVL(ea, movem_regs[i]));
                ea += 4;
            } else {
                ASSERT_OK(ReadVW(ea, &src));
                *movem_regs[i] = EXTW(src);
                ea += 2;
            }
        }
    }
    *areg = ea;
    return SCPE_OK;
}

static t_stat m68k_movem_ea_r(t_addr ea,uint32 regs,t_bool sz)
{
    int i;
    uint32 src;
    t_stat rc;
    movem_regs[15] = cur_sp;
    for (i=0; i<16; i++) {
        if (regs & (1<<i)) {
            if (sz) {
                ASSERT_OK(ReadVL(ea, movem_regs[i]));
                ea += 4;
            } else {
                ASSERT_OK(ReadVW(ea, &src));
                *movem_regs[i] = EXTW(src);
                ea += 2;
            }
        }
    }
    return SCPE_OK;
}

static t_stat m68k_divu_w(uint32 divdr,int32* reg, t_addr* pc)
{
    uint32 quo,rem,*dst;

    dst = (uint32*)reg;
    divdr = MASK_16L(divdr);
    if (divdr==0) return m68k_gen_exception(5,pc);

    quo = *dst / divdr;
    rem = (*dst % divdr)<<16;
    if (MASK_16U(quo)) ONEF(FLAG_V);
    else {
        SETNZ16(quo);
        CLRF(FLAG_V|FLAG_C);
        *dst = COMBINE16(rem,quo);
    }
    return SCPE_OK; 
}

static t_stat m68k_divs_w(uint32 divdr,int32* reg, t_addr* pc)
{
    int32 quo,rem,div;
    
    div = EXTW(divdr);
    if (div==0) return m68k_gen_exception(5,pc);
    if (*reg==0x80000000 && div==0xffffffff) {
        CLRF(FLAG_Z|FLAG_N|FLAG_V|FLAG_C);
        *reg = 0;
        return SCPE_OK;
    }
    
    quo = *reg / divdr;
    rem = (*reg % divdr)<<16;
    if (EXTW(quo) == quo) {
        SETNZ16(quo);
        CLRF(FLAG_V|FLAG_C);
        *reg = COMBINE16(rem,quo);
    } else ONEF(FLAG_V);
    return SCPE_OK;
}

static t_bool m68k_checkints(t_addr* pc)
{
    int i;
    if (intpending) {
        for (i=7; i>=1; i--) {
            if (intpending & (1<<i) && (i==7 || i > SR_IPL)) {
                /* found a pending irq at level i, that must be serviced now  */
                IFDEBUG(DBG_CPU_INT,fprintf(sim_deb,"CPU : [0x%08x] Interrupt: granting level=%d, IPL=%d, pending=%x\n",
                        *pc,i,SR_IPL,intpending));
                m68k_gen_exception(intvectors[i],pc); /* generate an exception */
                intpending &= ~(1<<i);
                intvectors[i] = 0; /* mark it as handled */
                m68k_setipl(i); /* set new interrupt prio, to leave out lower prio interrupts */
                return TRUE;
            }
        }
    }
    return intpending != 0;
}

/* handle stop instruction */
static t_stat m68k_stop(t_addr* pc)
{
    t_stat rc = SCPE_OK;
    t_addr oldpc = *pc;
    IFDEBUG(DBG_CPU_INT,fprintf(sim_deb,"CPU : [0x%08x] STOP: SR=0x%04x\n",oldpc-4,SR));
    for (;;) {
        /* is there an interrupt above IPL (checked in raise_vectorint) ? */
        if (m68k_checkints(pc)) break;
        
        /* loop until something is happening */
        if (sim_interval <= 0 && (rc=sim_process_event())) break;
        sim_interval--;
    }
    IFDEBUG(DBG_CPU_INT,fprintf(sim_deb,"CPU : [0x%08x] STOP: will continue at 0x%08x intpending=%x rc=%d\n",*pc,oldpc,intpending,rc));
    return rc;
}

t_stat sim_instr()
{
    t_stat rc;
    uint32 IR, IRE, src1, src2, res, ea;
    int32 sres, *reg, cnt;
    t_uint64 resx, srcx1, srcx2;
    t_addr PC, srca, *areg, oldpc;
    t_bool isbsr,iscond;
    uint16 tracet0;
    char out[20];
    
    /* restore state */
    PC = saved_PC;
    rc = 0;
    tracet0 = 0;

    /* the big main loop */
    while (rc == SCPE_OK) {
        saved_PC = PC;
        
        /* expired? */
        if (sim_interval <= 0) {
            if ((rc = sim_process_event())) break;
        }
        /* process breakpoints */
        if (sim_brk_summ && sim_brk_test(PC, E_BKPT_SPC|SWMASK('E'))) {
            rc = STOP_IBKPT;
            break;
        }
        
        /* opcode fetch */
        ASSERT_OK(ReadInstrInc(&PC,&IR));
        IFDEBUG(DBG_CPU_PC,fprintf(sim_deb,"DEBUG(PC): PC=%x IR=%x\n",PC-2,IR));
        
        sim_interval--;
        
        /* now decode instruction */
        switch (IR_1512) {
        /*   15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0   
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   0   0   0 | Opcode    | 0 |Length | effective address     | addi,andi,cmpi,eori,ori,subi
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   0   0   0 | Register  | 1 |Opcode | effective address<>001| bchg,bclr,bset,btst
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   0   0   0 | Register  | 1 |Opcode |  0  0   1 | Register  | movep
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x0000:
            switch (IR_1103) {
            case 0000400: case 0001400: case 0002400: case 0003400:
            case 0004400: case 0005400: case 0006400: case 0007400: /* btst d,d */
                cnt = DRX & 0x1f;
                goto do_btstd;
            case 0004000: /* btst #,d */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                cnt = IRE & 0x1f;
do_btstd:       SETZ32(DRY & bitmask[cnt+1]);
                rc = SCPE_OK; break;
            case 0000420: case 0000430: case 0000440: case 0000450:
            case 0000460: case 0000470: case 0001420: case 0001430: 
            case 0001440: case 0001450: case 0001460: case 0001470: 
            case 0002420: case 0002430: case 0002440: case 0002450:
            case 0002460: case 0002470: case 0003420: case 0003430:
            case 0003440: case 0003450: case 0003460: case 0003470: 
            case 0004420: case 0004430: case 0004440: case 0004450:
            case 0004460: case 0004470: case 0005420: case 0005430:
            case 0005440: case 0005450: case 0005460: case 0005470: 
            case 0006420: case 0006430: case 0006440: case 0006450:
            case 0006460: case 0006470: case 0007420: case 0007430:
            case 0007440: case 0007450: case 0007460: case 0007470: /* btst d,ea */
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                cnt = DRX & 7;
                goto do_btst8;
            case 0004020: case 0004030: case 0004040: case 0004050:
            case 0004060: case 0004070: /* btst #,ea */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                cnt = IRE & 7;
do_btst8:       SETZ8(src1 & bitmask[cnt+1]);
                rc = SCPE_OK;
                break;

            case 0000700: case 0001700: case 0002700: case 0003700:
            case 0004700: case 0005700: case 0006700: case 0007700: /* bset d,d */
                cnt = DRX & 0x1f;
                src1 = bitmask[cnt+1];
                goto do_bsetd;
            case 0004300: /* bset #,d */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                src1 = bitmask[(IRE & 0x1f)+1];
do_bsetd:       reg = &DRY;
                SETZ32(*reg & src1);
                *reg |= src1;
                rc = SCPE_OK; break;
            case 0000720: case 0000730: case 0000740: case 0000750:
            case 0000760: case 0000770: case 0001720: case 0001730:
            case 0001740: case 0001750: case 0001760: case 0001770: 
            case 0002720: case 0002730: case 0002740: case 0002750:
            case 0002760: case 0002770: case 0003720: case 0003730:
            case 0003740: case 0003750: case 0003760: case 0003770: 
            case 0004720: case 0004730: case 0004740: case 0004750:
            case 0004760: case 0004770: case 0005720: case 0005730:
            case 0005740: case 0005750: case 0005760: case 0005770: 
            case 0006720: case 0006730: case 0006740: case 0006750:
            case 0006760: case 0006770: case 0007720: case 0007730:
            case 0007740: case 0007750: case 0007760: case 0007770: /* bset d,ea */
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC));
                cnt = DRY & 7;
                src1 = bitmask[cnt+1];
                goto do_bset8;
            case 0004320: case 0004330: case 0004340: case 0004350:
            case 0004360: case 0004370: /* bset # */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC));
                src1 = bitmask[(IRE&7)+1];
do_bset8:       SETZ8(res & src1);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res | src1); break;
                
            case 0000500: case 0001500: case 0002500: case 0003500:
            case 0004500: case 0005500: case 0006500: case 0007500: /* bchg d,d */
                cnt = DRX & 0x1f;
                src1 = bitmask[cnt+1];
                goto do_bchgd;
            case 0004100: /* bchg #,d */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                src1 = bitmask[(IRE & 0x1f)+1];
do_bchgd:       reg = &DRY;
                SETZ32(*reg & src1);
                *reg ^= src1;
                rc = SCPE_OK; break;
            case 0000520: case 0000530: case 0000540: case 0000550:
            case 0000560: case 0000570: case 0001520: case 0001530:
            case 0001540: case 0001550: case 0001560: case 0001570: 
            case 0002520: case 0002530: case 0002540: case 0002550:
            case 0002560: case 0002570: case 0003520: case 0003530:
            case 0003540: case 0003550: case 0003560: case 0003570: 
            case 0004520: case 0004530: case 0004540: case 0004550:
            case 0004560: case 0004570: case 0005520: case 0005530:
            case 0005540: case 0005550: case 0005560: case 0005570: 
            case 0006520: case 0006530: case 0006540: case 0006550:
            case 0006560: case 0006570: case 0007520: case 0007530:
            case 0007540: case 0007550: case 0007560: case 0007570: /* bchg d,ea */
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC));
                cnt = DRX & 7;
                src1 = bitmask[cnt+1];
                goto do_bchg8;
            case 0004120: case 0004130: case 0004140: case 0004150:
            case 0004160: case 0004170: /* bchg #,ea */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC));
                src1 = bitmask[(IRE&7)+1];
do_bchg8:       SETZ8(res & src1);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res ^ src1); break;

            case 0000600: case 0001600: case 0002600: case 0003600:
            case 0004600: case 0005600: case 0006600: case 0007600: /* bclr d,d */ 
                cnt = DRX & 0x1f;
                src1 = bitmask[cnt+1];
                goto do_bclrd;
            case 0004200: /* bclr #,d */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                src1 = bitmask[(IRE & 0x1f)+1];
do_bclrd:       reg = &DRY;
                SETZ32(*reg & src1);
                *reg &= ~src1;
                rc = SCPE_OK; break;
            case 0000620: case 0000630: case 0000640: case 0000650:
            case 0000660: case 0000670: case 0001620: case 0001630:
            case 0001640: case 0001650: case 0001660: case 0001670:
            case 0002620: case 0002630: case 0002640: case 0002650:
            case 0002660: case 0002670: case 0003620: case 0003630:
            case 0003640: case 0003650: case 0003660: case 0003670:
            case 0004620: case 0004630: case 0004640: case 0004650:
            case 0004660: case 0004670: case 0005620: case 0005630:
            case 0005640: case 0005650: case 0005660: case 0005670:
            case 0006620: case 0006630: case 0006640: case 0006650:
            case 0006660: case 0006670: case 0007620: case 0007630:
            case 0007640: case 0007650: case 0007660: case 0007670: /* bclr d,ea */
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC));
                cnt = DRX & 7;
                src1 = bitmask[cnt+1];
                goto do_bclr8;
            case 0004220: case 0004230: case 0004240: case 0004250:
            case 0004260: case 0004270: /* bclr #,ea */
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC));
                src1 = bitmask[(IRE&7)+1];
do_bclr8:       SETZ8(res & src1);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res & ~src1); break;
                
            case 0000410: case 0001410: case 0002410: case 0003410:
            case 0004410: case 0005410: case 0006410: case 0007410: /*movep.w m,r*/
                ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                ASSERT_OK(ReadVB(srca,&src1));
                reg = &DRX;
                *reg = src1<<8;
                rc = ReadVB(srca+2,&src1);
                *reg = COMBINE8(*reg,src1);
                break;
            case 0000510: case 0001510: case 0002510: case 0003510:
            case 0004510: case 0005510: case 0006510: case 0007510: /*movep.l m,r*/
                ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                ASSERT_OK(ReadVB(srca,&src1));
                reg = &DRX;
                *reg = src1<<8;
                ASSERT_OK(ReadVB(srca+2,&src1));
                *reg = (COMBINE8(*reg,src1))<<8;
                ASSERT_OK(ReadVB(srca+4,&src1));
                *reg = (COMBINE8(*reg,src1))<<8;
                rc = ReadVB(srca+6,&src1);
                *reg = (COMBINE8(*reg,src1))<<8;
                break;
            case 0000610: case 0001610: case 0002610: case 0003610:
            case 0004610: case 0005610: case 0006610: case 0007610: /*movep.w r,m*/
                ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                src1 = DRX;
                ASSERT_OK(WriteVB(srca,src1>>8));
                rc = WriteVB(srca+2,src1); break;
            case 0000710: case 0001710: case 0002710: case 0003710:
            case 0004710: case 0005710: case 0006710: case 0007710: /*movep.l r,m*/
                ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                ASSERT_OK(WriteVB(srca,src1>>24));
                ASSERT_OK(WriteVB(srca+2,src1>>16));
                ASSERT_OK(WriteVB(srca+4,src1>>8));
                rc = WriteVB(srca+6,src1); break;
            
            case 0000000: case 0000020: case 0000030: case 0000040:
            case 0000050: case 0000060: case 0000070: /*ori.b*/
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_bs(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 | src2;
                if (IR_EA != EA_IMM) {
                    SETNZ8(res);
                    CLRF(FLAG_C|FLAG_V);
                }
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                tracet0 = SR_T0; break;
            case 0000100: case 0000120: case 0000130: case 0000140:
            case 0000150: case 0000160: case 0000170: /*ori.w*/
                if (IR_EA == EA_IMM) ASSERT_PRIV();
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_ws(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 | src2;
                if (IR_EA != EA_IMM) {
                    SETNZ16(res);
                    CLRF(FLAG_C|FLAG_V);
                }
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                tracet0 = SR_T0; break;
            case 0000200: case 0000220: case 0000230: case 0000240:
            case 0000250: case 0000260: case 0000270: /*ori.l*/
                ASSERT_OK(ReadInstrLongInc(&PC,&src2));
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 | src2;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); break;

            case 0001000: case 0001020: case 0001030: case 0001040:
            case 0001050: case 0001060: case 0001070: /*andi.b*/
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_bs(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 & src2;
                if (IR_EA != EA_IMM) {
                    SETNZ8(res);
                    CLRF(FLAG_C|FLAG_V);
                }
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                tracet0 = SR_T0; break;
            case 0001100: case 0001120: case 0001130: case 0001140:
            case 0001150: case 0001160: case 0001170: /*andi.w*/
                if (IR_EA==EA_IMM) ASSERT_PRIV();
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_ws(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 & src2;
                if (IR_EA != EA_IMM) {
                    SETNZ16(res);
                    CLRF(FLAG_C|FLAG_V);
                }
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                tracet0 = SR_T0; break;
            case 0001200: case 0001220: case 0001230: case 0001240:
            case 0001250: case 0001260: case 0001270: /*andi.l*/
                ASSERT_OK(ReadInstrLongInc(&PC,&src2));
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 & src2;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;

            case 0006000: case 0006020: case 0006030: case 0006040:
            case 0006050: case 0006060: case 0006070: /*cmpi.b*/
            case 0002000: case 0002020: case 0002030: case 0002040:
            case 0002050: case 0002060: case 0002070: /*subi.b*/
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_sub8(src1,src2,0);
                rc = IR_1103 < 0006000 ? ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res) : SCPE_OK; 
                break;
            case 0006100: case 0006120: case 0006130: case 0006140:
            case 0006150: case 0006160: case 0006170: /*cmpi.w*/
            case 0002100: case 0002120: case 0002130: case 0002140:
            case 0002150: case 0002160: case 0002170: /*subi.w*/
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_sub16(src1,src2,0,TRUE);
                rc = IR_1103 < 0006000 ? ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res) : SCPE_OK; 
                break;
            case 0006200: case 0006220: case 0006230: case 0006240:
            case 0006250: case 0006260: case 0006270: /*cmpi.l*/
            case 0002200: case 0002220: case 0002230: case 0002240:
            case 0002250: case 0002260: case 0002270: /*subi.l*/
                ASSERT_OK(ReadInstrLongInc(&PC,&src2));
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_sub32(srcx1,(t_uint64)src2,0,TRUE);
                rc = IR_1103 < 0006000 ? ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res) : SCPE_OK; 
                break;

            case 0003000: case 0003020: case 0003030: case 0003040:
            case 0003050: case 0003060: case 0003070: /*addi.b*/
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_add8(src1,src2,0);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); break;
            case 0003100: case 0003120: case 0003130: case 0003140:
            case 0003150: case 0003160: case 0003170: /*addi.w*/
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_add16(src1,src2,0,TRUE);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); break;
            case 0003200: case 0003220: case 0003230: case 0003240:
            case 0003250: case 0003260: case 0003270: /*addi.l*/
                ASSERT_OK(ReadInstrLongInc(&PC,&src2));
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_add32(srcx1,(t_uint64)src2,0,TRUE);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0005000: case 0005020: case 0005030: case 0005040:
            case 0005050: case 0005060: case 0005070: /*eori.b*/
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_bs(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 ^ src2;
                if (IR_EA != EA_IMM) {
                    SETNZ8(res);
                    CLRF(FLAG_C|FLAG_V);
                }
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                tracet0 = SR_T0; break;
            case 0005100: case 0005120: case 0005130: case 0005140:
            case 0005150: case 0005160: case 0005170: /*eori.w*/
                if (IR_EA==EA_IMM) ASSERT_PRIV();
                ASSERT_OK(ReadInstrInc(&PC,&src2));
                ASSERT_OK(ea_src_ws(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 ^ src2;
                if (IR_EA != EA_IMM) {
                    SETNZ16(res);
                    CLRF(FLAG_C|FLAG_V);
                }
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                tracet0 = SR_T0; break;
            case 0005200: case 0005220: case 0005230: case 0005240:
            case 0005250: case 0005260: case 0005270: /*eori.l*/
                ASSERT_OK(ReadInstrLongInc(&PC,&src2));
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 ^ src2;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); break;

            default:
                rc = STOP_ERROP;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   0 |Length2| TargetReg | TargetMode| SourceMode| SourceReg | move
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   0 |Length2| TargetReg | 0   0   1 | SourceMode| SourceReg | movea
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x1000:
            ea = IR_EATGT;
            ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
            if  (ea == EA_ADIR)
                rc = STOP_ERROP; /* movea.b */
            else {
                ASSERT_OK(ea_dst_b(ea,IR_REGX,src1,&PC));
                SETNZ8(src1);
            }
            break;
        case 0x2000:
            ea = IR_EATGT;
            ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
            if (ea==EA_ADIR) { /* movea.l */
                *AREG(IR_REGX) = src1;
                rc = SCPE_OK;
            } else {
                rc = ea_dst_l(ea,IR_REGX,src1,&PC);
                SETNZ32(src1);
            }
            break;
        case 0x3000:
            ea = IR_EATGT;
            ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
            if (ea==EA_ADIR) { /* movea.w */
                *AREG(IR_REGX) = EXTW(src1);
                rc = SCPE_OK;
            } else {
                rc = ea_dst_w(ea,IR_REGX,src1,&PC);
                SETNZ16(src1);
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Opcode    | 0 |Length | effective address     | clr,neg,negx,not,tst
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Opcode    | 0 | 1   1 | effective address     | moveccr,movesr
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Opcode    | 0 |Mode   | 0   0   0 | Register  | ext
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Opcode    | 0 |Opcode | effective address     | jmp,jsr,movem,nbcd,pea,tas
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Opcode    | 0 |Opcode         |   Vector      | trap
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Opcode    | 0 |Opcode             | Register  | link,moveusp,swap,unlink
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Opcode    | 0 |Opcode                         | illegal,nop,reset,rte,rtr,rts,stop,trapv
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   0 | Register  | 1 |Opcode | effective address     | chk,lea
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x4000:
            switch (IR_1106) {
            case 000600: case 001600: case 002600: case 003600:
            case 004600: case 005600: case 006600: case 007600: /*chk*/
                src1 = DRX;
                SETF((src1 & BIT31) != 0,FLAG_N);
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC));
                rc = CCR_N || src1 > res ? m68k_gen_exception(6,&PC) : SCPE_OK;
                break;
            case 000700: case 001700: case 002700: case 003700:
            case 004700: case 005700: case 006700: case 007700: /*lea*/
                ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                *AREG(IR_REGX) = srca;
                rc = SCPE_OK;
                break;
                
            case 000300: /*move from sr*/
                rc = ea_dst_w(IR_EAMOD,IR_EAREG,SR,&PC);
                break;

            case 001000: /*clr.b*/
                ONEF(FLAG_Z);
                CLRF(FLAG_N|FLAG_C|FLAG_V);
                rc = ea_dst_b(IR_EAMOD,IR_EAREG,0,&PC);
                break;
            case 001100: /*clr.w*/
                ONEF(FLAG_Z);
                CLRF(FLAG_N|FLAG_C|FLAG_V);
                rc = ea_dst_w(IR_EAMOD,IR_EAREG,0,&PC);
                break;
            case 001200: /*clr.l*/
                ONEF(FLAG_Z);
                CLRF(FLAG_N|FLAG_C|FLAG_V);
                rc = ea_dst_l(IR_EAMOD,IR_EAREG,0,&PC);
                break;

            case 000000: /*negx.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                src1 += (CCR_X ? 1 : 0);
                goto do_neg8;
            case 002000: /*neg.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
do_neg8:        res = m68k_sub8(0,src1,0);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;

            case 000100: /*negx.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                src1 += (CCR_X ? 1 : 0);
                goto do_neg16;
            case 002100: /*neg.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
do_neg16:       res = m68k_sub16(0,src1,0,TRUE);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                break;

            case 000200: /*negx.l*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                srcx1 = (t_uint64)src1 + (CCR_X ? 1 : 0);
                goto do_neg32;
            case 002200: /*neg.l*/
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
do_neg32:       res = m68k_sub32(0,srcx1,0,TRUE);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;

            case 002300: /*move to ccr*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                SR = COMBINE8(SR,src1);
                break;

            case 003000: /*not.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = ~src1;
                SETNZ8(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 003100: /*not.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = ~src1;
                SETNZ16(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                break;
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
            case 003200: /*not.l*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = ~src1;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;

            case 003300: /*move to sr*/
                ASSERT_PRIV();
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                SR = src1;
                tracet0 = SR_T0;
                break;

            case 004000:  /*nbcd*/
                rc = STOP_IMPL;
                break;
                
            case 004100: /*pea or swap*/
                if (IR_0503==000) { /*swap*/
                    reg = &DRY;
                    src1 = *reg << 16;
                    res = *reg >> 16;
                    *reg = COMBINE16(src1,res);
                    SETNZ32(*reg);
                    CLRF(FLAG_C|FLAG_V);
                    rc = SCPE_OK;
                } else { /*pea*/
                    ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                    ASSERT_OK(m68k_cpush32(srca));
                }
                break;
            case 004200: /*movem.w or ext*/
                if (IR_0503==000) { /*ext.w*/
                    reg = &DRY;
                    res = EXTB(*reg);
                    *reg = COMBINE16(*reg,res);
                    SETNZ16(res);
                    CLRF(FLAG_C|FLAG_V);
                    rc = SCPE_OK;
                } else { /*movem.w regs,ea*/
                    ASSERT_OK(ReadInstrInc(&PC,&IRE));
                    if (IR_EAMOD==EA_APD)
                        rc = m68k_movem_r_pd(AREG(IR_REGY),IRE,FALSE);
                    else {
                        ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                        rc = m68k_movem_r_ea(srca,IRE,FALSE);
                    }
                }
                break;
            case 004300: /*movem or ext*/
                if (IR_0503==000) { /*ext.l*/
                    reg = &DRY;
                    *reg = EXTW(*reg);
                    SETNZ32(*reg);
                    CLRF(FLAG_C|FLAG_V);
                    rc = SCPE_OK;
                } else { /*movem.l regs,ea */
                    ASSERT_OK(ReadInstrInc(&PC,&IRE));
                    if (IR_EAMOD==EA_APD)
                        rc = m68k_movem_r_pd(AREG(IR_REGY),IRE,TRUE);
                    else {
                        ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                        rc = m68k_movem_r_ea(srca,IRE,TRUE);
                    }
                }
                break;
            case 005000: /*tst.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                SETNZ8(src1);
                CLRF(FLAG_V|FLAG_C);
                break;
            case 005100: /*tst.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                SETNZ16(src1);
                CLRF(FLAG_V|FLAG_C);
                break;
            case 005200: /*tst.l*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                SETNZ32(src1);
                CLRF(FLAG_V|FLAG_C);
                break;
                
            case 005300: /*tas or illegal*/
                if (IR==045374) { /*illegal*/
                    rc = STOP_ERROP;
                } else { /*tas*/
                    rc = STOP_IMPL;
                }
                break;
            case 006200: /*movem.w ea,regs*/
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                if (IR_EAMOD==EA_API)
                    rc = m68k_movem_pi_r(AREG(IR_REGY),IRE,FALSE);
                else {
                    ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                    rc = m68k_movem_ea_r(srca,IRE,FALSE);
                }
                break;
            case 006300: /*movem.l ea,regs*/
                ASSERT_OK(ReadInstrInc(&PC,&IRE));
                if (IR_EAMOD==EA_API)
                    rc = m68k_movem_pi_r(AREG(IR_REGY),IRE,TRUE);
                else {
                    ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                    rc = m68k_movem_ea_r(srca,IRE,TRUE);
                }
                break;
            case 007100:
                switch(IR_0503) {
                case 000000:
                case 000010: /*trap*/
                    (*m68kcpu_trapcallback)(m68kcpu_dev,IR_TRAP);
                    rc = m68k_gen_exception(32+IR_TRAP,&PC);
                    break;
                case 000020: /*link*/
                    ASSERT_OK(ReadInstrInc(&PC,&IRE));
                    if (IR_REGY==7) {
                        *cur_sp -= 4;
                        ASSERT_OK(WriteVL(*cur_sp,*cur_sp));
                    } else {
                        areg = AREG(IR_REGY);
                        ASSERT_OK(m68k_cpush32(*areg));
                        *areg = *cur_sp;
                    }
                    *cur_sp += EXTW(IRE);
                    break;
                case 000030: /*unlk*/
                    if (IR_REGY==7) {
                        ASSERT_OK(ReadVL(*cur_sp,&srca));
                        *cur_sp = srca;
                    } else {
                        areg = AREG(IR_REGY);
                        *cur_sp = *areg;
                        ASSERT_OK(m68k_cpop32(areg));
                    }
                    break;
                case 000040: /*move to usp*/
                    ASSERT_PRIV();
                    USP = AR[IR_REGY];
                    tracet0 = SR_T0;
                    rc = SCPE_OK;
                    break;
                case 000050: /*move from usp*/
                    ASSERT_PRIV();
                    AR[IR_REGY] = USP;
                    rc = SCPE_OK;
                    break;
                case 000060:
                    switch(IR_0200) {
                    case 000000: /*reset*/
                        ASSERT_PRIV();
                        rc = m68kcpu_peripheral_reset();
                        break;
                    case 000001: /*nop*/
                        rc = SCPE_OK; 
                        tracet0 = SR_T0;
                        break;
                    case 000002: /*stop*/
                        ASSERT_PRIV();
                        ASSERT_OKRET(ReadInstrInc(&PC,&IRE));
                        SR = (uint16)IRE;
                        rc = STOP_HALT;
                        tracet0 = SR_T0;
                        break;
                    case 000003: /*rte*/
                        ASSERT_PRIV();
                        ASSERT_OK(m68k_pop16(&src1));
                        SR = src1;
                        m68k_set_s(SR_S != 0);
                        oldpc = PC;
                        rc = m68k_pop32(&PC);
                        tracet0 = SR_T0;
                        IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] RTE to 0x%08x, IPL=%d S=%d\n",
                                oldpc-2,PC,SR_IPL,SR_S?1:0));
                        break;
                    case 000005: /*rts*/
                        oldpc = PC;
                        rc = m68k_cpop32(&PC);
                        m68k_sublevel--;
                        IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] <<< RTS to 0x%08x (level=%d)\n",
                                oldpc-2,PC,m68k_sublevel));
                        tracet0 = SR_T0;
                        break;
                    case 000006: /*trapv*/
                        rc = CCR_V ? m68k_gen_exception(7,&PC) : SCPE_OK;
                        break;
                    case 000007: /*rtr*/
                        ASSERT_OK(m68k_cpop16(&src1));
                        SR = COMBINE8(SR,src1);
                        oldpc = PC;
                        rc = m68k_cpop32(&PC);
                        tracet0 = SR_T0;
                        IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] RTR to 0x%08x\n",oldpc-2,PC));
                        break;
                    default:
                        rc = STOP_ERROP;
                    }
                    break;
                default:
                    rc = STOP_ERROP;
                }
                break;
            case 007200: /*jsr*/
                oldpc = PC;
                ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                ASSERT_OK(m68k_cpush32(PC));
                IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] >>> JSR %s (level=%d)\n",
                        oldpc-2,m68k_getsym(srca,XFMT,out),m68k_sublevel));
                PC = srca;
                m68k_sublevel++;
                tracet0 = SR_T0;
                break;
            case 007300: /*jmp*/
                oldpc = PC;
                ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC));
                IFDEBUG(DBG_CPU_BTRACE,fprintf(sim_deb,"CPU : [0x%08x] ||| JMP %s\n",
                        oldpc-2,m68k_getsym(srca,XFMT,out)));
                PC = srca;
                tracet0 = SR_T0;
                break;
            default:
                rc = STOP_ERROP;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   1 | Quickdata |Opc|Length | effective address<>001| addq,subq
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   1 | Condition     | 1   1   0   0   1 | Register  | dbcc
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   0   1 | Condition     | 1   1 | effective address<>001| scc
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x5000:
            switch (IR_0806) {
            case 0000300:
            case 0000700:
                if (IR_0503==010) { /*dbcc*/
                    if (!IR_COND || !testcond(IR_COND)) { /* dbt is a NOP */
                        reg = &DRY;
                        src1 = MASK_16L((*reg-1));
                        *reg = MASK_16U(*reg) | src1;
                        if (src1 != 0xffff) {
                            ASSERT_OK(ReadInstr(PC,&IRE));
                            PC += (EXTW(IRE));
                            rc = SCPE_OK;
                            tracet0 = SR_T0;
                            break;
                        } /* else loop terminated */
                    }
                    /* loop cond not met or dbt */
                    PC += 2;
                    rc = SCPE_OK;
                } else { /*scc*/
                    src1 = testcond(IR_COND) ? 0xff : 0x00;
                    rc = ea_dst_b(IR_EAMOD,IR_EAREG,src1,&PC);
                }
                break;
            case 0000000: /*addq.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_add8(src1,quickarg[IR_REGX],0);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000100: /*addq.w*/
                if (IR_EAMOD == EA_ADIR) {
                    *AREG(IR_REGY) += EXTW(quickarg[IR_REGX]);
                    rc = SCPE_OK;
                } else {
                    ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                    res = m68k_add16(src1,quickarg[IR_REGX],0,TRUE);
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                }
                break;
            case 0000200: /*addq.l*/
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_add32(srcx1,(t_uint64)quickarg[IR_REGX],0,IR_EAMOD!=EA_ADIR);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000400: /*subq.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_sub8(src1,quickarg[IR_REGX],0);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000500: /*subq.w*/
                if (IR_EAMOD == EA_ADIR) {
                    *AREG(IR_REGY) -= EXTW(quickarg[IR_REGX]);
                    rc = SCPE_OK;
                } else {
                    ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                    res = m68k_sub16(src1,quickarg[IR_REGX],0,TRUE);
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                }
                break;
            case 0000600: /*subq.l*/
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_sub32(srcx1,(t_uint64)quickarg[IR_REGX],0,IR_EAMOD!=EA_ADIR);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   1   0 | Condition     |   Displacement                | Bcc,bra,bsr
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x6000:
            isbsr = IR_COND==0x100; /* is bsr */
            iscond = isbsr || testcond(IR_COND); /* condition matched */
            if (IR_DISP) {
                if (iscond) {
                    if (isbsr) {
                        IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] >>> BSR %s (level=%d\n",
                                PC-2,m68k_getsym(PC+EXTB(IR_DISP),XFMT,out),m68k_sublevel));
                        ASSERT_OK(m68k_cpush32(PC)); /* save PC for BSR */
                        m68k_sublevel++;
                    } else {
                        IFDEBUG(DBG_CPU_BTRACE,fprintf(sim_deb,"CPU : [0x%08x] ||| B%s %s\n",
                                PC-2,condnames[IR_COND>>8],m68k_getsym(PC+EXTB(IR_DISP),XFMT,out)));
                    }
                    PC += EXTB(IR_DISP); /* go to new location */
                } /* else condition not matched */
            } else { /* 16 bit ext word */
                if (iscond) {
                    ASSERT_OK(ReadInstr(PC,&IRE)); /* get extension word */
                    if (isbsr) {
                        IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] >>> BSR %s (level=%d)\n",
                                PC-2,m68k_getsym(PC+EXTW(IRE),XFMT,out),m68k_sublevel));
                        ASSERT_OK(m68k_cpush32(PC+2)); /* save PC for BSR */
                        m68k_sublevel++;
                    } else {
                        IFDEBUG(DBG_CPU_BTRACE,fprintf(sim_deb,"CPU : [0x%08x] ||| B%s %s\n",
                                PC-2,condnames[IR_COND>>8],m68k_getsym(PC+EXTW(IRE),XFMT,out)));
                    }
                    PC += EXTW(IRE); /* go to new location */
                } else {
                    PC += 2; /* condition not matched */
                }
            }
            tracet0 = SR_T0;
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 0   1   1   1 | Register  | 0 |   Data                        | moveq
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x7000:
            src1 = DRX = EXTB(IR_DATA);
            SETNZ32(src1);
            CLRF(FLAG_C|FLAG_V);
            rc = SCPE_OK; break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   0   0 | Register  |Opc|Length | effective address<>00x| or
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   0   0 |   Reg X   | 1   0   0 | 0   0 |R/M|  Reg Y    | sbcd
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   0   0 | Register  |Opc| 1   1 | effective address     | divs,divu
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x8000:
            switch(IR_0803) {
            case 0000300: case 0000320: case 0000330: case 0000340:
            case 0000350: case 0000360: case 0000370: /*divu.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                rc = m68k_divu_w(src1,&DR[IR_REGX], &PC);
                break;
            case 0000700: case 0000720: case 0000730: case 0000740:
            case 0000750: case 0000760: case 0000770: /*divs.w*/
                rc = m68k_divs_w(src1,&DR[IR_REGX], &PC);
                break;
            case 0000400: /*sbcd d*/
                rc = STOP_IMPL; break;
            case 0000410: /*sbcd a*/
                rc = STOP_IMPL; break;
            case 0000000: case 0000020: case 0000030: case 0000040:
            case 0000050: case 0000060: case 0000070: /*or.b ->d*/  
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = MASK_8L(src1 | DRX);
                SETNZ8(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000100: case 0000120: case 0000130: case 0000140:
            case 0000150: case 0000160: case 0000170: /*or.w ->d*/  
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = MASK_16L(src1 | DRX);
                SETNZ16(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000200: case 0000220: case 0000230: case 0000240:
            case 0000250: case 0000260: case 0000270: /*or.l ->d*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 & DRX;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000420: case 0000430: case 0000440: case 0000450:
            case 0000460: case 0000470: /*or.b ->ea*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 | DRX;
                SETNZ8(res);
                CLRF(FLAG_V|FLAG_C);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000520: case 0000530: case 0000540: case 0000550:
            case 0000560: case 0000570: /*or.w ->ea*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 | DRX;
                SETNZ16(res);
                CLRF(FLAG_V|FLAG_C);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000620: case 0000630: case 0000640: case 0000650:
            case 0000660: case 0000670: /*or.l ->ea*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 | DRX;
                SETNZ32(res);
                CLRF(FLAG_V|FLAG_C);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            default:
                rc = STOP_ERROP; break;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   0   1 | Register  |Opc|Length | effective address<>00x| sub
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   0   1 | Register  |Opc| 1   1 | effective address     | suba
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   0   1 |   Reg X   | 1 |Length | 0   0 |R/M|  Reg Y    | subx
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0x9000:
            switch (IR_0803) {
            case 0000300: case 0000310: case 0000320: case 0000330:
            case 0000340: case 0000350: case 0000360: case 0000370: /* suba.w */
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&srca,&PC));
                *AREG(IR_REGX) -= EXTW(srca); /* note: no flag changes! */
                break;
            case 0000700: case 0000710: case 0000720: case 0000730:
            case 0000740: case 0000750: case 0000760: case 0000770: /* suba.l */
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&srca,&PC));
                *AREG(IR_REGX) -= srca; /* note: no flag changes! */
                break;
            case 0000400: /*subx.b d*/
                res = m68k_sub8(MASK_8L(DRY),DRX,CCR_X?1:0);
                rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000410: /*subx.b -a*/
                ASSERT_OK(ea_src_b(EA_APD,IR_REGY,&src1,&PC));
                ASSERT_OK(ea_src_b(EA_APD,IR_REGX,&src2,&PC));
                res = m68k_sub8(src1,src2,CCR_X?1:0);
                rc = ea_dst_b_rmw(EA_APD,IR_REGX,res);
                break;
            case 0000500: /*subx.w d*/
                res = m68k_sub16(MASK_16L(DRY),DRX,CCR_X?1:0,TRUE);
                rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000510: /*subx.w -a*/
                ASSERT_OK(ea_src_w(EA_APD,IR_REGY,&src1,&PC));
                ASSERT_OK(ea_src_w(EA_APD,IR_REGX,&src2,&PC));
                res = m68k_sub16(src1,src2,CCR_X?1:0,TRUE);
                rc = ea_dst_w_rmw(EA_APD,IR_REGX,res);
                break;
            case 0000600: /*subx.l d*/
                res = m68k_sub32((t_uint64)DRY,(t_uint64)DRX,CCR_X?1:0,TRUE);
                rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000610: /*subx.l -a*/
                ASSERT_OK(ea_src_l64(EA_APD,IR_REGY,&srcx1,&PC));
                ASSERT_OK(ea_src_l64(EA_APD,IR_REGX,&srcx2,&PC));
                res = m68k_sub32(srcx1,srcx2,CCR_X?1:0,TRUE);
                rc = ea_dst_l_rmw(EA_APD,IR_REGX,res);
                break;
            case 0000000: case 0000020: case 0000030: case 0000040:
            case 0000050: case 0000060: case 0000070:               /* sub.b ->d */
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_sub8(DRX,src1,0);
                rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000100: case 0000110: case 0000120: case 0000130:
            case 0000140: case 0000150: case 0000160: case 0000170: /* sub.w ->d */
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_sub16(DRX,src1,0,TRUE);
                rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000200: case 0000210: case 0000220: case 0000230:
            case 0000240: case 0000250: case 0000260: case 0000270: /* sub.l ->d */
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_sub32((t_uint64)DRX,srcx1,0,TRUE);
                rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000420: case 0000430: case 0000440: case 0000450:
            case 0000460: case 0000470:                             /* sub.b ->ea */
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_sub8(src1,DRX,0);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000520: case 0000530: case 0000540: case 0000550:
            case 0000560: case 0000570:                             /* sub.w ->ea */
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_sub16(src1,DRX,0,TRUE);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000620: case 0000630: case 0000640: case 0000650:
            case 0000660: case 0000670:                             /* sub.l ->ea */
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_sub32(srcx1,(t_uint64)DRX,0,TRUE);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            default:
                rc = STOP_ERROP;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   1   0 | Opcode                                        | trapa
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0xa000:
            rc = m68k_gen_exception(10,&PC);
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   1   1 | Register  | 0 |Length | effective address     | cmp,cmpa
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   1   1 | Register  | 1 |Length | effective address<>001| eor
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   0   1   1 |   Reg X   | 1 |Length | 0   0   1 |  Reg Y    | cmpm
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0xb000:
            switch (IR_0803) {
            case 0000410: /*cmpm.b*/
                rc = STOP_IMPL; break;
            case 0000510: /*cmpm.w*/
                rc = STOP_IMPL; break;
            case 0000610: /*cmpm.l*/
                rc = STOP_IMPL; break;
            case 0000400: case 0000420: case 0000430: case 0000440:
            case 0000450: case 0000460: case 0000470: /*eor.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 ^ DRX;
                SETNZ8(res);
                CLRF(FLAG_V|FLAG_C);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000500: case 0000520: case 0000530: case 0000540:
            case 0000550: case 0000560: case 0000570: /*eor.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 ^ DRX;
                SETNZ16(res);
                CLRF(FLAG_V|FLAG_C);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000600: case 0000620: case 0000630: case 0000640:
            case 0000650: case 0000660: case 0000670: /*eor.l*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 ^ DRX;
                SETNZ32(res);
                CLRF(FLAG_V|FLAG_C);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000000: case 0000020: case 0000030: case 0000040:
            case 0000050: case 0000060: case 0000070: /*cmp.b*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                (void)m68k_sub8(DRX,src1,0);
                break;
            case 0000100: case 0000110: case 0000120: case 0000130:
            case 0000140: case 0000150: case 0000160: case 0000170: /*cmp.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                (void)m68k_sub16(DRX,src1,0,TRUE);
                break;
            case 0000200: case 0000210: case 0000220: case 0000230:
            case 0000240: case 0000250: case 0000260: case 0000270: /*cmp.l*/
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                (void)m68k_sub32((t_uint64)DRX,srcx1,0,TRUE);
                break;
            case 0000300: case 0000310: case 0000320: case 0000330:
            case 0000340: case 0000350: case 0000360: case 0000370: /*cmpa.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                areg = AREG(IR_REGX);
                (void)m68k_sub32((t_uint64)EXTW(*areg),(t_uint64)src1,0,TRUE);
                break;

            case 0000700: case 0000710: case 0000720: case 0000730:
            case 0000740: case 0000750: case 0000760: case 0000770: /*cmpa.l*/
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                (void)m68k_sub32((t_uint64)*AREG(IR_REGX),srcx1,0,TRUE);
                break;
            default:
                rc = STOP_ERROP;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   0   0 | Register  |Opc|Length | effective address<>00x| and
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   0   0 |   Reg X   | 1   0   0 | 0   0 |R/M|  Reg Y    | abcd
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   0   0 |   Reg X   | 1 |Opcode | 0   0 |Opc|  Reg Y    | exg
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   0   0 | Register  |Opc| 1   1 | effective address     | muls,mulu
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0xc000:
            switch(IR_0803) {
            case 0000300: case 0000310: case 0000320: case 0000330: 
            case 0000340: case 0000350: case 0000360: case 0000370: /*mulu*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = (uint16)MASK_16L(src1) * (uint16)MASK_16L(DRX);
                DRX = res;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                break;
            case 0000700: case 0000710: case 0000720: case 0000730: 
            case 0000740: case 0000750: case 0000760: case 0000770: /*muls*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                sres = (int16)MASK_16L(src1) * (int16)MASK_16L(DRX);
                DRX = (uint32)sres;
                SETNZ32(sres);
                CLRF(FLAG_C|FLAG_V);
                break;
            case 0000500: /* exg d,d */
                res = DRX; DRX = DRY; DRY = res;
                rc = SCPE_OK; break;
            case 0000510: /* exg a,a */
                srca = *AREG(IR_REGX); *AREG(IR_REGX) = *AREG(IR_REGY); *AREG(IR_REGY) = srca;
                rc = SCPE_OK; break;
            case 0000610: /* exg a,d */
                res = DRX; DRX = (uint32)*AREG(IR_REGY); *AREG(IR_REGY) = (t_addr)res;
                rc = SCPE_OK; break;
            case 0000400: /* abcd d */
                rc = STOP_IMPL; break;
            case 0000410: /* abcd a */
                rc = STOP_IMPL; break;
            case 0000000: case 00000020: case 0000030: case 0000040:
            case 0000050: case 00000060: case 0000070: /* and.b -> d*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 & DRX;
                SETNZ8(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000100: case 00000120: case 0000130: case 0000140:
            case 0000150: case 00000160: case 0000170: /* and.w -> d*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 & DRX;
                SETNZ16(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000200: case 00000220: case 0000230: case 0000240:
            case 0000250: case 00000260: case 0000270: /* and.l -> d*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1 & DRX;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000420: case 00000430: case 0000440: case 0000450:
            case 0000460: case 00000470: /* and.b -> ea*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = DRX & src1;
                SETNZ8(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000520: case 00000530: case 0000540: case 0000550:
            case 0000560: case 00000570: /* and.w -> ea*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = DRX & src1;
                SETNZ16(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000620: case 00000630: case 0000640: case 0000650:
            case 0000660: case 00000670: /* and.l -> ea*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = DRX & src1;
                SETNZ32(res);
                CLRF(FLAG_C|FLAG_V);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            default:
                rc = STOP_ERROP;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   0   1 | Register  |Opc| 1   1 | effective address<>00x| add,adda
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   0   1 |   Reg X   | 1 |Length | 0   0 |R/M|  Reg Y    | addx
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0xd000:
            switch (IR_0803) {
            case 0000300: case 0000310: case 0000320: case 0000330:
            case 0000340: case 0000350: case 0000360: case 0000370: /*adda.w*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&srca,&PC));
                *AREG(IR_REGX) += EXTW(srca); /* note: no flag changes! */
                break;
            case 0000700: case 0000710: case 0000720: case 0000730:
            case 0000740: case 0000750: case 0000760: case 0000770: /*adda.l*/
                ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&srca,&PC));
                *AREG(IR_REGX) += srca; /* note: no flag changes! */
                break;
            case 0000400: /* addx.b d*/
                res = m68k_add8(MASK_8L(DRY),DRX,CCR_X?1:0);
                rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000410: /* addx.b -a*/
                ASSERT_OK(ea_src_b(EA_APD,IR_REGY,&src1,&PC));
                ASSERT_OK(ea_src_b(EA_APD,IR_REGX,&src2,&PC));
                res = m68k_add8(src1,src2,CCR_X?1:0);
                rc = ea_dst_b_rmw(EA_APD,IR_REGX,res);
                break;
            case 0000500: /* addx.w d*/
                res = m68k_add16(MASK_16L(DRY),DRX,CCR_X?1:0,TRUE);
                rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000510: /* addx.w -a*/
                ASSERT_OK(ea_src_w(EA_APD,IR_REGY,&src1,&PC));
                ASSERT_OK(ea_src_w(EA_APD,IR_REGX,&src2,&PC));
                res = m68k_add16(src1,src2,CCR_X?1:0,TRUE);
                rc = ea_dst_w_rmw(EA_APD,IR_REGX,res);
                break;
            case 0000600: /* addx.l d*/
                res = m68k_add32((t_uint64)DRY,(t_uint64)DRX,CCR_X?1:0,TRUE);
                rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000610: /* addx.l -a*/
                ASSERT_OK(ea_src_l64(EA_APD,IR_REGY,&srcx1,&PC));
                ASSERT_OK(ea_src_l64(EA_APD,IR_REGX,&srcx2,&PC));
                res = m68k_add32(srcx1,srcx2,CCR_X?1:0,TRUE);
                rc = ea_dst_l_rmw(EA_APD,IR_REGX,res);
                break;
            case 0000000: case 0000010: case 0000020: case 0000030:
            case 0000040: case 0000050: case 0000060: case 0000070: /*add.b ->d*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_add8(src1,DRX,0);
                rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000100: case 0000110: case 0000120: case 0000130:
            case 0000140: case 0000150: case 0000160: case 0000170: /*add.w ->d*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_add16(src1,DRX,0,TRUE);
                rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000200: case 0000210: case 0000220: case 0000230:
            case 0000240: case 0000250: case 0000260: case 0000270: /*add.l ->d*/
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_add32(srcx1,(t_uint64)DRX,0,TRUE);
                rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC);
                break;
            case 0000420: case 0000430: case 0000440: case 0000450:
            case 0000460: case 0000470: /*add.b ->ea*/
                ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_add8(src1,DRX,0);
                rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000520: case 0000530: case 0000540: case 0000550:
            case 0000560: case 0000570: /*add.w ->ea*/
                ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = m68k_add16(src1,DRX,0,TRUE);
                rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            case 0000620: case 0000630: case 0000640: case 0000650:
            case 0000660: case 0000670: /*add.l ->ea*/
                ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC));
                res = m68k_add32(srcx1,(t_uint64)DRX,0,TRUE);
                rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res);
                break;
            default:
                rc = STOP_ERROP;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   1   0 |Size/Reg X |dir|Length |i/r|Opcode2|  Reg Y    | asl,asr,lsl,lsr,rol,ror,roxl,roxr
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   1   0 | Opcode    |dir| 1   1 | effective address     | asl,asr,lsl,lsr,rol,ror,roxl,roxr
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0xe000:
            switch (IR_1103) {
            case 000040: case 001040: case 002040: case 003040: 
            case 004040: case 005040: case 006040: case 007040: /*asr.b r*/
                cnt = DRX & 077;
                goto do_asr8;
            case 000000: case 001000: case 002000: case 003000:
            case 004000: case 005000: case 006000: case 007000: /*asr.b #*/
                cnt = quickarg[IR_REGX];
do_asr8:        reg = DR+IR_REGY;
                res = src1 = MASK_8L(*reg);
                if (cnt) {
                    if (cnt<8) {
                        res >>= cnt; 
                        if (MASK_8SGN(src1)) res |= shmask8[cnt];
                        SETF(src1&bitmask[cnt],FLAG_C|FLAG_X);
                    } else {
                        res = MASK_8SGN(src1) ? 0xff : 0x00;
                        SETF(res,FLAG_C|FLAG_X);
                    }
                    *reg = COMBINE8(*reg,res);
                } else
                    CLRF(FLAG_C);
                SETNZ8(res);
                CLRF(FLAG_V);
                rc =SCPE_OK; break;

            case 000320: case 000330: case 000340: case 000350:
            case 000360: case 000370: /*asr*/
                cnt = 1;
                goto do_asr16;
            case 000140: case 001140: case 002140: case 003140: 
            case 004140: case 005140: case 006140: case 007140: /*asr.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_asr16;
            case 000100: case 001100: case 002100: case 003100: 
            case 004100: case 005100: case 006100: case 007100: /*asr.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_asr16:       ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                if (cnt) {
                    if (cnt<16) {
                        res = src1 >> cnt; 
                        if (MASK_16SGN(src1)) res |= shmask16[cnt];
                        SETF(src1&bitmask[cnt],FLAG_C|FLAG_X);
                    } else {
                        res = MASK_16SGN(src1) ? 0xffff : 0x0000;
                        SETF(res,FLAG_C|FLAG_X);
                    }
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                } else {
                    CLRF(FLAG_C);
                    res = src1;
                    rc = SCPE_OK;
                }
                SETNZ16(res);
                CLRF(FLAG_V);
                break;

            case 000240: case 001240: case 002240: case 003240: 
            case 004240: case 005240: case 006240: case 007240: /*asr.l r*/
                cnt = DRX & 077;
                goto do_asr32;
            case 000200: case 001200: case 002200: case 003200: 
            case 004200: case 005200: case 006200: case 007200: /*asr.l #*/
                cnt = quickarg[IR_REGX];
do_asr32:       reg = DR+IR_REGY;
                res = src1 = *reg;
                if (cnt) {
                    if (cnt < 32) {
                        res >>= cnt; 
                        if (MASK_32SGN(src1)) res |= shmask32[cnt];
                        SETF(src1&bitmask[cnt],FLAG_C|FLAG_X);
                    } else {
                        res = MASK_32SGN(src1) ? 0xffffffff : 0x00000000;
                        SETF(res,FLAG_C|FLAG_X);
                    }
                    *reg = res;
                } else CLRF(FLAG_C);
                SETNZ32(res);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;

            case 000440: case 001440: case 002440: case 003440: 
            case 004440: case 005440: case 006440: case 007440: /*asl.b r*/
                cnt = DRX & 077;
                goto do_asl8;
            case 000400: case 001400: case 002400: case 003400: 
            case 004400: case 005400: case 006400: case 007400: /*asl.b #*/
                cnt = quickarg[IR_REGX];
do_asl8:        reg = DR+IR_REGY;
                res = src1 = MASK_8L(*reg);
                if (cnt) {
                    if (cnt<8) {
                        res = src1 << cnt;
                        SETF(MASK_9(res),FLAG_C|FLAG_X);
                        src1 &= shmask8[cnt+1];
                        SETF(src1 && src1 != shmask8[cnt+1],FLAG_V);
                    } else {
                        res = 0;
                        SETF(cnt==8?(src1 & 1):0,FLAG_C|FLAG_X);
                        SETF(src1,FLAG_V);
                    }
                    *reg = COMBINE8(*reg,res);
                } else CLRF(FLAG_C|FLAG_V);
                SETNZ8(res);
                rc = SCPE_OK; break;
                
            case 000720: case 000730: case 000740: case 000750:
            case 000760: case 000770: /*asl*/
                cnt = 1;
                goto do_asl16;
            case 000540: case 001540: case 002540: case 003540:
            case 004540: case 005540: case 006540: case 007540: /*asl.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_asl16;
            case 000500: case 001500: case 002500: case 003500:
            case 004500: case 005500: case 006500: case 007500: /*asl.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_asl16:       ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                if (cnt) {
                    if (cnt<16) {
                        res = src1 << cnt;
                        SETF(MASK_17(res),FLAG_C|FLAG_X);
                        src1 &= shmask16[cnt+1];
                        SETF(src1 && src1 != shmask16[cnt+1],FLAG_V);
                    } else {
                        res = 0;
                        SETF(cnt==16?(src1 & 1):0,FLAG_C|FLAG_X);
                        SETF(src1,FLAG_V);
                    }
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                } else {
                    CLRF(FLAG_C|FLAG_V);
                    rc = SCPE_OK;
                }
                SETNZ16(res);
                break;

            case 000640: case 001640: case 002640: case 003640:
            case 004640: case 005640: case 006640: case 007640: /*asl.l r*/
                cnt = DRX & 077;
                goto do_asl32;
            case 000600: case 001600: case 002600: case 003600: 
            case 004600: case 005600: case 006600: case 007600: /*asl.l #*/
                cnt = quickarg[IR_REGX];
do_asl32:       reg = DR+IR_REGY;
                res = src1 = *reg;
                if (cnt) {
                    if (cnt<32) {
                        res <<= cnt;
                        SETF(src1 & bitmask[32-cnt],FLAG_C|FLAG_X);
                        src1 &= shmask32[cnt+1];
                        SETF(src1 && src1 != shmask32[cnt+1],FLAG_V);
                    } else {
                        res = 0;
                        SETF(cnt==16?(src1 & 1):0,FLAG_C|FLAG_X);
                        SETF(src1,FLAG_V);
                    }
                    *reg = res;
                } else CLRF(FLAG_C|FLAG_V);
                SETNZ32(res);
                rc = SCPE_OK; break;
            
            case 000050: case 001050: case 002050: case 003050:
            case 004050: case 005050: case 006050: case 007050: /*lsr.b r*/
                cnt = DRX & 077;
                goto do_lsr8;
            case 000010: case 001010: case 002010: case 003010:
            case 004010: case 005010: case 006010: case 007010: /*lsr.b #*/
                cnt = quickarg[IR_REGX];
do_lsr8:        reg = DR+IR_REGY;
                res = src1 = MASK_8L(*reg);
                if (cnt) {
                    if (cnt <= 8) {
                        res = src1 >> cnt;
                        SETF(src1&bitmask[cnt],FLAG_C|FLAG_X);
                    } else {
                        res = 0;
                        CLRF(FLAG_X|FLAG_C);
                    }
                    *reg = COMBINE8(*reg,res);
                } else CLRF(FLAG_C);
                CLRF(FLAG_V);
                SETNZ8(res);
                rc = SCPE_OK; break;
                
            case 001320: case 001330: case 001340: case 001350:
            case 001360: case 001370: /*lsr*/
                cnt = 1;
                goto do_lsr16;
            case 000150: case 001150: case 002150: case 003150:
            case 004150: case 005150: case 006150: case 007150: /*lsr.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_lsr16;
            case 000110: case 001110: case 002110: case 003110:
            case 004110: case 005110: case 006110: case 007110: /*lsr.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_lsr16:       ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                if (cnt) {
                    if (cnt <= 16) {
                        res = src1 >> cnt;
                        SETF(src1&bitmask[cnt],FLAG_C|FLAG_X);
                    } else {
                        res = 0;
                        CLRF(FLAG_X|FLAG_C);
                    }
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                } else {
                    CLRF(FLAG_C);
                    rc = SCPE_OK;
                }
                CLRF(FLAG_V);
                SETNZ16(res);
                break;

            case 000250: case 001250: case 002250: case 003250:
            case 004250: case 005250: case 006250: case 007250: /*lsr.l r*/
                cnt = DRX & 077;
                goto do_lsr32;
            case 000210: case 001210: case 002210: case 003210:
            case 004210: case 005210: case 006210: case 007210: /*lsr.l #*/
                cnt = quickarg[IR_REGX];
do_lsr32:       reg = DR+IR_REGY;
                res = src1 = *reg;
                if (cnt) {
                    if (cnt <= 32) {
                        res = src1 >> cnt;
                        SETF(src1&bitmask[cnt],FLAG_C|FLAG_X);
                    } else {
                        res = 0;
                        CLRF(FLAG_X|FLAG_C);
                    }
                    *reg = res;
                } else CLRF(FLAG_C);
                CLRF(FLAG_V);
                SETNZ32(res);
                rc = SCPE_OK;
                break;

            case 000450: case 001450: case 002450: case 003450:
            case 004450: case 005450: case 006450: case 007450: /*lsl.b r*/
                cnt = DRX & 077;
                goto do_lsl8;
            case 000410: case 001410: case 002410: case 003410: 
            case 004410: case 005410: case 006410: case 007410: /*lsl.b #*/
                cnt = quickarg[IR_REGX];
do_lsl8:        reg = DR+IR_REGY;
                res = src1 = MASK_8L(*reg);
                if (cnt) {
                    if (cnt <= 8) {
                        res = src1 << cnt;
                        SETF(src1&bitmask[9-cnt],FLAG_C|FLAG_X);
                    } else {
                        res = 0;
                        CLRF(FLAG_X|FLAG_C);
                    }
                    *reg = COMBINE8(*reg,res);
                } else CLRF(FLAG_C);
                SETNZ8(res);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;
            
            case 001720: case 001730: case 001740: case 001750:
            case 001760: case 001770: /*lsl*/
                cnt = 1;
                goto do_lsl16;
            case 000550: case 001550: case 002550: case 003550:
            case 004550: case 005550: case 006550: case 007550: /*lsl.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_lsl16;
            case 000510: case 001510: case 002510: case 003510:
            case 004510: case 005510: case 006510: case 007510: /*lsl.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_lsl16:       ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC));
                res = src1;
                if (cnt) {
                    if (cnt <= 16) {
                        res = src1 << cnt;
                        SETF(src1&bitmask[17-cnt],FLAG_C|FLAG_X);
                    } else {
                        res = 0;
                        CLRF(FLAG_X|FLAG_C);
                    }
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                } else {
                    CLRF(FLAG_C);
                    rc = SCPE_OK;
                }
                SETNZ16(res);
                CLRF(FLAG_V);
                break;

            case 000650: case 001650: case 002650: case 003650:
            case 004650: case 005650: case 006650: case 007650: /*lsl.l r*/
                cnt = DRX & 077;
                goto do_lsl32;
            case 000610: case 001610: case 002610: case 003610:
            case 004610: case 005610: case 006610: case 007610: /*lsl.l #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_lsl32:       reg = DR+IR_REGY;
                res = src1 = *reg;
                if (cnt) {
                    if (cnt <= 32) {
                        res = src1 << cnt;
                        SETF(src1&bitmask[33-cnt],FLAG_C|FLAG_X);
                    } else {
                        res = 0;
                        CLRF(FLAG_X|FLAG_C);
                    }
                    *reg = res;
                } else {
                    CLRF(FLAG_C);
                    rc = SCPE_OK;
                }
                SETNZ32(res);
                CLRF(FLAG_V);
                break;
            
            case 000060: case 001060: case 002060: case 003060:
            case 004060: case 005060: case 006060: case 007060: /*roxr.b r*/
                cnt = DRX & 077;
                goto do_roxr8;
            case 000020: case 001020: case 002020: case 003020:
            case 004020: case 005020: case 006020: case 007020: /*roxr.b #*/
                cnt = quickarg[IR_REGX];
do_roxr8:       reg = DR+IR_REGY;
                res = MASK_8L(*reg);
                if (cnt) {
                    cnt %= 9;
                    if (CCR_X) res |= BIT8;
                    res = (res>>cnt) | (res<<(9-cnt));
                    *reg = COMBINE8(*reg,res);
                    SETF(MASK_9(res),FLAG_X|FLAG_C);
                } else SETF(CCR_X,FLAG_C);
                SETNZ8(res);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;
                
            case 002320: case 002330: case 002340: case 002350:
            case 002360: case 002370: /*roxr*/
                cnt = 1;
                goto do_roxr16;
            case 000160: case 001160: case 002160: case 003160:
            case 004160: case 005160: case 006160: case 007160: /*roxr.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_roxr16;
            case 000120: case 001120: case 002120: case 003120:
            case 004120: case 005120: case 006120: case 007120: /*roxr.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_roxr16:      ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC));
                if (cnt) {
                    cnt %= 17;
                    if (CCR_X) res |= BIT16;
                    res = (res>>cnt) | (res<<(17-cnt));
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                    SETF(MASK_17(res),FLAG_X|FLAG_C);
                } else {
                    SETF(CCR_X,FLAG_C);
                    rc = SCPE_OK;
                }
                SETNZ16(res);
                CLRF(FLAG_V);
                break;

            case 000260: case 001260: case 002260: case 003260:
            case 004260: case 005260: case 006260: case 007260: /*roxr.l r*/
                cnt = DRX & 077;
                goto do_roxr32;
            case 000220: case 001220: case 002220: case 003220:
            case 004220: case 005220: case 006220: case 007220: /*roxr.l #*/
                cnt = quickarg[IR_REGX];
do_roxr32:      reg = DR+IR_REGY;
                resx = *reg;
                if (cnt) {
                    cnt %= 33;
                    if (CCR_X) resx |= BIT32;
                    resx = (resx>>cnt) | (resx<<(33-cnt));
                    *reg = MASK_32L(resx);
                    SETF(MASK_33(resx),FLAG_X|FLAG_C);
                } else SETF(CCR_X,FLAG_C);
                SETNZ32(resx);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;
            
            case 000460: case 001460: case 002460: case 003460:
            case 004460: case 005460: case 006460: case 007460: /*roxl.b r*/
                cnt = DRX & 077;
                goto do_roxl8;
            case 000420: case 001420: case 002420: case 003420:
            case 004420: case 005420: case 006420: case 007420: /*roxl.b #*/
                cnt = quickarg[IR_REGX];
do_roxl8:       reg = DR+IR_REGY;
                res = MASK_8L(*reg);
                if (cnt) {
                    cnt %= 9;
                    if (CCR_X) res |= BIT8;
                    res = (res<<cnt) | (res>>(9-cnt));
                    *reg = COMBINE8(*reg,res);
                    SETF(MASK_9(res),FLAG_X|FLAG_C);
                } else SETF(CCR_X,FLAG_C);
                SETNZ8(res);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;

            case 002720: case 002730: case 002740: case 002750:
            case 002760: case 002770: /*roxl*/
                cnt = 1;
                goto do_roxl16;
            case 000560: case 001560: case 002560: case 003560:
            case 004560: case 005560: case 006560: case 007560: /*roxl.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_roxl16;
            case 000520: case 001520: case 002520: case 003520:
            case 004520: case 005520: case 006520: case 007520: /*roxl.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_roxl16:      ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC));
                if (cnt) {
                    cnt %= 17;
                    if (CCR_X) res |= BIT16;
                    res = (res<<cnt) | (res>>(17-cnt));
                    SETF(MASK_17(res),FLAG_X|FLAG_C);
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); 
                } else {
                    SETF(CCR_X,FLAG_C);
                    rc = SCPE_OK;
                }
                SETNZ16(res);
                CLRF(FLAG_V);
                break;
            
            case 000660: case 001660: case 002660: case 003660:
            case 004660: case 005660: case 006660: case 007660: /*roxl.l r*/
                cnt = DRX & 077;
                goto do_roxl32;
            case 000620: case 001620: case 002620: case 003620:
            case 004620: case 005620: case 006620: case 007620: /*roxl.l #*/
                cnt = quickarg[IR_REGX];
do_roxl32:      reg = DR+IR_REGY;
                resx = *reg;
                if (cnt) {
                    cnt %= 33;
                    if (CCR_X) resx |= BIT32;
                    resx = (resx<<cnt) | (resx>>(33-cnt));
                    SETF(MASK_33(resx),FLAG_X|FLAG_C);
                    *reg = MASK_32L(resx);
                } else SETF(CCR_X,FLAG_C);
                SETNZ32(resx);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;
            
            case 000070: case 001070: case 002070: case 003070:
            case 004070: case 005070: case 006070: case 007070: /*ror.b r*/
                cnt = DRX & 077;
                goto do_ror8;
            case 000030: case 001030: case 002030: case 003030:
            case 004030: case 005030: case 006030: case 007030: /*ror.b #*/
                cnt = quickarg[IR_REGX];
do_ror8:        reg = DR+IR_REGY;
                res = MASK_8L(*reg);
                if (cnt) {
                    cnt &= 7;
                    res = (res>>cnt) | (res<<(8-cnt));
                    SETF(MASK_9(res),FLAG_C);
                    *reg = COMBINE8(*reg,res);
                } else CLRF(FLAG_C);
                SETNZ8(res);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;

            case 003320: case 003330: case 003340: case 003350:
            case 003360: case 003370: /*ror*/
                cnt = 1;
                goto do_ror16;
            case 000170: case 001170: case 002170: case 003170:
            case 004170: case 005170: case 006170: case 007170: /*ror.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_ror16;
            case 000130: case 001130: case 002130: case 003130:
            case 004130: case 005130: case 006130: case 007130: /*ror.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_ror16:       ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC));
                if (cnt) {
                    cnt &= 15;
                    res = (res>>cnt) | (res<<(16-cnt));
                    SETF(MASK_17(res),FLAG_C);
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                } else {
                    CLRF(FLAG_C);
                    rc = SCPE_OK;
                }
                SETNZ16(res);
                CLRF(FLAG_V);
                break;

            case 000270: case 001270: case 002270: case 003270:
            case 004270: case 005270: case 006270: case 007270: /*ror.l r*/
                cnt = DRX & 077;
                goto do_ror32;
            case 000230: case 001230: case 002230: case 003230:
            case 004230: case 005230: case 006230: case 007230: /*ror.l #*/
                cnt = quickarg[IR_REGX];
do_ror32:       reg = DR+IR_REGY;
                resx = *reg;
                if (cnt) {
                    cnt &= 31;
                    resx = (resx>>cnt) | (resx<<(32-cnt));
                    SETF(MASK_33(resx),FLAG_C);
                    *reg = (int32)resx;
                } else {
                    CLRF(FLAG_C);
                    rc = SCPE_OK;
                }
                SETNZ32(resx);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;

            case 000470: case 001470: case 002470: case 003470:
            case 004470: case 005470: case 006470: case 007470: /*rol.b r*/
                cnt = DRX & 077;
                goto do_rol8;
            case 000430: case 001430: case 002430: case 003430:
            case 004430: case 005430: case 006430: case 007430: /*rol.b #*/
                cnt = quickarg[IR_REGX];
do_rol8:        reg = DR+IR_REGY;
                res = MASK_8L(*reg);
                if (cnt) {
                    cnt &= 7;
                    res = (res<<cnt) | (res>>(8-cnt));
                    SETF(MASK_9(res),FLAG_C);
                    *reg = COMBINE8(*reg,res);
                } else CLRF(FLAG_C);
                SETNZ8(res);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;
                
            case 003720: case 003730: case 003740: case 003750:
            case 003760: case 003770: /*rol*/
                cnt = 1;
                goto do_rol16;
            case 000570: case 001570: case 002570: case 003570:
            case 004570: case 005570: case 006570: case 007570: /*rol.w r*/
                cnt = DRX & 077;
                IR = EA_DDIR | IR_REGY;
                goto do_rol16;
            case 000530: case 001530: case 002530: case 003530:
            case 004530: case 005530: case 006530: case 007530: /*rol.w #*/
                cnt = quickarg[IR_REGX];
                IR = EA_DDIR | IR_REGY;
do_rol16:       ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC));
                if (cnt) {
                    cnt &= 15;
                    res = (res<<cnt) | (res>>(16-cnt));
                    SETF(MASK_17(res),FLAG_C);
                    rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res);
                } else {
                    CLRF(FLAG_C);
                    rc = SCPE_OK;
                }
                SETNZ16(res);
                CLRF(FLAG_V);
                break;

            case 000670: case 001670: case 002670: case 003670:
            case 004670: case 005670: case 006670: case 007670: /*rol.l r*/
                cnt = DRX & 077;
                goto do_rol32;
            case 000630: case 001630: case 002630: case 003630:
            case 004630: case 005630: case 006630: case 007630: /*rol.l #*/
                cnt = quickarg[IR_REGX];
do_rol32:       reg = DR+IR_REGY;
                resx = (uint32)*reg;
                if (cnt) {
                    cnt &= 31;
                    resx = (resx<<cnt) | (resx>>(32-cnt));
                    SETF(MASK_32L(resx),FLAG_C);
                    *reg = MASK_32L(resx);
                } else CLRF(FLAG_C);
                SETNZ32(resx);
                CLRF(FLAG_V);
                rc = SCPE_OK; break;
            
            default:
                rc = STOP_ERROP;
            }
            break;

        /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
         * | 1   1   1   1 | Opcode                                        | trapf
         * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/
        case 0xf000:
            rc = m68k_gen_exception(11,&PC); break;

        /* unreachable */
        default:
            rc = STOP_ERROP; break;
        }
        
        /* handle tracing */
        if (tracet0 || SR_T1) {
            if (m68kcpu_unit->flags & UNIT_CPU_TRACE) {
                /* leave loop */
                sim_interval = -1;
                rc = STOP_TRACE;
                break;
            }
            IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Tracebit set\n",PC));
            ASSERT_OK(m68k_gen_exception(9,&PC));
            /* remain in loop */
        }
        tracet0 = 0;

        /* handle interrupts (sets/resets intpending) */
        m68k_checkints(&PC);
        
        /* handle STOP instr */
        if (rc==STOP_HALT) {
            if (m68kcpu_unit->flags & UNIT_CPU_STOP) {
                PC -= 4; /* correct PC to point to STOP instr */
                break;
            }
            if ((rc = m68k_stop(&PC)) != SCPE_OK) 
                break; /* does not return until interrupt occurs, will react to CTRL-E */
        }
    }

    /* handle various exit codes */
    switch (rc) {
    case STOP_ERRADR: /* address error */
        if ((m68kcpu_unit->flags & UNIT_CPU_EXC)==0) {
            IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Address error\n",PC));
            if ((rc = m68k_gen_exception(3,&PC)) != SCPE_OK) {
                /* double bus fault */
                rc = STOP_DBF; /* cannot be masked, will stop simulator */
            }
        }
        return rc;
    case STOP_PCIO: /* cannot be masked, will stop simulator */
        return rc;
    case STOP_ERRIO: /* bus error */
        if ((m68kcpu_unit->flags & UNIT_CPU_EXC)==0) {
            IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Bus error\n",PC));
            if ((rc = m68k_gen_exception(2,&PC)) != SCPE_OK) {
                /* double bus fault */
                rc = STOP_DBF; /* cannot be masked, will stop simulator */
            }
        }
        return rc;
    case STOP_ERROP: /* illegal opcode */
        if (!(m68kcpu_unit->flags & UNIT_CPU_EXC)) {
            IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Illegal opcode\n",PC));
            rc = m68k_gen_exception(4,&PC);
        }
        return rc;
    case STOP_PRVIO: /* privilege violation */
        if (!(m68kcpu_unit->flags & UNIT_CPU_PRVIO)) {
            IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Privilege violation\n",PC));
            rc = m68k_gen_exception(8,&PC);
        }
        break;
    case STOP_IMPL:
        return rc; /* leave sim_instr */
    default:
        return rc; /* leave sim_instr */
    }

    /* save state */
    saved_PC = PC;

    return rc;
}
