3352 lines
102 KiB
C
3352 lines
102 KiB
C
/* 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"
|
|
#include <ctype.h>
|
|
|
|
#if defined(_WIN32)
|
|
#include <windows.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
/* 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 0x100000000L
|
|
|
|
#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(x) ((x) & 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 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;
|
|
if (!devs) return SCPE_IERR;
|
|
|
|
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)&addrmask,&mem));
|
|
|
|
/* 68000/08/10 do not like unaligned access */
|
|
if (cputype < 3 && (tpc & 1)) return STOP_ERRADR;
|
|
|
|
for (i=CACHE_SIZE; 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 < 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;
|
|
rc = STOP_IMPL; 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(res),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(res),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;
|
|
}
|