mirror of
https://github.com/zydeco/minivmac4ios.git
synced 2024-11-29 05:49:21 +00:00
5108 lines
97 KiB
C
Executable File
5108 lines
97 KiB
C
Executable File
/*
|
|
MINEM68K.c
|
|
|
|
Copyright (C) 2009 Bernd Schmidt, Paul C. Pratt
|
|
|
|
You can redistribute this file and/or modify it under the terms
|
|
of version 2 of the GNU General Public License as published by
|
|
the Free Software Foundation. You should have received a copy
|
|
of the license along with this file; see the file COPYING.
|
|
|
|
This file is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
license for more details.
|
|
*/
|
|
|
|
/*
|
|
MINimum EMulator of 68K cpu
|
|
|
|
This code descends from a simple 68000 emulator that I
|
|
(Paul C. Pratt) wrote long ago. That emulator ran on a 680x0,
|
|
and used the cpu it ran on to do some of the work. This
|
|
descendent fills in those holes with code from the
|
|
Un*x Amiga Emulator by Bernd Schmidt, as found being used in vMac.
|
|
|
|
This emulator is about 10 times smaller than the UAE,
|
|
at the cost of being 2 to 3 times slower.
|
|
|
|
FPU Emulation added 9/12/2009 by Ross Martin
|
|
(this code now located in "FPCPEMDV.h")
|
|
*/
|
|
|
|
#ifndef AllFiles
|
|
#include "SYSDEPNS.h"
|
|
|
|
#include "MYOSGLUE.h"
|
|
#include "ENDIANAC.h"
|
|
#include "EMCONFIG.h"
|
|
#include "GLOBGLUE.h"
|
|
|
|
#include "M68KITAB.h"
|
|
|
|
#if WantDisasm
|
|
#include "DISAM68K.h"
|
|
#endif
|
|
#endif
|
|
|
|
#include "MINEM68K.h"
|
|
|
|
typedef unsigned char flagtype;
|
|
|
|
|
|
/* Memory Address Translation Cache record */
|
|
|
|
struct MATCr {
|
|
ui5r cmpmask;
|
|
ui5r cmpvalu;
|
|
ui5r usemask;
|
|
ui3p usebase;
|
|
};
|
|
typedef struct MATCr MATCr;
|
|
typedef MATCr *MATCp;
|
|
|
|
/*
|
|
This variable was introduced because a program could do a Bcc from
|
|
within chip memory to a location within expansion memory. With a
|
|
pointer variable the program counter would point to the wrong
|
|
location. With this variable unset the program counter is always
|
|
correct, but programs will run slower (about 4%).
|
|
Usually, you'll want to have this defined.
|
|
|
|
vMac REQUIRES this. It allows for fun things like Restart.
|
|
*/
|
|
|
|
#ifndef USE_POINTER
|
|
#define USE_POINTER 1
|
|
#endif
|
|
|
|
#define AKMemory 0
|
|
#define AKRegister 1
|
|
#define AKConstant 2
|
|
|
|
union ArgAddrT {
|
|
ui5r mem;
|
|
ui5r *rga;
|
|
};
|
|
typedef union ArgAddrT ArgAddrT;
|
|
|
|
LOCALVAR struct regstruct
|
|
{
|
|
ui5r regs[16]; /* Data and Address registers */
|
|
ui5r pc; /* Program Counter */
|
|
CPTR usp; /* User Stack Pointer */
|
|
CPTR isp; /* Interrupt Stack Pointer */
|
|
#if Use68020
|
|
CPTR msp; /* Master Stack Pointer */
|
|
#endif
|
|
|
|
/* Status Register */
|
|
ui5r intmask; /* bits 10-8 : interrupt priority mask */
|
|
flagtype t1; /* bit 15: Trace mode 1 */
|
|
#if Use68020
|
|
flagtype t0; /* bit 14: Trace mode 0 */
|
|
#endif
|
|
flagtype s; /* bit 13: Supervisor or user privilege level */
|
|
#if Use68020
|
|
flagtype m; /* bit 12: Master or interrupt mode */
|
|
#endif
|
|
flagtype x; /* bit 4: eXtend */
|
|
flagtype n; /* bit 3: Negative */
|
|
flagtype z; /* bit 2: Zero */
|
|
flagtype v; /* bit 1: oVerflow */
|
|
flagtype c; /* bit 0: Carry */
|
|
|
|
flagtype TracePending;
|
|
flagtype ExternalInterruptPending;
|
|
#if 0
|
|
flagtype ResetPending;
|
|
#endif
|
|
ui3b *fIPL;
|
|
|
|
#if Use68020
|
|
ui5b sfc; /* Source Function Code register */
|
|
ui5b dfc; /* Destination Function Code register */
|
|
ui5b vbr; /* Vector Base Register */
|
|
ui5b cacr; /* Cache Control Register */
|
|
/*
|
|
bit 0 : Enable Cache
|
|
bit 1 : Freeze Cache
|
|
bit 2 : Clear Entry In Cache (write only)
|
|
bit 3 : Clear Cache (write only)
|
|
*/
|
|
ui5b caar; /* Cache Address Register */
|
|
#endif
|
|
MATCr MATCrdB;
|
|
MATCr MATCwrB;
|
|
MATCr MATCrdW;
|
|
MATCr MATCwrW;
|
|
MATCr MATCex;
|
|
ATTep HeadATTel;
|
|
DecOpR CurDecOp;
|
|
|
|
|
|
#if USE_POINTER
|
|
ui3p pc_p;
|
|
ui3p pc_oldp;
|
|
#endif
|
|
ui5b opsize;
|
|
ui5b ArgKind;
|
|
ArgAddrT ArgAddr;
|
|
ui5b SrcVal;
|
|
ui5b opcode;
|
|
si5r MaxCyclesToGo;
|
|
si5r MoreCyclesToGo;
|
|
si5r ResidualCycles;
|
|
ui3b fakeword[2];
|
|
|
|
#define disp_table_sz (256 * 256)
|
|
#if SmallGlobals
|
|
DecOpR *disp_table;
|
|
#else
|
|
DecOpR disp_table[disp_table_sz];
|
|
#endif
|
|
} regs;
|
|
|
|
#define ui5r_MSBisSet(x) (((si5r)(x)) < 0)
|
|
|
|
#define ZFLG regs.z
|
|
#define NFLG regs.n
|
|
#define CFLG regs.c
|
|
#define VFLG regs.v
|
|
#define XFLG regs.x
|
|
|
|
LOCALFUNC ui4b m68k_getCR(void)
|
|
{
|
|
return (XFLG << 4) | (NFLG << 3) | (ZFLG << 2)
|
|
| (VFLG << 1) | CFLG;
|
|
}
|
|
|
|
LOCALFUNC MayInline void m68k_setCR(ui4b newcr)
|
|
{
|
|
XFLG = (newcr >> 4) & 1;
|
|
NFLG = (newcr >> 3) & 1;
|
|
ZFLG = (newcr >> 2) & 1;
|
|
VFLG = (newcr >> 1) & 1;
|
|
CFLG = newcr & 1;
|
|
}
|
|
|
|
LOCALFUNC MayInline blnr cctrue(void)
|
|
{
|
|
switch ((regs.opcode >> 8) & 15) {
|
|
case 0: return trueblnr; /* T */
|
|
case 1: return falseblnr; /* F */
|
|
case 2: return (! CFLG) && (! ZFLG); /* HI */
|
|
case 3: return CFLG || ZFLG; /* LS */
|
|
case 4: return ! CFLG; /* CC */
|
|
case 5: return CFLG; /* CS */
|
|
case 6: return ! ZFLG; /* NE */
|
|
case 7: return ZFLG; /* EQ */
|
|
case 8: return ! VFLG; /* VC */
|
|
case 9: return VFLG; /* VS */
|
|
case 10: return ! NFLG; /* PL */
|
|
case 11: return NFLG; /* MI */
|
|
case 12: return NFLG == VFLG; /* GE */
|
|
case 13: return NFLG != VFLG; /* LT */
|
|
case 14: return (! ZFLG) && (NFLG == VFLG); /* GT */
|
|
case 15: return ZFLG || (NFLG != VFLG); /* LE */
|
|
default: return falseblnr; /* shouldn't get here */
|
|
}
|
|
}
|
|
|
|
LOCALPROC ALU_CmpB(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result0 = dstvalue - srcvalue;
|
|
ui5r result1 = ui5r_FromUByte(dstvalue) - ui5r_FromUByte(srcvalue);
|
|
ui5r result = ui5r_FromSByte(result0);
|
|
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (((result0 >> 1) ^ result0) >> 7) & 1;
|
|
CFLG = (result1 >> 8) & 1;
|
|
}
|
|
|
|
LOCALPROC ALU_CmpW(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result0 = dstvalue - srcvalue;
|
|
ui5r result1 = ui5r_FromUWord(dstvalue) - ui5r_FromUWord(srcvalue);
|
|
ui5r result = ui5r_FromSWord(result0);
|
|
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (((result0 >> 1) ^ result0) >> 15) & 1;
|
|
CFLG = (result1 >> 16) & 1;
|
|
}
|
|
|
|
LOCALPROC ALU_CmpL(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSLong(dstvalue - srcvalue);
|
|
|
|
int flgs = ui5r_MSBisSet(srcvalue);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
CFLG = (flgs && ! flgo) || (NFLG && ((! flgo) || flgs));
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_AddB(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result0 = dstvalue + srcvalue;
|
|
ui5r result1 = ui5r_FromUByte(dstvalue) + ui5r_FromUByte(srcvalue);
|
|
ui5r result = ui5r_FromSByte(result0);
|
|
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (((result0 >> 1) ^ result0) >> 7) & 1;
|
|
XFLG = CFLG = (result1 >> 8);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_AddW(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result0 = dstvalue + srcvalue;
|
|
ui5r result1 = ui5r_FromUWord(dstvalue) + ui5r_FromUWord(srcvalue);
|
|
ui5r result = ui5r_FromSWord(result0);
|
|
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (((result0 >> 1) ^ result0) >> 15) & 1;
|
|
XFLG = CFLG = (result1 >> 16);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_AddL(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSLong(dstvalue + srcvalue);
|
|
|
|
int flgs = ui5r_MSBisSet(srcvalue);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs && flgo && ! NFLG) || ((! flgs) && (! flgo) && NFLG);
|
|
XFLG = CFLG = (flgs && flgo) || ((! NFLG) && (flgo || flgs));
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_SubB(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result0 = dstvalue - srcvalue;
|
|
ui5r result1 = ui5r_FromUByte(dstvalue) - ui5r_FromUByte(srcvalue);
|
|
ui5r result = ui5r_FromSByte(result0);
|
|
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (((result0 >> 1) ^ result0) >> 7) & 1;
|
|
XFLG = CFLG = (result1 >> 8) & 1;
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_SubW(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result0 = dstvalue - srcvalue;
|
|
ui5r result1 = ui5r_FromUWord(dstvalue) - ui5r_FromUWord(srcvalue);
|
|
ui5r result = ui5r_FromSWord(result0);
|
|
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (((result0 >> 1) ^ result0) >> 15) & 1;
|
|
XFLG = CFLG = (result1 >> 16) & 1;
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_SubL(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSLong(dstvalue - srcvalue);
|
|
|
|
int flgs = ui5r_MSBisSet(srcvalue);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
XFLG = CFLG = (flgs && ! flgo) || (NFLG && ((! flgo) || flgs));
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_NegB(ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSByte(0 - dstvalue);
|
|
|
|
int flgs = ui5r_MSBisSet(dstvalue);
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs && NFLG);
|
|
XFLG = CFLG = (flgs || NFLG);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_NegW(ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSWord(0 - dstvalue);
|
|
|
|
int flgs = ui5r_MSBisSet(dstvalue);
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs && NFLG);
|
|
XFLG = CFLG = (flgs || NFLG);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_NegL(ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSLong(0 - dstvalue);
|
|
|
|
int flgs = ui5r_MSBisSet(dstvalue);
|
|
ZFLG = (result == 0);
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs && NFLG);
|
|
XFLG = CFLG = (flgs || NFLG);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_NegXB(ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSByte(0 - dstvalue - (XFLG ? 1 : 0));
|
|
|
|
int flgs = ui5r_MSBisSet(dstvalue);
|
|
if (result != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs && NFLG);
|
|
XFLG = CFLG = (flgs || NFLG);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_NegXW(ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSWord(0 - dstvalue - (XFLG ? 1 : 0));
|
|
|
|
int flgs = ui5r_MSBisSet(dstvalue);
|
|
if (result != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs && NFLG);
|
|
XFLG = CFLG = (flgs || NFLG);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_NegXL(ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSLong(0 - dstvalue - (XFLG ? 1 : 0));
|
|
|
|
int flgs = ui5r_MSBisSet(dstvalue);
|
|
if (result != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = (flgs && NFLG);
|
|
XFLG = CFLG = (flgs || NFLG);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALPROC SetCCRforAddX(ui5r srcvalue, ui5r dstvalue, ui5r result)
|
|
{
|
|
int flgs = ui5r_MSBisSet(srcvalue);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
if (result != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
NFLG = ui5r_MSBisSet(result);
|
|
XFLG = CFLG = (flgs && flgo) || ((! NFLG) && (flgo || flgs));
|
|
VFLG = (flgs && flgo && ! NFLG) || ((! flgs) && (! flgo) && NFLG);
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_AddXB(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSByte(dstvalue + srcvalue + (XFLG ? 1 : 0));
|
|
|
|
SetCCRforAddX(srcvalue, dstvalue, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_AddXW(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSWord(dstvalue + srcvalue + (XFLG ? 1 : 0));
|
|
|
|
SetCCRforAddX(srcvalue, dstvalue, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_AddXL(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSLong(dstvalue + srcvalue + (XFLG ? 1 : 0));
|
|
|
|
SetCCRforAddX(srcvalue, dstvalue, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALPROC SetCCRforSubX(ui5r srcvalue, ui5r dstvalue, ui5r result)
|
|
{
|
|
int flgs = ui5r_MSBisSet(srcvalue);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
if (result != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
NFLG = ui5r_MSBisSet(result);
|
|
VFLG = ((! flgs) && flgo && (! NFLG)) || (flgs && (! flgo) && NFLG);
|
|
XFLG = CFLG = (flgs && (! flgo)) || (NFLG && ((! flgo) || flgs));
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_SubXB(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSByte(dstvalue - srcvalue - (XFLG ? 1 : 0));
|
|
|
|
SetCCRforSubX(srcvalue, dstvalue, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_SubXW(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSWord(dstvalue - srcvalue - (XFLG ? 1 : 0));
|
|
|
|
SetCCRforSubX(srcvalue, dstvalue, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
LOCALFUNC ui5r ALU_SubXL(ui5r srcvalue, ui5r dstvalue)
|
|
{
|
|
ui5r result = ui5r_FromSLong(dstvalue - srcvalue - (XFLG ? 1 : 0));
|
|
|
|
SetCCRforSubX(srcvalue, dstvalue, result);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
#define m68k_logExceptions (dbglog_HAVE && 0)
|
|
|
|
|
|
GLOBALFUNC ATTep FindATTel(CPTR addr)
|
|
{
|
|
ATTep prev;
|
|
ATTep p;
|
|
|
|
p = regs.HeadATTel;
|
|
if ((addr & p->cmpmask) != p->cmpvalu) {
|
|
do {
|
|
prev = p;
|
|
p = p->Next;
|
|
} while ((addr & p->cmpmask) != p->cmpvalu);
|
|
|
|
{
|
|
ATTep next = p->Next;
|
|
|
|
if (nullpr == next) {
|
|
/* don't move the end guard */
|
|
} else {
|
|
/* move to first */
|
|
prev->Next = next;
|
|
p->Next = regs.HeadATTel;
|
|
regs.HeadATTel = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
LOCALPROC SetUpMATC(
|
|
MATCp CurMATC,
|
|
ATTep p)
|
|
{
|
|
CurMATC->cmpmask = p->cmpmask;
|
|
CurMATC->usemask = p->usemask;
|
|
CurMATC->cmpvalu = p->cmpvalu;
|
|
CurMATC->usebase = p->usebase;
|
|
}
|
|
|
|
LOCALFUNC ui5r get_byte_ext(CPTR addr)
|
|
{
|
|
ATTep p;
|
|
ui3p m;
|
|
ui5r AccFlags;
|
|
ui5r Data;
|
|
|
|
Label_Retry:
|
|
p = FindATTel(addr);
|
|
AccFlags = p->Access;
|
|
|
|
if (0 != (AccFlags & kATTA_readreadymask)) {
|
|
SetUpMATC(®s.MATCrdB, p);
|
|
m = p->usebase + (addr & p->usemask);
|
|
|
|
Data = *m;
|
|
} else if (0 != (AccFlags & kATTA_mmdvmask)) {
|
|
Data = MMDV_Access(p, 0, falseblnr, trueblnr, addr);
|
|
} else if (0 != (AccFlags & kATTA_ntfymask)) {
|
|
if (MemAccessNtfy(p)) {
|
|
goto Label_Retry;
|
|
} else {
|
|
Data = 0; /* fail */
|
|
}
|
|
} else {
|
|
Data = 0; /* fail */
|
|
}
|
|
|
|
return ui5r_FromSByte(Data);
|
|
}
|
|
|
|
LOCALFUNC MayNotInline ui5r get_byte(CPTR addr)
|
|
{
|
|
ui3p m = (addr & regs.MATCrdB.usemask) + regs.MATCrdB.usebase;
|
|
|
|
if ((addr & regs.MATCrdB.cmpmask) == regs.MATCrdB.cmpvalu) {
|
|
return ui5r_FromSByte(*m);
|
|
} else {
|
|
return get_byte_ext(addr);
|
|
}
|
|
}
|
|
|
|
LOCALPROC put_byte_ext(CPTR addr, ui5r b)
|
|
{
|
|
ATTep p;
|
|
ui3p m;
|
|
ui5r AccFlags;
|
|
|
|
Label_Retry:
|
|
p = FindATTel(addr);
|
|
AccFlags = p->Access;
|
|
|
|
if (0 != (AccFlags & kATTA_writereadymask)) {
|
|
SetUpMATC(®s.MATCwrB, p);
|
|
m = p->usebase + (addr & p->usemask);
|
|
*m = b;
|
|
} else if (0 != (AccFlags & kATTA_mmdvmask)) {
|
|
(void) MMDV_Access(p, b & 0x00FF, trueblnr, trueblnr, addr);
|
|
} else if (0 != (AccFlags & kATTA_ntfymask)) {
|
|
if (MemAccessNtfy(p)) {
|
|
goto Label_Retry;
|
|
} else {
|
|
/* fail */
|
|
}
|
|
} else {
|
|
/* fail */
|
|
}
|
|
}
|
|
|
|
LOCALPROC MayNotInline put_byte(CPTR addr, ui5r b)
|
|
{
|
|
ui3p m = (addr & regs.MATCwrB.usemask) + regs.MATCwrB.usebase;
|
|
if ((addr & regs.MATCwrB.cmpmask) == regs.MATCwrB.cmpvalu) {
|
|
*m = b;
|
|
} else {
|
|
put_byte_ext(addr, b);
|
|
}
|
|
}
|
|
|
|
LOCALFUNC ui5r get_word_ext(CPTR addr)
|
|
{
|
|
ui5r Data;
|
|
|
|
if (0 != (addr & 0x01)) {
|
|
ui5r hi = get_byte(addr);
|
|
ui5r lo = get_byte(addr + 1);
|
|
Data = ((hi << 8) & 0x0000FF00)
|
|
| (lo & 0x000000FF);
|
|
} else {
|
|
ATTep p;
|
|
ui3p m;
|
|
ui5r AccFlags;
|
|
|
|
Label_Retry:
|
|
p = FindATTel(addr);
|
|
AccFlags = p->Access;
|
|
|
|
if (0 != (AccFlags & kATTA_readreadymask)) {
|
|
SetUpMATC(®s.MATCrdW, p);
|
|
regs.MATCrdW.cmpmask |= 0x01;
|
|
m = p->usebase + (addr & p->usemask);
|
|
Data = do_get_mem_word(m);
|
|
} else if (0 != (AccFlags & kATTA_mmdvmask)) {
|
|
Data = MMDV_Access(p, 0, falseblnr, falseblnr, addr);
|
|
} else if (0 != (AccFlags & kATTA_ntfymask)) {
|
|
if (MemAccessNtfy(p)) {
|
|
goto Label_Retry;
|
|
} else {
|
|
Data = 0; /* fail */
|
|
}
|
|
} else {
|
|
Data = 0; /* fail */
|
|
}
|
|
}
|
|
|
|
return ui5r_FromSWord(Data);
|
|
}
|
|
|
|
LOCALFUNC MayNotInline ui5r get_word(CPTR addr)
|
|
{
|
|
ui3p m = (addr & regs.MATCrdW.usemask) + regs.MATCrdW.usebase;
|
|
if ((addr & regs.MATCrdW.cmpmask) == regs.MATCrdW.cmpvalu) {
|
|
return ui5r_FromSWord(do_get_mem_word(m));
|
|
} else {
|
|
return get_word_ext(addr);
|
|
}
|
|
}
|
|
|
|
LOCALPROC put_word_ext(CPTR addr, ui5r w)
|
|
{
|
|
if (0 != (addr & 0x01)) {
|
|
put_byte(addr, w >> 8);
|
|
put_byte(addr + 1, w);
|
|
} else {
|
|
ATTep p;
|
|
ui3p m;
|
|
ui5r AccFlags;
|
|
|
|
Label_Retry:
|
|
p = FindATTel(addr);
|
|
AccFlags = p->Access;
|
|
|
|
if (0 != (AccFlags & kATTA_writereadymask)) {
|
|
SetUpMATC(®s.MATCwrW, p);
|
|
regs.MATCwrW.cmpmask |= 0x01;
|
|
m = p->usebase + (addr & p->usemask);
|
|
do_put_mem_word(m, w);
|
|
} else if (0 != (AccFlags & kATTA_mmdvmask)) {
|
|
(void) MMDV_Access(p, w & 0x0000FFFF,
|
|
trueblnr, falseblnr, addr);
|
|
} else if (0 != (AccFlags & kATTA_ntfymask)) {
|
|
if (MemAccessNtfy(p)) {
|
|
goto Label_Retry;
|
|
} else {
|
|
/* fail */
|
|
}
|
|
} else {
|
|
/* fail */
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCALPROC MayNotInline put_word(CPTR addr, ui5r w)
|
|
{
|
|
ui3p m = (addr & regs.MATCwrW.usemask) + regs.MATCwrW.usebase;
|
|
if ((addr & regs.MATCwrW.cmpmask) == regs.MATCwrW.cmpvalu) {
|
|
do_put_mem_word(m, w);
|
|
} else {
|
|
put_word_ext(addr, w);
|
|
}
|
|
}
|
|
|
|
LOCALFUNC ui5r get_long_ext(CPTR addr)
|
|
{
|
|
ui5r hi = get_word(addr);
|
|
ui5r lo = get_word(addr + 2);
|
|
ui5r Data = ((hi << 16) & 0xFFFF0000)
|
|
| (lo & 0x0000FFFF);
|
|
|
|
return ui5r_FromSLong(Data);
|
|
}
|
|
|
|
LOCALFUNC MayNotInline ui5r get_long(CPTR addr)
|
|
{
|
|
CPTR addr2 = addr + 2;
|
|
ui3p m = (addr & regs.MATCrdW.usemask) + regs.MATCrdW.usebase;
|
|
ui3p m2 = (addr2 & regs.MATCrdW.usemask) + regs.MATCrdW.usebase;
|
|
if (((addr & regs.MATCrdW.cmpmask) == regs.MATCrdW.cmpvalu)
|
|
&& ((addr2 & regs.MATCrdW.cmpmask) == regs.MATCrdW.cmpvalu))
|
|
{
|
|
ui5r hi = do_get_mem_word(m);
|
|
ui5r lo = do_get_mem_word(m2);
|
|
ui5r Data = ((hi << 16) & 0xFFFF0000)
|
|
| (lo & 0x0000FFFF);
|
|
|
|
return ui5r_FromSLong(Data);
|
|
} else {
|
|
return get_long_ext(addr);
|
|
}
|
|
}
|
|
|
|
LOCALPROC put_long_ext(CPTR addr, ui5r l)
|
|
{
|
|
put_word(addr, l >> 16);
|
|
put_word(addr + 2, l);
|
|
}
|
|
|
|
LOCALPROC MayNotInline put_long(CPTR addr, ui5r l)
|
|
{
|
|
CPTR addr2 = addr + 2;
|
|
ui3p m = (addr & regs.MATCwrW.usemask) + regs.MATCwrW.usebase;
|
|
ui3p m2 = (addr2 & regs.MATCwrW.usemask) + regs.MATCwrW.usebase;
|
|
if (((addr & regs.MATCwrW.cmpmask) == regs.MATCwrW.cmpvalu)
|
|
&& ((addr2 & regs.MATCwrW.cmpmask) == regs.MATCwrW.cmpvalu))
|
|
{
|
|
do_put_mem_word(m, l >> 16);
|
|
do_put_mem_word(m2, l);
|
|
} else {
|
|
put_long_ext(addr, l);
|
|
}
|
|
}
|
|
|
|
|
|
#if ! USE_POINTER
|
|
LOCALFUNC ui4r get_pc_word_ext(void)
|
|
{
|
|
ui4r Data;
|
|
CPTR addr = regs.pc;
|
|
|
|
if (0 != (addr & 0x01)) {
|
|
Data = 0; /* fail */
|
|
/* should be an error, if had way to return it */
|
|
#if 0
|
|
ui4r hi = get_byte(addr);
|
|
ui4r lo = get_byte(addr + 1);
|
|
Data = ((hi << 8) & 0x0000FF00)
|
|
| (lo & 0x000000FF);
|
|
#endif
|
|
} else {
|
|
ATTep p;
|
|
ui3p m;
|
|
ui5r AccFlags;
|
|
|
|
Label_Retry:
|
|
p = FindATTel(addr);
|
|
AccFlags = p->Access;
|
|
|
|
if (0 != (AccFlags & kATTA_readreadymask)) {
|
|
SetUpMATC(®s.MATCex, p);
|
|
regs.MATCex.cmpmask |= 0x01;
|
|
m = p->usebase + (addr & p->usemask);
|
|
Data = do_get_mem_word(m);
|
|
} else
|
|
/*
|
|
no, don't run from device
|
|
if (0 != (AccFlags & kATTA_mmdvmask)) {
|
|
Data = MMDV_Access(p, 0, falseblnr, falseblnr, addr);
|
|
} else
|
|
*/
|
|
if (0 != (AccFlags & kATTA_ntfymask)) {
|
|
if (MemAccessNtfy(p)) {
|
|
goto Label_Retry;
|
|
} else {
|
|
Data = 0; /* fail */
|
|
}
|
|
} else {
|
|
Data = 0; /* fail */
|
|
}
|
|
}
|
|
|
|
return Data;
|
|
}
|
|
#endif
|
|
|
|
LOCALFUNC MayInline ui4r nextiword(void)
|
|
/* NOT sign extended */
|
|
{
|
|
#if USE_POINTER
|
|
ui4r r = do_get_mem_word(regs.pc_p);
|
|
regs.pc_p += 2;
|
|
return r;
|
|
#else
|
|
ui3p m;
|
|
ui4r Data;
|
|
CPTR addr = regs.pc;
|
|
|
|
m = (addr & regs.MATCex.usemask) + regs.MATCex.usebase;
|
|
if ((addr & regs.MATCex.cmpmask) == regs.MATCex.cmpvalu) {
|
|
Data = do_get_mem_word(m);
|
|
} else {
|
|
Data = get_pc_word_ext();
|
|
}
|
|
regs.pc = addr + 2;
|
|
return Data;
|
|
#endif
|
|
}
|
|
|
|
LOCALFUNC MayInline ui3r nextibyte(void)
|
|
{
|
|
#if USE_POINTER
|
|
ui3r r = do_get_mem_byte(regs.pc_p + 1);
|
|
regs.pc_p += 2;
|
|
return r;
|
|
#else
|
|
return (ui3b) nextiword();
|
|
#endif
|
|
}
|
|
|
|
LOCALFUNC MayInline ui5r nextilong(void)
|
|
{
|
|
#if USE_POINTER
|
|
ui5r r = do_get_mem_long(regs.pc_p);
|
|
regs.pc_p += 4;
|
|
#else
|
|
ui5r hi = nextiword();
|
|
ui5r lo = nextiword();
|
|
ui5r r = ((hi << 16) & 0xFFFF0000)
|
|
| (lo & 0x0000FFFF);
|
|
#endif
|
|
return r;
|
|
}
|
|
|
|
LOCALFUNC MayInline void BackupPC(void)
|
|
{
|
|
#if USE_POINTER
|
|
regs.pc_p -= 2;
|
|
#else
|
|
regs.pc -= 2;
|
|
#endif
|
|
}
|
|
|
|
LOCALFUNC MayInline void SkipiWord(void)
|
|
{
|
|
#if USE_POINTER
|
|
regs.pc_p += 2;
|
|
#else
|
|
regs.pc += 2;
|
|
#endif
|
|
}
|
|
|
|
#if Use68020
|
|
LOCALFUNC MayInline void SkipiLong(void)
|
|
{
|
|
#if USE_POINTER
|
|
regs.pc_p += 4;
|
|
#else
|
|
regs.pc += 4;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifndef WantDumpAJump
|
|
#define WantDumpAJump 0
|
|
#endif
|
|
|
|
#if WantDumpAJump
|
|
LOCALPROC DumpAJump(CPTR toaddr)
|
|
{
|
|
#if USE_POINTER
|
|
CPTR fromaddr = regs.pc + (regs.pc_p - regs.pc_oldp);
|
|
if ((toaddr > fromaddr) || (toaddr < regs.pc))
|
|
#else
|
|
CPTR fromaddr = regs.pc;
|
|
#endif
|
|
{
|
|
dbglog_writeHex(fromaddr);
|
|
dbglog_writeCStr(",");
|
|
dbglog_writeHex(toaddr);
|
|
dbglog_writeReturn();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if USE_POINTER
|
|
LOCALFUNC ui3p get_pc_real_address(CPTR addr)
|
|
{
|
|
ui3p v;
|
|
ATTep p;
|
|
|
|
Label_Retry:
|
|
p = FindATTel(addr);
|
|
if (0 == (p->Access & kATTA_readreadymask))
|
|
{
|
|
if (0 != (p->Access & kATTA_ntfymask)) {
|
|
if (MemAccessNtfy(p)) {
|
|
goto Label_Retry;
|
|
}
|
|
}
|
|
/* in trouble if get here */
|
|
/* ReportAbnormal("get_pc_real_address fails"); */
|
|
v = regs.fakeword;
|
|
regs.MATCex.cmpmask = 0;
|
|
regs.MATCex.cmpvalu = 0xFFFFFFFF;
|
|
} else {
|
|
SetUpMATC(®s.MATCex, p);
|
|
v = (addr & p->usemask) + p->usebase;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
#endif
|
|
|
|
LOCALFUNC MayInline void m68k_setpc(CPTR newpc)
|
|
{
|
|
#if WantDumpAJump
|
|
DumpAJump(newpc);
|
|
#endif
|
|
|
|
#if 0
|
|
if (newpc == 0xBD50 /* 401AB4 */) {
|
|
/* Debugger(); */
|
|
/* Exception(5); */ /* try and get macsbug */
|
|
}
|
|
#endif
|
|
|
|
#if USE_POINTER
|
|
{
|
|
ui3p m;
|
|
|
|
m = (newpc & regs.MATCex.usemask) + regs.MATCex.usebase;
|
|
if ((newpc & regs.MATCex.cmpmask) != regs.MATCex.cmpvalu)
|
|
{
|
|
m = get_pc_real_address(newpc);
|
|
}
|
|
|
|
regs.pc_p = regs.pc_oldp = m;
|
|
}
|
|
#endif
|
|
|
|
regs.pc = newpc;
|
|
}
|
|
|
|
LOCALFUNC MayInline CPTR m68k_getpc(void)
|
|
{
|
|
#if USE_POINTER
|
|
return regs.pc + (regs.pc_p - regs.pc_oldp);
|
|
#else
|
|
return regs.pc;
|
|
#endif
|
|
}
|
|
|
|
LOCALFUNC ui4b m68k_getSR(void)
|
|
{
|
|
return (regs.t1 << 15)
|
|
#if Use68020
|
|
| (regs.t0 << 14)
|
|
#endif
|
|
| (regs.s << 13)
|
|
#if Use68020
|
|
| (regs.m << 12)
|
|
#endif
|
|
| (regs.intmask << 8)
|
|
| m68k_getCR();
|
|
}
|
|
|
|
LOCALPROC NeedToGetOut(void)
|
|
{
|
|
if (regs.MaxCyclesToGo <= 0) {
|
|
/*
|
|
already have gotten out, and exception processing has
|
|
caused another exception, such as because a bad
|
|
stack pointer pointing to a memory mapped device.
|
|
*/
|
|
} else {
|
|
regs.MoreCyclesToGo += regs.MaxCyclesToGo;
|
|
/* not counting the current instruction */
|
|
regs.MaxCyclesToGo = 0;
|
|
}
|
|
}
|
|
|
|
LOCALPROC SetExternalInterruptPending(void)
|
|
{
|
|
regs.ExternalInterruptPending = trueblnr;
|
|
NeedToGetOut();
|
|
}
|
|
|
|
#define m68k_dreg(num) (regs.regs[(num)])
|
|
#define m68k_areg(num) (regs.regs[(num) + 8])
|
|
|
|
LOCALPROC m68k_setSR(ui4r newsr)
|
|
{
|
|
CPTR *pnewstk;
|
|
CPTR *poldstk = regs.s ? (
|
|
#if Use68020
|
|
regs.m ? ®s.msp :
|
|
#endif
|
|
®s.isp) : ®s.usp;
|
|
ui5r oldintmask = regs.intmask;
|
|
|
|
m68k_setCR(newsr);
|
|
regs.t1 = (newsr >> 15) & 1;
|
|
#if Use68020
|
|
regs.t0 = (newsr >> 14) & 1;
|
|
if (regs.t0) {
|
|
ReportAbnormal("t0 flag set in m68k_setSR");
|
|
}
|
|
#endif
|
|
regs.s = (newsr >> 13) & 1;
|
|
#if Use68020
|
|
regs.m = (newsr >> 12) & 1;
|
|
if (regs.m) {
|
|
ReportAbnormal("m flag set in m68k_setSR");
|
|
}
|
|
#endif
|
|
regs.intmask = (newsr >> 8) & 7;
|
|
|
|
pnewstk = regs.s ? (
|
|
#if Use68020
|
|
regs.m ? ®s.msp :
|
|
#endif
|
|
®s.isp) : ®s.usp;
|
|
|
|
if (poldstk != pnewstk) {
|
|
*poldstk = m68k_areg(7);
|
|
m68k_areg(7) = *pnewstk;
|
|
}
|
|
|
|
if (regs.intmask != oldintmask) {
|
|
SetExternalInterruptPending();
|
|
}
|
|
|
|
if (regs.t1) {
|
|
NeedToGetOut();
|
|
} else {
|
|
/* regs.TracePending = falseblnr; */
|
|
}
|
|
}
|
|
|
|
#ifndef FastRelativeJump
|
|
#define FastRelativeJump (1 && USE_POINTER)
|
|
#endif
|
|
|
|
LOCALPROC ExceptionTo(CPTR newpc
|
|
#if Use68020
|
|
, int nr
|
|
#endif
|
|
)
|
|
{
|
|
ui4b saveSR = m68k_getSR();
|
|
|
|
if (! regs.s) {
|
|
regs.usp = m68k_areg(7);
|
|
m68k_areg(7) =
|
|
#if Use68020
|
|
regs.m ? regs.msp :
|
|
#endif
|
|
regs.isp;
|
|
regs.s = 1;
|
|
}
|
|
#if Use68020
|
|
switch (nr) {
|
|
case 5: /* Zero Divide */
|
|
case 6: /* CHK, CHK2 */
|
|
case 7: /* cpTRAPcc, TRAPCcc, TRAPv */
|
|
case 9: /* Trace */
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), m68k_getpc());
|
|
m68k_areg(7) -= 2;
|
|
put_word(m68k_areg(7), 0x2000 + nr * 4);
|
|
break;
|
|
default:
|
|
m68k_areg(7) -= 2;
|
|
put_word(m68k_areg(7), nr * 4);
|
|
break;
|
|
}
|
|
/* if regs.m should make throw away stack frame */
|
|
#endif
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), m68k_getpc());
|
|
m68k_areg(7) -= 2;
|
|
put_word(m68k_areg(7), saveSR);
|
|
m68k_setpc(newpc);
|
|
regs.t1 = 0;
|
|
#if Use68020
|
|
regs.t0 = 0;
|
|
regs.m = 0;
|
|
#endif
|
|
regs.TracePending = falseblnr;
|
|
}
|
|
|
|
LOCALPROC Exception(int nr)
|
|
{
|
|
ExceptionTo(get_long(4 * nr
|
|
#if Use68020
|
|
+ regs.vbr
|
|
#endif
|
|
)
|
|
#if Use68020
|
|
, nr
|
|
#endif
|
|
);
|
|
}
|
|
|
|
LOCALFUNC MayNotInline ui5b get_disp_ea(ui5b base)
|
|
{
|
|
ui4b dp = nextiword();
|
|
int regno = (dp >> 12) & 0x0F;
|
|
si5b regd = regs.regs[regno];
|
|
if ((dp & 0x0800) == 0) {
|
|
regd = (si5b)(si4b)regd;
|
|
}
|
|
#if Use68020
|
|
regd <<= (dp >> 9) & 3;
|
|
#if ExtraAbnormalReports
|
|
if (((dp >> 9) & 3) != 0) {
|
|
/* ReportAbnormal("Have scale in Extension Word"); */
|
|
/* apparently can happen in Sys 7.5.5 boot on 68000 */
|
|
}
|
|
#endif
|
|
if (dp & 0x0100) {
|
|
if ((dp & 0x80) != 0) {
|
|
base = 0;
|
|
/* ReportAbnormal("Extension Word: suppress base"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
}
|
|
if ((dp & 0x40) != 0) {
|
|
regd = 0;
|
|
/* ReportAbnormal("Extension Word: suppress regd"); */
|
|
/* used by Mac II boot */
|
|
}
|
|
|
|
switch ((dp >> 4) & 0x03) {
|
|
case 0:
|
|
/* reserved */
|
|
ReportAbnormal("Extension Word: dp reserved");
|
|
break;
|
|
case 1:
|
|
/* no displacement */
|
|
/* ReportAbnormal("Extension Word: no displacement"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
break;
|
|
case 2:
|
|
base += (si5b)(si4b)nextiword();
|
|
/*
|
|
ReportAbnormal("Extension Word: word displacement");
|
|
*/
|
|
/* used by Sys 7.5.5 boot */
|
|
break;
|
|
case 3:
|
|
base += nextilong();
|
|
/*
|
|
ReportAbnormal("Extension Word: long displacement");
|
|
*/
|
|
/* used by Mac II boot from system 6.0.8? */
|
|
break;
|
|
}
|
|
|
|
if ((dp & 0x03) == 0) {
|
|
base += regd;
|
|
if ((dp & 0x04) != 0) {
|
|
ReportAbnormal("Extension Word: reserved dp form");
|
|
}
|
|
/* ReportAbnormal("Extension Word: noindex"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
} else {
|
|
if ((dp & 0x04) != 0) {
|
|
base = get_long(base);
|
|
base += regd;
|
|
/* ReportAbnormal("Extension Word: postindex"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
} else {
|
|
base += regd;
|
|
base = get_long(base);
|
|
/* ReportAbnormal("Extension Word: preindex"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
}
|
|
switch (dp & 0x03) {
|
|
case 1:
|
|
/* null outer displacement */
|
|
/*
|
|
ReportAbnormal(
|
|
"Extension Word: null outer displacement");
|
|
*/
|
|
/* used by Sys 7.5.5 boot */
|
|
break;
|
|
case 2:
|
|
base += (si5b)(si4b)nextiword();
|
|
/*
|
|
ReportAbnormal(
|
|
"Extension Word: word outer displacement");
|
|
*/
|
|
/* used by Mac II boot from system 6.0.8? */
|
|
break;
|
|
case 3:
|
|
base += nextilong();
|
|
/*
|
|
ReportAbnormal(
|
|
"Extension Word: long outer displacement");
|
|
*/
|
|
/* used by Mac II boot from system 6.0.8? */
|
|
break;
|
|
}
|
|
}
|
|
|
|
return base;
|
|
} else
|
|
#endif
|
|
{
|
|
return base + (si3b)(dp) + regd;
|
|
}
|
|
}
|
|
|
|
|
|
LOCALFUNC MayNotInline ArgAddrT DecodeSrcDst(ui5r f)
|
|
{
|
|
ui5r *p;
|
|
ArgAddrT v;
|
|
|
|
switch (GetDcoFldAMd(f)) {
|
|
case kAMdReg :
|
|
v.rga = ®s.regs[GetDcoFldArgDat(f)];
|
|
break;
|
|
case kAMdIndirect :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
v.mem = *p;
|
|
break;
|
|
case kAMdAPosIncB :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
v.mem = *p;
|
|
*p += 1;
|
|
break;
|
|
case kAMdAPosIncW :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
v.mem = *p;
|
|
*p += 2;
|
|
break;
|
|
case kAMdAPosIncL :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
v.mem = *p;
|
|
*p += 4;
|
|
break;
|
|
case kAMdAPreDecB :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
*p -= 1;
|
|
v.mem = *p;
|
|
break;
|
|
case kAMdAPreDecW :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
*p -= 2;
|
|
v.mem = *p;
|
|
break;
|
|
case kAMdAPreDecL :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
*p -= 4;
|
|
v.mem = *p;
|
|
break;
|
|
case kAMdADisp :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
v.mem = *p + ui5r_FromSWord(nextiword());
|
|
break;
|
|
case kAMdAIndex :
|
|
p = ®s.regs[GetDcoFldArgDat(f)];
|
|
v.mem = get_disp_ea(*p);
|
|
break;
|
|
case kAMdAbsW :
|
|
v.mem = ui5r_FromSWord(nextiword());
|
|
break;
|
|
case kAMdAbsL :
|
|
v.mem = nextilong();
|
|
break;
|
|
case kAMdPCDisp :
|
|
v.mem = m68k_getpc();
|
|
v.mem += ui5r_FromSWord(nextiword());
|
|
break;
|
|
case kAMdPCIndex :
|
|
v.mem = get_disp_ea(m68k_getpc());
|
|
break;
|
|
case kAMdImmedB :
|
|
v.mem = ui5r_FromSByte(nextibyte());
|
|
break;
|
|
case kAMdImmedW :
|
|
v.mem = ui5r_FromSWord(nextiword());
|
|
break;
|
|
case kAMdImmedL :
|
|
v.mem = ui5r_FromSLong(nextilong());
|
|
break;
|
|
case kAMdDat4 :
|
|
default: /* make compiler happy, should not happen */
|
|
v.mem = GetDcoFldArgDat(f);
|
|
break;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
LOCALFUNC MayNotInline ui5r GetSrcDstValue(ui5r f, ArgAddrT addr)
|
|
{
|
|
ui5r v;
|
|
|
|
switch (GetDcoFldArgk(f)) {
|
|
case kArgkRegB:
|
|
v = ui5r_FromSByte(*addr.rga);
|
|
break;
|
|
case kArgkRegW:
|
|
v = ui5r_FromSWord(*addr.rga);
|
|
break;
|
|
case kArgkRegL:
|
|
v = ui5r_FromSLong(*addr.rga);
|
|
break;
|
|
case kArgkMemB:
|
|
v = get_byte(addr.mem);
|
|
break;
|
|
case kArgkMemW:
|
|
v = get_word(addr.mem);
|
|
break;
|
|
case kArgkMemL:
|
|
v = get_long(addr.mem);
|
|
break;
|
|
case kArgkCnst:
|
|
default: /* for compiler. shouldn't be any other cases */
|
|
v = addr.mem;
|
|
break;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
LOCALPROC MayNotInline SetSrcDstValue(ui5r f, ArgAddrT addr, ui5r v)
|
|
{
|
|
switch (GetDcoFldArgk(f)) {
|
|
case kArgkRegB:
|
|
*addr.rga = (*addr.rga & ~ 0xff) | ((v) & 0xff);
|
|
break;
|
|
case kArgkRegW:
|
|
*addr.rga = (*addr.rga & ~ 0xffff) | ((v) & 0xffff);
|
|
break;
|
|
case kArgkRegL:
|
|
*addr.rga = v;
|
|
break;
|
|
case kArgkMemB:
|
|
put_byte(addr.mem, v);
|
|
break;
|
|
case kArgkMemW:
|
|
put_word(addr.mem, v);
|
|
break;
|
|
case kArgkMemL:
|
|
put_long(addr.mem, v);
|
|
break;
|
|
default: /* for compiler. shouldn't be any other cases */
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOCALFUNC MayInline ArgAddrT DecodeSrc(void)
|
|
{
|
|
return DecodeSrcDst(regs.CurDecOp.B);
|
|
}
|
|
|
|
LOCALFUNC MayInline ui5r GetSrcValue(ArgAddrT addr)
|
|
{
|
|
return GetSrcDstValue(regs.CurDecOp.B, addr);
|
|
}
|
|
|
|
LOCALFUNC MayInline ArgAddrT DecodeDst(void)
|
|
{
|
|
return DecodeSrcDst(regs.CurDecOp.A);
|
|
}
|
|
|
|
LOCALFUNC MayInline ui5r GetDstValue(ArgAddrT addr)
|
|
{
|
|
return GetSrcDstValue(regs.CurDecOp.A, addr);
|
|
}
|
|
|
|
LOCALPROC MayInline SetDstValue(ArgAddrT addr, ui5r v)
|
|
{
|
|
SetSrcDstValue(regs.CurDecOp.A, addr, v);
|
|
}
|
|
|
|
LOCALFUNC MayNotInline ui5r DecodeSrcDstGet(void)
|
|
{
|
|
ArgAddrT SrcAddr = DecodeSrc();
|
|
ui5r srcvalue = GetSrcValue(SrcAddr);
|
|
ArgAddrT DstAddr = DecodeDst();
|
|
ui5r dstvalue = GetDstValue(DstAddr);
|
|
|
|
regs.SrcVal = srcvalue;
|
|
regs.ArgAddr = DstAddr;
|
|
|
|
return dstvalue;
|
|
}
|
|
|
|
LOCALFUNC MayNotInline ui5r DecodeDstGet(void)
|
|
{
|
|
ArgAddrT DstAddr = DecodeDst();
|
|
ui5r dstvalue = GetDstValue(DstAddr);
|
|
|
|
regs.ArgAddr = DstAddr;
|
|
|
|
return dstvalue;
|
|
}
|
|
|
|
LOCALPROC MayNotInline SetDstArgValue(ui5r v)
|
|
{
|
|
SetDstValue(regs.ArgAddr, v);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeTst(void)
|
|
{
|
|
/* Tst 01001010ssmmmrrr */
|
|
|
|
ArgAddrT DstAddr = DecodeDst();
|
|
ui5r srcvalue = GetDstValue(DstAddr);
|
|
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (srcvalue == 0);
|
|
NFLG = ui5r_MSBisSet(srcvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeCmpB(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
ALU_CmpB(regs.SrcVal, dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeCmpW(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
ALU_CmpW(regs.SrcVal, dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeCmpL(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
ALU_CmpL(regs.SrcVal, dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBraB(void)
|
|
{
|
|
ui5b src = ((ui5b)regs.opcode) & 255;
|
|
#if FastRelativeJump
|
|
ui3p s = regs.pc_p;
|
|
#else
|
|
ui5r s = m68k_getpc();
|
|
#endif
|
|
|
|
s += (si3b)(ui3b)src;
|
|
|
|
#if FastRelativeJump
|
|
regs.pc_p = s;
|
|
#else
|
|
m68k_setpc(s);
|
|
#endif
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBraW(void)
|
|
{
|
|
#if FastRelativeJump
|
|
ui3p s = regs.pc_p;
|
|
#else
|
|
ui5r s = m68k_getpc();
|
|
#endif
|
|
|
|
s += (si4b)(ui4b)nextiword();
|
|
|
|
#if FastRelativeJump
|
|
regs.pc_p = s;
|
|
#else
|
|
m68k_setpc(s);
|
|
#endif
|
|
}
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeBraL(void)
|
|
{
|
|
#if FastRelativeJump
|
|
ui3p s = regs.pc_p;
|
|
#else
|
|
ui5r s = m68k_getpc();
|
|
#endif
|
|
|
|
s += (si5b)(ui5b)nextilong();
|
|
|
|
/* Bra 0110ccccnnnnnnnn */
|
|
#if FastRelativeJump
|
|
regs.pc_p = s;
|
|
#else
|
|
m68k_setpc(s);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
LOCALPROCUSEDONCE DoCodeBccB(void)
|
|
{
|
|
/* Bcc 0110ccccnnnnnnnn */
|
|
if (cctrue()) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (10 * kCycleScale + 2 * RdAvgXtraCyc);
|
|
#endif
|
|
DoCodeBraB();
|
|
} else {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (8 * kCycleScale + RdAvgXtraCyc);
|
|
#endif
|
|
/* do nothing */
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBccW(void)
|
|
{
|
|
/* Bcc 0110ccccnnnnnnnn */
|
|
if (cctrue()) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (10 * kCycleScale + 2 * RdAvgXtraCyc);
|
|
#endif
|
|
DoCodeBraW();
|
|
} else {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (12 * kCycleScale + 2 * RdAvgXtraCyc);
|
|
#endif
|
|
SkipiWord();
|
|
}
|
|
}
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeBccL(void)
|
|
{
|
|
/* Bcc 0110ccccnnnnnnnn */
|
|
if (cctrue()) {
|
|
DoCodeBraL();
|
|
} else {
|
|
SkipiLong();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#define reg (regs.opcode & 7)
|
|
#define rg9 ((regs.opcode >> 9) & 7)
|
|
|
|
LOCALPROCUSEDONCE DoCodeDBcc(void)
|
|
{
|
|
/* DBcc 0101cccc11001ddd */
|
|
|
|
ui5r dstvalue;
|
|
#if FastRelativeJump
|
|
ui3p srcvalue = regs.pc_p;
|
|
#else
|
|
ui5r srcvalue = m68k_getpc();
|
|
#endif
|
|
|
|
srcvalue += (si4b)(ui4b)nextiword();
|
|
if (cctrue()) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (12 * kCycleScale + 2 * RdAvgXtraCyc);
|
|
#endif
|
|
} else {
|
|
dstvalue = ui5r_FromSWord(m68k_dreg(reg));
|
|
--dstvalue;
|
|
m68k_dreg(reg) = (m68k_dreg(reg) & ~ 0xffff)
|
|
| ((dstvalue) & 0xffff);
|
|
if ((si5b)dstvalue == -1) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (14 * kCycleScale + 3 * RdAvgXtraCyc);
|
|
#endif
|
|
} else {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (10 * kCycleScale + 2 * RdAvgXtraCyc);
|
|
#endif
|
|
#if FastRelativeJump
|
|
regs.pc_p = srcvalue;
|
|
#else
|
|
m68k_setpc(srcvalue);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSwap(void)
|
|
{
|
|
/* Swap 0100100001000rrr */
|
|
ui5r srcreg = reg;
|
|
ui5r src = m68k_dreg(srcreg);
|
|
ui5r dst = ui5r_FromSLong(((src >> 16) & 0xFFFF)
|
|
| ((src & 0xFFFF) << 16));
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dst == 0);
|
|
NFLG = ui5r_MSBisSet(dst);
|
|
m68k_dreg(srcreg) = dst;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMove(void)
|
|
{
|
|
ArgAddrT SrcAddr = DecodeSrc();
|
|
ui5r src = GetSrcValue(SrcAddr);
|
|
ArgAddrT DstAddr = DecodeDst();
|
|
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (src == 0);
|
|
NFLG = ui5r_MSBisSet(src);
|
|
SetDstValue(DstAddr, src);
|
|
}
|
|
|
|
LOCALPROC DoCodeMoveA(void) /* MOVE */
|
|
{
|
|
ArgAddrT SrcAddr;
|
|
ui5r src;
|
|
|
|
SrcAddr = DecodeSrc();
|
|
src = GetSrcValue(SrcAddr);
|
|
m68k_areg(rg9) = src;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveQ(void)
|
|
{
|
|
/* MoveQ 0111ddd0nnnnnnnn */
|
|
ui5r src = ui5r_FromSByte(regs.opcode);
|
|
ui5r dstreg = rg9;
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (src == 0);
|
|
NFLG = ui5r_MSBisSet(src);
|
|
m68k_dreg(dstreg) = src;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAddB(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_AddB(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAddW(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_AddW(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAddL(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_AddL(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSubB(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_SubB(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSubW(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_SubW(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSubL(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_SubL(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeLea(void)
|
|
{
|
|
ArgAddrT DstAddr;
|
|
/* Lea 0100aaa111mmmrrr */
|
|
DstAddr = DecodeDst();
|
|
m68k_areg(rg9) = DstAddr.mem;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodePEA(void)
|
|
{
|
|
ArgAddrT DstAddr;
|
|
/* PEA 0100100001mmmrrr */
|
|
DstAddr = DecodeDst();
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), DstAddr.mem);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeA(void)
|
|
{
|
|
BackupPC();
|
|
Exception(0xA);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBsrB(void)
|
|
{
|
|
ui5b src = ((ui5b)regs.opcode) & 255;
|
|
#if FastRelativeJump
|
|
ui3p s = regs.pc_p;
|
|
#else
|
|
ui5r s = m68k_getpc();
|
|
#endif
|
|
|
|
s += (si3b)(ui3b)src;
|
|
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), m68k_getpc());
|
|
#if FastRelativeJump
|
|
regs.pc_p = s;
|
|
#else
|
|
m68k_setpc(s);
|
|
#endif
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBsrW(void)
|
|
{
|
|
#if FastRelativeJump
|
|
ui3p s = regs.pc_p;
|
|
#else
|
|
ui5r s = m68k_getpc();
|
|
#endif
|
|
|
|
s += (si4b)(ui4b)nextiword();
|
|
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), m68k_getpc());
|
|
#if FastRelativeJump
|
|
regs.pc_p = s;
|
|
#else
|
|
m68k_setpc(s);
|
|
#endif
|
|
}
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeBsrL(void)
|
|
{
|
|
#if FastRelativeJump
|
|
ui3p s = regs.pc_p;
|
|
#else
|
|
ui5r s = m68k_getpc();
|
|
#endif
|
|
|
|
s += (si5b)(ui5b)nextilong();
|
|
/* ReportAbnormal("long branch in DoCode6"); */
|
|
/* Used by various Apps */
|
|
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), m68k_getpc());
|
|
#if FastRelativeJump
|
|
regs.pc_p = s;
|
|
#else
|
|
m68k_setpc(s);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
LOCALPROCUSEDONCE DoCodeJsr(void)
|
|
{
|
|
/* Jsr 0100111010mmmrrr */
|
|
ArgAddrT DstAddr = DecodeDst();
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), m68k_getpc());
|
|
m68k_setpc(DstAddr.mem);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeLinkA6(void)
|
|
{
|
|
CPTR stackp = m68k_areg(7);
|
|
stackp -= 4;
|
|
put_long(stackp, m68k_areg(6));
|
|
m68k_areg(6) = stackp;
|
|
m68k_areg(7) = stackp + ui5r_FromSWord(nextiword());
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMOVEMRmML(void)
|
|
{
|
|
/* MOVEM reg to mem 01001000111100rrr */
|
|
si4b z;
|
|
ui5r regmask = nextiword();
|
|
ui5r p = m68k_areg(reg);
|
|
|
|
#if Use68020
|
|
{
|
|
int n = 0;
|
|
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
n++;
|
|
}
|
|
}
|
|
m68k_areg(reg) = p - n * 4;
|
|
}
|
|
#endif
|
|
for (z = 16; --z >= 0; ) {
|
|
if ((regmask & (1 << (15 - z))) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (8 * kCycleScale + 2 * WrAvgXtraCyc);
|
|
#endif
|
|
p -= 4;
|
|
put_long(p, regs.regs[z]);
|
|
}
|
|
}
|
|
#if ! Use68020
|
|
m68k_areg(reg) = p;
|
|
#endif
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMOVEMApRL(void)
|
|
{
|
|
/* MOVEM mem to reg 01001100111011rrr */
|
|
si4b z;
|
|
ui5r regmask = nextiword();
|
|
ui5r p = m68k_areg(reg);
|
|
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (8 * kCycleScale + 2 * RdAvgXtraCyc);
|
|
#endif
|
|
regs.regs[z] = get_long(p);
|
|
p += 4;
|
|
}
|
|
}
|
|
m68k_areg(reg) = p;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeUnlkA6(void)
|
|
{
|
|
ui5r src = m68k_areg(6);
|
|
m68k_areg(6) = get_long(src);
|
|
m68k_areg(7) = src + 4;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeRts(void)
|
|
{
|
|
/* Rts 0100111001110101 */
|
|
ui5r NewPC = get_long(m68k_areg(7));
|
|
m68k_areg(7) += 4;
|
|
m68k_setpc(NewPC);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeJmp(void)
|
|
{
|
|
/* JMP 0100111011mmmrrr */
|
|
ArgAddrT DstAddr = DecodeDst();
|
|
m68k_setpc(DstAddr.mem);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeClr(void)
|
|
{
|
|
/* Clr 01000010ssmmmrrr */
|
|
|
|
ArgAddrT DstAddr = DecodeDst();
|
|
VFLG = CFLG = 0;
|
|
ZFLG = 1;
|
|
NFLG = 0;
|
|
SetDstValue(DstAddr, 0);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAddA(void)
|
|
{
|
|
/* ADDA 1101dddm11mmmrrr */
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
|
|
dstvalue += regs.SrcVal;
|
|
SetDstArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSubA(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
|
|
dstvalue -= regs.SrcVal;
|
|
SetDstArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeCmpA(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
|
|
{
|
|
int flgs = ui5r_MSBisSet(regs.SrcVal);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
dstvalue -= regs.SrcVal;
|
|
dstvalue = ui5r_FromSLong(dstvalue);
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
CFLG = (flgs && ! flgo) || (NFLG && ((! flgo) || flgs));
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAddXB(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_AddXB(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAddXW(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_AddXW(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAddXL(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_AddXL(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSubXB(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_SubXB(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSubXW(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_SubXW(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSubXL(void)
|
|
{
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
SetDstArgValue(ALU_SubXL(regs.SrcVal, dstvalue));
|
|
}
|
|
|
|
LOCALPROC SetArgKindReg(ui5b thereg)
|
|
{
|
|
regs.ArgKind = AKRegister;
|
|
regs.ArgAddr.rga = ®s.regs[thereg];
|
|
}
|
|
|
|
LOCALPROC MayNotInline DecodeModeRegister(ui5b themode, ui5b thereg)
|
|
{
|
|
switch (themode) {
|
|
case 0 :
|
|
SetArgKindReg(thereg);
|
|
break;
|
|
case 1 :
|
|
SetArgKindReg(thereg + 8);
|
|
break;
|
|
case 2 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = m68k_areg(thereg);
|
|
break;
|
|
case 3 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = m68k_areg(thereg);
|
|
if ((thereg == 7) && (regs.opsize == 1)) {
|
|
m68k_areg(thereg) += 2;
|
|
} else {
|
|
m68k_areg(thereg) += regs.opsize;
|
|
}
|
|
break;
|
|
case 4 :
|
|
regs.ArgKind = AKMemory;
|
|
if ((thereg == 7) && (regs.opsize == 1)) {
|
|
m68k_areg(thereg) -= 2;
|
|
} else {
|
|
m68k_areg(thereg) -= regs.opsize;
|
|
}
|
|
regs.ArgAddr.mem = m68k_areg(thereg);
|
|
break;
|
|
case 5 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = m68k_areg(thereg)
|
|
+ ui5r_FromSWord(nextiword());
|
|
break;
|
|
case 6 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = get_disp_ea(m68k_areg(thereg));
|
|
break;
|
|
case 7 :
|
|
switch (thereg) {
|
|
case 0 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = ui5r_FromSWord(nextiword());
|
|
break;
|
|
case 1 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = nextilong();
|
|
break;
|
|
case 2 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = m68k_getpc();
|
|
regs.ArgAddr.mem += ui5r_FromSWord(nextiword());
|
|
break;
|
|
case 3 :
|
|
regs.ArgKind = AKMemory;
|
|
regs.ArgAddr.mem = get_disp_ea(m68k_getpc());
|
|
break;
|
|
case 4 :
|
|
regs.ArgKind = AKConstant;
|
|
if (regs.opsize == 2) {
|
|
regs.ArgAddr.mem = ui5r_FromSWord(nextiword());
|
|
} else if (regs.opsize < 2) {
|
|
regs.ArgAddr.mem = ui5r_FromSByte(nextibyte());
|
|
} else {
|
|
regs.ArgAddr.mem = ui5r_FromSLong(nextilong());
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 8 :
|
|
regs.ArgKind = AKConstant;
|
|
regs.ArgAddr.mem = thereg;
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOCALFUNC ui5r GetArgValue(void)
|
|
{
|
|
ui5r v;
|
|
|
|
switch (regs.ArgKind) {
|
|
case AKMemory:
|
|
if (regs.opsize == 2) {
|
|
v = get_word(regs.ArgAddr.mem);
|
|
} else if (regs.opsize < 2) {
|
|
v = get_byte(regs.ArgAddr.mem);
|
|
} else {
|
|
v = get_long(regs.ArgAddr.mem);
|
|
}
|
|
break;
|
|
case AKRegister:
|
|
v = *regs.ArgAddr.rga;
|
|
if (regs.opsize == 2) {
|
|
v = ui5r_FromSWord(v);
|
|
} else if (regs.opsize < 2) {
|
|
v = ui5r_FromSByte(v);
|
|
} else {
|
|
v = ui5r_FromSLong(v);
|
|
}
|
|
break;
|
|
case AKConstant:
|
|
default: /* for compiler. shouldn't be any other cases */
|
|
v = regs.ArgAddr.mem;
|
|
break;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
LOCALPROC SetArgValue(ui5r v)
|
|
{
|
|
if (regs.ArgKind == AKRegister) {
|
|
if (regs.opsize == 2) {
|
|
*regs.ArgAddr.rga =
|
|
(*regs.ArgAddr.rga & ~ 0xffff) | ((v) & 0xffff);
|
|
} else if (regs.opsize < 2) {
|
|
*regs.ArgAddr.rga =
|
|
(*regs.ArgAddr.rga & ~ 0xff) | ((v) & 0xff);
|
|
} else {
|
|
*regs.ArgAddr.rga = v;
|
|
}
|
|
} else {
|
|
/* must be AKMemory */
|
|
/* should not get here for AKConstant */
|
|
if (regs.opsize == 2) {
|
|
put_word(regs.ArgAddr.mem, v);
|
|
} else if (regs.opsize < 2) {
|
|
put_byte(regs.ArgAddr.mem, v);
|
|
} else {
|
|
put_long(regs.ArgAddr.mem, v);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define b76 ((regs.opcode >> 6) & 3)
|
|
#define b8 ((regs.opcode >> 8) & 1)
|
|
#define mode ((regs.opcode >> 3) & 7)
|
|
#define md6 ((regs.opcode >> 6) & 7)
|
|
|
|
LOCALPROC FindOpSizeFromb76(void)
|
|
{
|
|
regs.opsize = 1 << b76;
|
|
#if 0
|
|
switch (b76) {
|
|
case 0 :
|
|
regs.opsize = 1;
|
|
break;
|
|
case 1 :
|
|
regs.opsize = 2;
|
|
break;
|
|
case 2 :
|
|
regs.opsize = 4;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
LOCALFUNC ui5r octdat(ui5r x)
|
|
{
|
|
if (x == 0) {
|
|
return 8;
|
|
} else {
|
|
return x;
|
|
}
|
|
}
|
|
|
|
#define extendopsizedstvalue() \
|
|
if (regs.opsize == 2) {\
|
|
dstvalue = ui5r_FromSWord(dstvalue);\
|
|
} else if (regs.opsize < 2) {\
|
|
dstvalue = ui5r_FromSByte(dstvalue);\
|
|
} else {\
|
|
dstvalue = ui5r_FromSLong(dstvalue);\
|
|
}
|
|
|
|
#define unextendopsizedstvalue() \
|
|
if (regs.opsize == 2) {\
|
|
dstvalue = ui5r_FromUWord(dstvalue);\
|
|
} else if (regs.opsize < 2) {\
|
|
dstvalue = ui5r_FromUByte(dstvalue);\
|
|
} else {\
|
|
dstvalue = ui5r_FromULong(dstvalue);\
|
|
}
|
|
|
|
#define BinOpASL 0
|
|
#define BinOpASR 1
|
|
#define BinOpLSL 2
|
|
#define BinOpLSR 3
|
|
#define BinOpRXL 4
|
|
#define BinOpRXR 5
|
|
#define BinOpROL 6
|
|
#define BinOpROR 7
|
|
|
|
LOCALPROC DoBinOp1(ui5r srcvalue, ui5r binop)
|
|
{
|
|
ui5r dstvalue;
|
|
ui5r cnt = srcvalue & 63;
|
|
|
|
dstvalue = GetArgValue();
|
|
switch (binop) {
|
|
case BinOpASL:
|
|
{
|
|
ui5r dstvalue0 = dstvalue;
|
|
ui5r comparevalue;
|
|
if (! cnt) {
|
|
VFLG = 0;
|
|
CFLG = 0;
|
|
} else {
|
|
if (cnt > 32) {
|
|
dstvalue = 0;
|
|
} else {
|
|
dstvalue = dstvalue << (cnt - 1);
|
|
}
|
|
extendopsizedstvalue();
|
|
CFLG = XFLG = ui5r_MSBisSet(dstvalue);
|
|
dstvalue = dstvalue << 1;
|
|
extendopsizedstvalue();
|
|
}
|
|
if (ui5r_MSBisSet(dstvalue)) {
|
|
comparevalue = - ((- dstvalue) >> cnt);
|
|
} else {
|
|
comparevalue = dstvalue >> cnt;
|
|
}
|
|
VFLG = (comparevalue != dstvalue0);
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
}
|
|
break;
|
|
case BinOpASR:
|
|
{
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = 0;
|
|
if (! cnt) {
|
|
CFLG = 0;
|
|
} else {
|
|
if (NFLG) {
|
|
dstvalue = (~ dstvalue);
|
|
}
|
|
unextendopsizedstvalue();
|
|
if (cnt > 32) {
|
|
dstvalue = 0;
|
|
} else {
|
|
dstvalue = dstvalue >> (cnt - 1);
|
|
}
|
|
CFLG = (dstvalue & 1) != 0;
|
|
dstvalue = dstvalue >> 1;
|
|
if (NFLG) {
|
|
CFLG = ! CFLG;
|
|
dstvalue = (~ dstvalue);
|
|
}
|
|
XFLG = CFLG;
|
|
}
|
|
ZFLG = (dstvalue == 0);
|
|
}
|
|
break;
|
|
case BinOpLSL:
|
|
{
|
|
if (! cnt) {
|
|
CFLG = 0;
|
|
} else {
|
|
if (cnt > 32) {
|
|
dstvalue = 0;
|
|
} else {
|
|
dstvalue = dstvalue << (cnt - 1);
|
|
}
|
|
extendopsizedstvalue();
|
|
CFLG = XFLG = ui5r_MSBisSet(dstvalue);
|
|
dstvalue = dstvalue << 1;
|
|
extendopsizedstvalue();
|
|
}
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = 0;
|
|
}
|
|
break;
|
|
case BinOpLSR:
|
|
{
|
|
if (! cnt) {
|
|
CFLG = 0;
|
|
} else {
|
|
unextendopsizedstvalue();
|
|
if (cnt > 32) {
|
|
dstvalue = 0;
|
|
} else {
|
|
dstvalue = dstvalue >> (cnt - 1);
|
|
}
|
|
CFLG = XFLG = (dstvalue & 1) != 0;
|
|
dstvalue = dstvalue >> 1;
|
|
}
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
/* if cnt != 0, always false */
|
|
VFLG = 0;
|
|
}
|
|
break;
|
|
case BinOpROL:
|
|
{
|
|
if (! cnt) {
|
|
CFLG = 0;
|
|
} else {
|
|
for (; cnt; --cnt) {
|
|
CFLG = ui5r_MSBisSet(dstvalue);
|
|
dstvalue = dstvalue << 1;
|
|
if (CFLG) {
|
|
dstvalue = dstvalue | 1;
|
|
}
|
|
extendopsizedstvalue();
|
|
}
|
|
}
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = 0;
|
|
}
|
|
break;
|
|
case BinOpRXL:
|
|
{
|
|
if (! cnt) {
|
|
CFLG = XFLG;
|
|
} else {
|
|
for (; cnt; --cnt) {
|
|
CFLG = ui5r_MSBisSet(dstvalue);
|
|
dstvalue = dstvalue << 1;
|
|
if (XFLG) {
|
|
dstvalue = dstvalue | 1;
|
|
}
|
|
extendopsizedstvalue();
|
|
XFLG = CFLG;
|
|
}
|
|
}
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = 0;
|
|
}
|
|
break;
|
|
case BinOpROR:
|
|
{
|
|
ui5r cmask = (ui5r)1 << (regs.opsize * 8 - 1);
|
|
if (! cnt) {
|
|
CFLG = 0;
|
|
} else {
|
|
unextendopsizedstvalue();
|
|
for (; cnt; --cnt) {
|
|
CFLG = (dstvalue & 1) != 0;
|
|
dstvalue = dstvalue >> 1;
|
|
if (CFLG) {
|
|
dstvalue = dstvalue | cmask;
|
|
}
|
|
}
|
|
extendopsizedstvalue();
|
|
}
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = 0;
|
|
}
|
|
break;
|
|
case BinOpRXR:
|
|
{
|
|
ui5r cmask = (ui5r)1 << (regs.opsize * 8 - 1);
|
|
if (! cnt) {
|
|
CFLG = XFLG;
|
|
} else {
|
|
unextendopsizedstvalue();
|
|
for (; cnt; --cnt) {
|
|
CFLG = (dstvalue & 1) != 0;
|
|
dstvalue = dstvalue >> 1;
|
|
if (XFLG) {
|
|
dstvalue = dstvalue | cmask;
|
|
}
|
|
XFLG = CFLG;
|
|
}
|
|
extendopsizedstvalue();
|
|
}
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = 0;
|
|
}
|
|
break;
|
|
default:
|
|
/* should not get here */
|
|
break;
|
|
}
|
|
SetArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALFUNC ui5r rolops(ui5r x)
|
|
{
|
|
ui5r binop;
|
|
|
|
binop = (x << 1);
|
|
if (! b8) {
|
|
binop++; /* 'R' */
|
|
} /* else 'L' */
|
|
return binop;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeRolopNM(void)
|
|
{
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
DoBinOp1(1, rolops(rg9));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeRolopND(void)
|
|
{
|
|
/* 1110cccdss0ttddd */
|
|
FindOpSizeFromb76();
|
|
SetArgKindReg(reg);
|
|
DoBinOp1(octdat(rg9), rolops(mode & 3));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeRolopDD(void)
|
|
{
|
|
/* 1110rrrdss1ttddd */
|
|
ui5r srcvalue;
|
|
FindOpSizeFromb76();
|
|
SetArgKindReg(rg9);
|
|
srcvalue = GetArgValue();
|
|
SetArgKindReg(reg);
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= ((srcvalue & 63) * 2 * kCycleScale);
|
|
#endif
|
|
DoBinOp1(srcvalue, rolops(mode & 3));
|
|
}
|
|
|
|
#define BinOpBTst 0
|
|
#define BinOpBChg 1
|
|
#define BinOpBClr 2
|
|
#define BinOpBSet 3
|
|
|
|
LOCALPROC DoBinBitOp1(ui5r srcvalue)
|
|
{
|
|
ui5r dstvalue;
|
|
ui5r binop;
|
|
|
|
dstvalue = GetArgValue();
|
|
|
|
ZFLG = ((dstvalue & ((ui5r)1 << srcvalue)) == 0);
|
|
binop = b76;
|
|
if (binop != BinOpBTst) {
|
|
switch (binop) {
|
|
case BinOpBChg:
|
|
dstvalue ^= (1 << srcvalue);
|
|
break;
|
|
case BinOpBClr:
|
|
dstvalue &= ~ (1 << srcvalue);
|
|
break;
|
|
case BinOpBSet:
|
|
dstvalue |= (1 << srcvalue);
|
|
break;
|
|
default:
|
|
/* should not get here */
|
|
break;
|
|
}
|
|
SetArgValue(dstvalue);
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBitOpDD(void)
|
|
{
|
|
/* dynamic bit, Opcode = 0000ddd1tt000rrr */
|
|
ui5r srcvalue = (ui5r_FromSByte(m68k_dreg(rg9))) & 31;
|
|
regs.opsize = 4;
|
|
SetArgKindReg(reg);
|
|
DoBinBitOp1(srcvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBitOpDM(void)
|
|
{
|
|
/* dynamic bit, Opcode = 0000ddd1ttmmmrrr */
|
|
ui5r srcvalue = (ui5r_FromSByte(m68k_dreg(rg9))) & 7;
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(mode, reg);
|
|
DoBinBitOp1(srcvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBitOpND(void)
|
|
{
|
|
/* static bit 00001010tt000rrr */
|
|
ui5r srcvalue = (ui5r_FromSByte(nextibyte())) & 31;
|
|
regs.opsize = 4;
|
|
SetArgKindReg(reg);
|
|
DoBinBitOp1(srcvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeBitOpNM(void)
|
|
{
|
|
/* static bit 00001010ttmmmrrr */
|
|
ui5r srcvalue = (ui5r_FromSByte(nextibyte())) & 7;
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(mode, reg);
|
|
DoBinBitOp1(srcvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAnd(void)
|
|
{
|
|
/* DoBinOpAnd(DecodeI_xxxxxxxxssmmmrrr()); */
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
|
|
dstvalue &= regs.SrcVal;
|
|
/*
|
|
don't need to extend, since excess high
|
|
bits all the same as desired high bit.
|
|
*/
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
|
|
SetDstArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeOr(void)
|
|
{
|
|
/* DoBinOr(DecodeI_xxxxxxxxssmmmrrr()); */
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
|
|
dstvalue |= regs.SrcVal;
|
|
/*
|
|
don't need to extend, since excess high
|
|
bits all the same as desired high bit.
|
|
*/
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
|
|
SetDstArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeEor(void)
|
|
{
|
|
/* Eor 1011ddd1ssmmmrrr */
|
|
/* DoBinOpEor(DecodeDEa_xxxxdddxssmmmrrr()); */
|
|
ui5r dstvalue = DecodeSrcDstGet();
|
|
|
|
dstvalue ^= regs.SrcVal;
|
|
/*
|
|
don't need to extend, since excess high
|
|
bits all the same as desired high bit.
|
|
*/
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
|
|
SetDstArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNot(void)
|
|
{
|
|
/* Not 01000110ssmmmrrr */
|
|
ui5r dstvalue = DecodeDstGet();
|
|
|
|
dstvalue = ~ dstvalue;
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = CFLG = 0;
|
|
|
|
SetDstArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeScc(void)
|
|
{
|
|
/* Scc 0101cccc11mmmrrr */
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(mode, reg);
|
|
if (cctrue()) {
|
|
#if WantCloserCyc
|
|
if (mode == 0) {
|
|
regs.MaxCyclesToGo -= (2 * kCycleScale);
|
|
}
|
|
#endif
|
|
SetArgValue(0xff);
|
|
} else {
|
|
SetArgValue(0);
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeEXTL(void)
|
|
{
|
|
/* EXT.L */
|
|
ui5r srcreg = reg;
|
|
ui5r src = m68k_dreg(srcreg);
|
|
ui5r dst = ui5r_FromSWord(src);
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dst == 0);
|
|
NFLG = ui5r_MSBisSet(dst);
|
|
m68k_dreg(srcreg) = dst;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeEXTW(void)
|
|
{
|
|
/* EXT.W */
|
|
ui5r srcreg = reg;
|
|
ui5r src = m68k_dreg(srcreg);
|
|
ui5r dst = ui5r_FromSByte(src);
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dst == 0);
|
|
NFLG = ui5r_MSBisSet(dst);
|
|
m68k_dreg(srcreg) = (m68k_dreg(srcreg) & ~ 0xffff) | (dst & 0xffff);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNegB(void)
|
|
{
|
|
ui5r dstvalue = DecodeDstGet();
|
|
SetDstArgValue(ALU_NegB(dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNegW(void)
|
|
{
|
|
ui5r dstvalue = DecodeDstGet();
|
|
SetDstArgValue(ALU_NegW(dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNegL(void)
|
|
{
|
|
ui5r dstvalue = DecodeDstGet();
|
|
SetDstArgValue(ALU_NegL(dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNegXB(void)
|
|
{
|
|
ui5r dstvalue = DecodeDstGet();
|
|
SetDstArgValue(ALU_NegXB(dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNegXW(void)
|
|
{
|
|
ui5r dstvalue = DecodeDstGet();
|
|
SetDstArgValue(ALU_NegXW(dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNegXL(void)
|
|
{
|
|
ui5r dstvalue = DecodeDstGet();
|
|
SetDstArgValue(ALU_NegXL(dstvalue));
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMulU(void)
|
|
{
|
|
/* MulU 1100ddd011mmmrrr */
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
srcvalue = GetArgValue();
|
|
dstvalue = ui5r_FromSLong(ui5r_FromUWord(regs.regs[rg9])
|
|
* ui5r_FromUWord(srcvalue));
|
|
#if WantCloserCyc
|
|
{
|
|
ui5r v = srcvalue;
|
|
|
|
while (v != 0) {
|
|
if ((v & 1) != 0) {
|
|
regs.MaxCyclesToGo -= (2 * kCycleScale);
|
|
}
|
|
v >>= 1;
|
|
}
|
|
}
|
|
#endif
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
regs.regs[rg9] = dstvalue;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMulS(void)
|
|
{
|
|
/* MulS 1100ddd111mmmrrr */
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
srcvalue = GetArgValue();
|
|
dstvalue = ui5r_FromSLong((si5b)(si4b)regs.regs[rg9]
|
|
* (si5b)(si4b)srcvalue);
|
|
#if WantCloserCyc
|
|
{
|
|
ui5r v = (srcvalue << 1);
|
|
|
|
while (v != 0) {
|
|
if ((v & 1) != ((v >> 1) & 1)) {
|
|
regs.MaxCyclesToGo -= (2 * kCycleScale);
|
|
}
|
|
v >>= 1;
|
|
}
|
|
}
|
|
#endif
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
regs.regs[rg9] = dstvalue;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeDivU(void)
|
|
{
|
|
/* DivU 1000ddd011mmmrrr */
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
srcvalue = GetArgValue();
|
|
dstvalue = regs.regs[rg9];
|
|
if (srcvalue == 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(38 * kCycleScale + 3 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
Exception(5);
|
|
#if m68k_logExceptions
|
|
dbglog_StartLine();
|
|
dbglog_writeCStr("*** zero devide exception");
|
|
dbglog_writeReturn();
|
|
#endif
|
|
} else {
|
|
ui5b newv = (ui5b)dstvalue / (ui5b)(ui4b)srcvalue;
|
|
ui5b rem = (ui5b)dstvalue % (ui5b)(ui4b)srcvalue;
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (133 * kCycleScale);
|
|
#endif
|
|
if (newv > 0xffff) {
|
|
VFLG = NFLG = 1;
|
|
CFLG = 0;
|
|
} else {
|
|
VFLG = CFLG = 0;
|
|
ZFLG = ((si4b)(newv)) == 0;
|
|
NFLG = ((si4b)(newv)) < 0;
|
|
newv = (newv & 0xffff) | ((ui5b)rem << 16);
|
|
dstvalue = newv;
|
|
}
|
|
}
|
|
regs.regs[rg9] = dstvalue;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeDivS(void)
|
|
{
|
|
/* DivS 1000ddd111mmmrrr */
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
srcvalue = GetArgValue();
|
|
dstvalue = regs.regs[rg9];
|
|
if (srcvalue == 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(38 * kCycleScale + 3 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
Exception(5);
|
|
#if m68k_logExceptions
|
|
dbglog_StartLine();
|
|
dbglog_writeCStr("*** zero devide exception");
|
|
dbglog_writeReturn();
|
|
#endif
|
|
} else {
|
|
si5b newv = (si5b)dstvalue / (si5b)(si4b)srcvalue;
|
|
ui4b rem = (si5b)dstvalue % (si5b)(si4b)srcvalue;
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (150 * kCycleScale);
|
|
#endif
|
|
if (((newv & 0xffff8000) != 0) &&
|
|
((newv & 0xffff8000) != 0xffff8000))
|
|
{
|
|
VFLG = NFLG = 1;
|
|
CFLG = 0;
|
|
} else {
|
|
if (((si4b)rem < 0) != ((si5b)dstvalue < 0)) {
|
|
rem = - rem;
|
|
}
|
|
VFLG = CFLG = 0;
|
|
ZFLG = ((si4b)(newv)) == 0;
|
|
NFLG = ((si4b)(newv)) < 0;
|
|
newv = (newv & 0xffff) | ((ui5b)rem << 16);
|
|
dstvalue = newv;
|
|
}
|
|
}
|
|
regs.regs[rg9] = dstvalue;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeExgdd(void)
|
|
{
|
|
/* Exg 1100ddd101000rrr, opsize = 4 */
|
|
ui5r srcreg = rg9;
|
|
ui5r dstreg = reg;
|
|
ui5r src = m68k_dreg(srcreg);
|
|
ui5r dst = m68k_dreg(dstreg);
|
|
m68k_dreg(srcreg) = dst;
|
|
m68k_dreg(dstreg) = src;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeExgaa(void)
|
|
{
|
|
/* Exg 1100ddd101001rrr, opsize = 4 */
|
|
ui5r srcreg = rg9;
|
|
ui5r dstreg = reg;
|
|
ui5r src = m68k_areg(srcreg);
|
|
ui5r dst = m68k_areg(dstreg);
|
|
m68k_areg(srcreg) = dst;
|
|
m68k_areg(dstreg) = src;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeExgda(void)
|
|
{
|
|
/* Exg 1100ddd110001rrr, opsize = 4 */
|
|
ui5r srcreg = rg9;
|
|
ui5r dstreg = reg;
|
|
ui5r src = m68k_dreg(srcreg);
|
|
ui5r dst = m68k_areg(dstreg);
|
|
m68k_dreg(srcreg) = dst;
|
|
m68k_areg(dstreg) = src;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveCCREa(void)
|
|
{
|
|
/* Move from CCR 0100001011mmmrrr */
|
|
#if ! Use68020
|
|
ReportAbnormal("Move from CCR");
|
|
#endif
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
SetArgValue(m68k_getSR() & 0xFF);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveEaCR(void)
|
|
{
|
|
/* 0100010011mmmrrr */
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
m68k_setCR(GetArgValue());
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveSREa(void)
|
|
{
|
|
/* Move from SR 0100000011mmmrrr */
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
SetArgValue(m68k_getSR());
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveEaSR(void)
|
|
{
|
|
/* 0100011011mmmrrr */
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
m68k_setSR(GetArgValue());
|
|
}
|
|
|
|
LOCALPROC DoPrivilegeViolation(void)
|
|
{
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo += GetDcoCycles(®s.CurDecOp);
|
|
regs.MaxCyclesToGo -=
|
|
(34 * kCycleScale + 4 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
BackupPC();
|
|
Exception(8);
|
|
}
|
|
|
|
LOCALPROC DoBinOpStatusCCR(void)
|
|
{
|
|
blnr IsStatus = (b76 != 0);
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
FindOpSizeFromb76();
|
|
if (IsStatus && (! regs.s)) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
srcvalue = ui5r_FromSWord(nextiword());
|
|
dstvalue = m68k_getSR();
|
|
switch (rg9) {
|
|
case 0 :
|
|
dstvalue |= srcvalue;
|
|
break;
|
|
case 1 :
|
|
dstvalue &= srcvalue;
|
|
break;
|
|
case 5 :
|
|
dstvalue ^= srcvalue;
|
|
break;
|
|
default: /* should not happen */
|
|
break;
|
|
}
|
|
if (IsStatus) {
|
|
m68k_setSR(dstvalue);
|
|
} else {
|
|
m68k_setCR(dstvalue);
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMOVEMApRW(void)
|
|
{
|
|
/* MOVEM mem to reg 01001100110011rrr */
|
|
si4b z;
|
|
ui5r regmask = nextiword();
|
|
ui5r p = m68k_areg(reg);
|
|
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (4 * kCycleScale + RdAvgXtraCyc);
|
|
#endif
|
|
regs.regs[z] = get_word(p);
|
|
p += 2;
|
|
}
|
|
}
|
|
m68k_areg(reg) = p;
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMOVEMRmMW(void)
|
|
{
|
|
/* MOVEM reg to mem 01001000110100rrr */
|
|
si4b z;
|
|
ui5r regmask = nextiword();
|
|
ui5r p = m68k_areg(reg);
|
|
|
|
#if Use68020
|
|
{
|
|
int n = 0;
|
|
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
n++;
|
|
}
|
|
}
|
|
m68k_areg(reg) = p - n * 2;
|
|
}
|
|
#endif
|
|
for (z = 16; --z >= 0; ) {
|
|
if ((regmask & (1 << (15 - z))) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (4 * kCycleScale + WrAvgXtraCyc);
|
|
#endif
|
|
p -= 2;
|
|
put_word(p, regs.regs[z]);
|
|
}
|
|
}
|
|
#if ! Use68020
|
|
m68k_areg(reg) = p;
|
|
#endif
|
|
}
|
|
|
|
LOCALPROC reglist(si4b direction, ui5b m1, ui5b r1)
|
|
{
|
|
si4b z;
|
|
ui5r p;
|
|
ui5r regmask;
|
|
|
|
regmask = nextiword();
|
|
regs.opsize = 2 * b76 - 2;
|
|
DecodeModeRegister(m1, r1);
|
|
p = regs.ArgAddr.mem;
|
|
if (direction == 0) {
|
|
if (regs.opsize == 2) {
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(4 * kCycleScale + WrAvgXtraCyc);
|
|
#endif
|
|
put_word(p, regs.regs[z]);
|
|
p += 2;
|
|
}
|
|
}
|
|
} else {
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(8 * kCycleScale + 2 * WrAvgXtraCyc);
|
|
#endif
|
|
put_long(p, regs.regs[z]);
|
|
p += 4;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (regs.opsize == 2) {
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(4 * kCycleScale + RdAvgXtraCyc);
|
|
#endif
|
|
regs.regs[z] = get_word(p);
|
|
p += 2;
|
|
}
|
|
}
|
|
} else {
|
|
for (z = 0; z < 16; ++z) {
|
|
if ((regmask & (1 << z)) != 0) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(8 * kCycleScale + 2 * RdAvgXtraCyc);
|
|
#endif
|
|
regs.regs[z] = get_long(p);
|
|
p += 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMOVEMrm(void)
|
|
{
|
|
/* MOVEM reg to mem 010010001ssmmmrrr */
|
|
reglist(0, mode, reg);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMOVEMmr(void)
|
|
{
|
|
/* MOVEM mem to reg 0100110011smmmrrr */
|
|
reglist(1, mode, reg);
|
|
}
|
|
|
|
LOCALPROC DoBinOpAbcd(ui5b m1, ui5b r1, ui5b m2, ui5b r2)
|
|
{
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(m1, r1);
|
|
srcvalue = GetArgValue();
|
|
DecodeModeRegister(m2, r2);
|
|
dstvalue = GetArgValue();
|
|
{
|
|
/* if (regs.opsize != 1) a bug */
|
|
int flgs = ui5r_MSBisSet(srcvalue);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
ui4b newv_lo =
|
|
(srcvalue & 0xF) + (dstvalue & 0xF) + (XFLG ? 1 : 0);
|
|
ui4b newv_hi = (srcvalue & 0xF0) + (dstvalue & 0xF0);
|
|
ui4b newv;
|
|
|
|
if (newv_lo > 9) {
|
|
newv_lo += 6;
|
|
}
|
|
newv = newv_hi + newv_lo;
|
|
CFLG = XFLG = (newv & 0x1F0) > 0x90;
|
|
if (CFLG) {
|
|
newv += 0x60;
|
|
}
|
|
dstvalue = ui5r_FromSByte(newv);
|
|
if (dstvalue != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
/*
|
|
but according to my reference book,
|
|
VFLG is Undefined for ABCD
|
|
*/
|
|
}
|
|
SetArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAbcdr(void)
|
|
{
|
|
/* ABCD 1100ddd100000rrr */
|
|
DoBinOpAbcd(0, reg, 0, rg9);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeAbcdm(void)
|
|
{
|
|
/* ABCD 1100ddd100001rrr */
|
|
DoBinOpAbcd(4, reg, 4, rg9);
|
|
}
|
|
|
|
LOCALPROC DoBinOpSbcd(ui5b m1, ui5b r1, ui5b m2, ui5b r2)
|
|
{
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(m1, r1);
|
|
srcvalue = GetArgValue();
|
|
DecodeModeRegister(m2, r2);
|
|
dstvalue = GetArgValue();
|
|
{
|
|
int flgs = ui5r_MSBisSet(srcvalue);
|
|
int flgo = ui5r_MSBisSet(dstvalue);
|
|
ui4b newv_lo =
|
|
(dstvalue & 0xF) - (srcvalue & 0xF) - (XFLG ? 1 : 0);
|
|
ui4b newv_hi = (dstvalue & 0xF0) - (srcvalue & 0xF0);
|
|
ui4b newv;
|
|
|
|
if (newv_lo > 9) {
|
|
newv_lo -= 6;
|
|
newv_hi -= 0x10;
|
|
}
|
|
newv = newv_hi + (newv_lo & 0xF);
|
|
CFLG = XFLG = (newv_hi & 0x1F0) > 0x90;
|
|
if (CFLG) {
|
|
newv -= 0x60;
|
|
}
|
|
dstvalue = ui5r_FromSByte(newv);
|
|
if (dstvalue != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
/*
|
|
but according to my reference book,
|
|
VFLG is Undefined for SBCD
|
|
*/
|
|
}
|
|
SetArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSbcdr(void)
|
|
{
|
|
/* SBCD 1000xxx100000xxx */
|
|
DoBinOpSbcd(0, reg, 0, rg9);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeSbcdm(void)
|
|
{
|
|
/* SBCD 1000xxx100001xxx */
|
|
DoBinOpSbcd(4, reg, 4, rg9);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNbcd(void)
|
|
{
|
|
/* Nbcd 0100100000mmmrrr */
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(mode, reg);
|
|
dstvalue = GetArgValue();
|
|
{
|
|
ui4b newv_lo = - (dstvalue & 0xF) - (XFLG ? 1 : 0);
|
|
ui4b newv_hi = - (dstvalue & 0xF0);
|
|
ui4b newv;
|
|
|
|
if (newv_lo > 9) {
|
|
newv_lo -= 6;
|
|
newv_hi -= 0x10;
|
|
}
|
|
newv = newv_hi + (newv_lo & 0xF);
|
|
CFLG = XFLG = (newv_hi & 0x1F0) > 0x90;
|
|
if (CFLG) {
|
|
newv -= 0x60;
|
|
}
|
|
|
|
dstvalue = ui5r_FromSByte(newv);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
if (dstvalue != 0) {
|
|
ZFLG = 0;
|
|
}
|
|
}
|
|
SetArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeRte(void)
|
|
{
|
|
/* Rte 0100111001110011 */
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
ui5r NewPC;
|
|
CPTR stackp = m68k_areg(7);
|
|
ui5r NewSR = get_word(stackp);
|
|
stackp += 2;
|
|
NewPC = get_long(stackp);
|
|
stackp += 4;
|
|
|
|
#if Use68020
|
|
{
|
|
ui4b format = get_word(stackp);
|
|
stackp += 2;
|
|
|
|
switch ((format >> 12) & 0x0F) {
|
|
case 0:
|
|
/* ReportAbnormal("rte stack frame format 0"); */
|
|
break;
|
|
case 1:
|
|
ReportAbnormal("rte stack frame format 1");
|
|
NewPC = m68k_getpc() - 2;
|
|
/* rerun instruction */
|
|
break;
|
|
case 2:
|
|
ReportAbnormal("rte stack frame format 2");
|
|
stackp += 4;
|
|
break;
|
|
case 9:
|
|
ReportAbnormal("rte stack frame format 9");
|
|
stackp += 12;
|
|
break;
|
|
case 10:
|
|
ReportAbnormal("rte stack frame format 10");
|
|
stackp += 24;
|
|
break;
|
|
case 11:
|
|
ReportAbnormal("rte stack frame format 11");
|
|
stackp += 84;
|
|
break;
|
|
default:
|
|
ReportAbnormal("unknown rte stack frame format");
|
|
Exception(14);
|
|
return;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
m68k_areg(7) = stackp;
|
|
m68k_setSR(NewSR);
|
|
m68k_setpc(NewPC);
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeNop(void)
|
|
{
|
|
/* Nop 0100111001110001 */
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveP(void)
|
|
{
|
|
/* MoveP 0000ddd1mm001aaa */
|
|
ui5r TheReg = reg;
|
|
ui5r TheRg9 = rg9;
|
|
ui5r Displacement = nextiword();
|
|
/* shouldn't this sign extend ? */
|
|
CPTR memp = m68k_areg(TheReg) + Displacement;
|
|
|
|
#if 0
|
|
if ((Displacement & 0x00008000) != 0) {
|
|
/* **** for testing only **** */
|
|
BackupPC();
|
|
op_illg();
|
|
}
|
|
#endif
|
|
|
|
switch (b76) {
|
|
case 0:
|
|
{
|
|
ui4b val = ((get_byte(memp) & 0x00FF) << 8)
|
|
| (get_byte(memp + 2) & 0x00FF);
|
|
|
|
m68k_dreg(TheRg9) =
|
|
(m68k_dreg(TheRg9) & ~ 0xffff) | (val & 0xffff);
|
|
}
|
|
break;
|
|
case 1:
|
|
{
|
|
ui5b val = ((get_byte(memp) & 0x00FF) << 24)
|
|
| ((get_byte(memp + 2) & 0x00FF) << 16)
|
|
| ((get_byte(memp + 4) & 0x00FF) << 8)
|
|
| (get_byte(memp + 6) & 0x00FF);
|
|
|
|
m68k_dreg(TheRg9) = val;
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
si4b src = m68k_dreg(TheRg9);
|
|
|
|
put_byte(memp, src >> 8);
|
|
put_byte(memp + 2, src);
|
|
}
|
|
break;
|
|
case 3:
|
|
{
|
|
si5b src = m68k_dreg(TheRg9);
|
|
|
|
put_byte(memp, src >> 24);
|
|
put_byte(memp + 2, src >> 16);
|
|
put_byte(memp + 4, src >> 8);
|
|
put_byte(memp + 6, src);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOCALPROC op_illg(void)
|
|
{
|
|
BackupPC();
|
|
Exception(4);
|
|
}
|
|
|
|
LOCALPROC DoCheck(void)
|
|
{
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
DecodeModeRegister(mode, reg);
|
|
srcvalue = GetArgValue();
|
|
DecodeModeRegister(0, rg9);
|
|
dstvalue = GetArgValue();
|
|
if (ui5r_MSBisSet(dstvalue)) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(30 * kCycleScale + 3 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
NFLG = 1;
|
|
Exception(6);
|
|
} else if (((si5r)dstvalue) > ((si5r)srcvalue)) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(30 * kCycleScale + 3 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
NFLG = 0;
|
|
Exception(6);
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeChkW(void)
|
|
{
|
|
/* Chk.W 0100ddd110mmmrrr */
|
|
regs.opsize = 2;
|
|
DoCheck();
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeTrap(void)
|
|
{
|
|
/* Trap 010011100100vvvv */
|
|
Exception((regs.opcode & 15) + 32);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeTrapV(void)
|
|
{
|
|
/* TrapV 0100111001110110 */
|
|
if (VFLG) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo += GetDcoCycles(®s.CurDecOp);
|
|
regs.MaxCyclesToGo -=
|
|
(34 * kCycleScale + 4 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
Exception(7);
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeRtr(void)
|
|
{
|
|
/* Rtr 0100111001110111 */
|
|
ui5r NewPC;
|
|
CPTR stackp = m68k_areg(7);
|
|
ui5r NewCR = get_word(stackp);
|
|
stackp += 2;
|
|
NewPC = get_long(stackp);
|
|
stackp += 4;
|
|
m68k_areg(7) = stackp;
|
|
m68k_setCR(NewCR);
|
|
m68k_setpc(NewPC);
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeLink(void)
|
|
{
|
|
ui5r srcreg = reg;
|
|
CPTR stackp = m68k_areg(7);
|
|
stackp -= 4;
|
|
m68k_areg(7) = stackp; /* only matters if srcreg == 7 */
|
|
put_long(stackp, m68k_areg(srcreg));
|
|
m68k_areg(srcreg) = stackp;
|
|
m68k_areg(7) += ui5r_FromSWord(nextiword());
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeUnlk(void)
|
|
{
|
|
ui5r srcreg = reg;
|
|
if (srcreg != 7) {
|
|
ui5r src = m68k_areg(srcreg);
|
|
m68k_areg(srcreg) = get_long(src);
|
|
m68k_areg(7) = src + 4;
|
|
} else {
|
|
/* wouldn't expect this to happen */
|
|
m68k_areg(7) = get_long(m68k_areg(7)) + 4;
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveRUSP(void)
|
|
{
|
|
/* MOVE USP 0100111001100aaa */
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
regs.usp = m68k_areg(reg);
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeMoveUSPR(void)
|
|
{
|
|
/* MOVE USP 0100111001101aaa */
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
m68k_areg(reg) = regs.usp;
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeTas(void)
|
|
{
|
|
/* Tas 0100101011mmmrrr */
|
|
ui5r dstvalue;
|
|
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(mode, reg);
|
|
dstvalue = GetArgValue();
|
|
|
|
{
|
|
ZFLG = (dstvalue == 0);
|
|
NFLG = ui5r_MSBisSet(dstvalue);
|
|
VFLG = CFLG = 0;
|
|
dstvalue |= 0x80;
|
|
}
|
|
SetArgValue(dstvalue);
|
|
}
|
|
|
|
LOCALPROC DoCodeFdefault(void)
|
|
{
|
|
BackupPC();
|
|
Exception(0xB);
|
|
}
|
|
|
|
#if EmMMU
|
|
LOCALPROCUSEDONCE DoCodeMMU(void)
|
|
{
|
|
/*
|
|
Emulate enough of MMU for System 7.5.5 universal
|
|
to boot on Mac Plus 68020. There is one
|
|
spurious "PMOVE TC, (A0)".
|
|
And implement a few more PMOVE operations seen
|
|
when running Disk Copy 6.3.3 and MacsBug.
|
|
*/
|
|
if (regs.opcode == 0xF010) {
|
|
ui4b ew = (int)nextiword();
|
|
if (ew == 0x4200) {
|
|
/* PMOVE TC, (A0) */
|
|
/* fprintf(stderr, "0xF010 0x4200\n"); */
|
|
regs.opsize = 4;
|
|
DecodeModeRegister(mode, reg);
|
|
SetArgValue(0);
|
|
return;
|
|
} else if ((ew == 0x4E00) || (ew == 0x4A00)) {
|
|
/* PMOVE CRP, (A0) and PMOVE SRP, (A0) */
|
|
/* fprintf(stderr, "0xF010 %x\n", ew); */
|
|
regs.opsize = 4;
|
|
DecodeModeRegister(mode, reg);
|
|
SetArgValue(0x7FFF0001);
|
|
regs.ArgAddr.mem += 4;
|
|
SetArgValue(0);
|
|
return;
|
|
} else if (ew == 0x6200) {
|
|
/* PMOVE MMUSR, (A0) */
|
|
/* fprintf(stderr, "0xF010 %x\n", ew); */
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(mode, reg);
|
|
SetArgValue(0);
|
|
return;
|
|
}
|
|
/* fprintf(stderr, "extensions %x\n", ew); */
|
|
BackupPC();
|
|
}
|
|
/* fprintf(stderr, "opcode %x\n", (int)regs.opcode); */
|
|
ReportAbnormal("MMU op");
|
|
DoCodeFdefault();
|
|
}
|
|
#endif
|
|
|
|
#if EmFPU
|
|
|
|
#if 0
|
|
#include "FPMATHNT.h"
|
|
#else
|
|
#include "FPMATHEM.h"
|
|
#endif
|
|
|
|
#include "FPCPEMDV.h"
|
|
|
|
#endif
|
|
|
|
LOCALPROCUSEDONCE DoCodeF(void)
|
|
{
|
|
/* ReportAbnormal("DoCodeF"); */
|
|
#if EmMMU
|
|
if (0 == rg9) {
|
|
DoCodeMMU();
|
|
} else
|
|
#endif
|
|
#if EmFPU
|
|
if (1 == rg9) {
|
|
DoCodeFPU();
|
|
} else
|
|
#endif
|
|
{
|
|
DoCodeFdefault();
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeCallMorRtm(void)
|
|
{
|
|
/* CALLM or RTM 0000011011mmmrrr */
|
|
ReportAbnormal("CALLM or RTM instruction");
|
|
}
|
|
|
|
LOCALPROC m68k_setstopped(void)
|
|
{
|
|
/* not implemented. doesn't seemed to be used on Mac Plus */
|
|
Exception(4); /* fake an illegal instruction */
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeStop(void)
|
|
{
|
|
/* Stop 0100111001110010 */
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
m68k_setSR(nextiword());
|
|
m68k_setstopped();
|
|
}
|
|
}
|
|
|
|
LOCALPROCUSEDONCE DoCodeReset(void)
|
|
{
|
|
/* Reset 0100111001100000 */
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
customreset();
|
|
}
|
|
}
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeEXTBL(void)
|
|
{
|
|
/* EXTB.L */
|
|
ui5r srcreg = reg;
|
|
ui5r src = m68k_dreg(srcreg);
|
|
ui5r dst = ui5r_FromSByte(src);
|
|
VFLG = CFLG = 0;
|
|
ZFLG = (dst == 0);
|
|
NFLG = ui5r_MSBisSet(dst);
|
|
m68k_dreg(srcreg) = dst;
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoCHK2orCMP2(void)
|
|
{
|
|
/* CHK2 or CMP2 00000ss011mmmrrr */
|
|
ui5r regv;
|
|
ui5r lower;
|
|
ui5r upper;
|
|
ui5r extra = nextiword();
|
|
|
|
/* ReportAbnormal("CHK2 or CMP2 instruction"); */
|
|
switch ((regs.opcode >> 9) & 3) {
|
|
case 0:
|
|
regs.opsize = 1;
|
|
break;
|
|
case 1:
|
|
regs.opsize = 2;
|
|
break;
|
|
case 2:
|
|
regs.opsize = 4;
|
|
break;
|
|
default:
|
|
ReportAbnormal("illegal opsize in CHK2 or CMP2");
|
|
break;
|
|
}
|
|
if ((extra & 0x8000) == 0) {
|
|
DecodeModeRegister(0, (extra >> 12) & 0x07);
|
|
regv = GetArgValue();
|
|
} else {
|
|
regv = ui5r_FromSLong(m68k_areg((extra >> 12) & 0x07));
|
|
}
|
|
DecodeModeRegister(mode, reg);
|
|
/* regs.ArgKind == AKMemory, otherwise illegal and don't get here */
|
|
lower = GetArgValue();
|
|
regs.ArgAddr.mem += regs.opsize;
|
|
upper = GetArgValue();
|
|
|
|
ZFLG = (upper == regv) || (lower == regv);
|
|
CFLG = (((si5r)lower) <= ((si5r)upper))
|
|
? (((si5r)regv) < ((si5r)lower)
|
|
|| ((si5r)regv) > ((si5r)upper))
|
|
: (((si5r)regv) > ((si5r)upper)
|
|
|| ((si5r)regv) < ((si5r)lower));
|
|
if ((extra & 0x800) && CFLG) {
|
|
Exception(6);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoCAS(void)
|
|
{
|
|
/* CAS 00001ss011mmmrrr */
|
|
ui5r srcvalue;
|
|
ui5r dstvalue;
|
|
|
|
ui4b src = nextiword();
|
|
int ru = (src >> 6) & 7;
|
|
int rc = src & 7;
|
|
|
|
ReportAbnormal("CAS instruction");
|
|
switch ((regs.opcode >> 9) & 3) {
|
|
case 1 :
|
|
regs.opsize = 1;
|
|
break;
|
|
case 2 :
|
|
regs.opsize = 2;
|
|
break;
|
|
case 3 :
|
|
regs.opsize = 4;
|
|
break;
|
|
}
|
|
|
|
DecodeModeRegister(0, rc);
|
|
srcvalue = GetArgValue();
|
|
DecodeModeRegister(mode, reg);
|
|
dstvalue = GetArgValue();
|
|
{
|
|
int flgs = ((si5b)srcvalue) < 0;
|
|
int flgo = ((si5b)dstvalue) < 0;
|
|
ui5r newv = dstvalue - srcvalue;
|
|
if (regs.opsize == 1) {
|
|
newv = ui5r_FromSByte(newv);
|
|
} else if (regs.opsize == 2) {
|
|
newv = ui5r_FromSWord(newv);
|
|
} else {
|
|
newv = ui5r_FromSLong(newv);
|
|
}
|
|
ZFLG = (((si5b)newv) == 0);
|
|
NFLG = (((si5b)newv) < 0);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
CFLG = (flgs && ! flgo) || (NFLG && ((! flgo) || flgs));
|
|
if (ZFLG) {
|
|
SetArgValue(m68k_dreg(ru));
|
|
} else {
|
|
DecodeModeRegister(0, rc);
|
|
SetArgValue(dstvalue);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoCAS2(void)
|
|
{
|
|
/* CAS2 00001ss011111100 */
|
|
ui5b extra = nextilong();
|
|
int dc2 = extra & 7;
|
|
int du2 = (extra >> 6) & 7;
|
|
int dc1 = (extra >> 16) & 7;
|
|
int du1 = (extra >> 22) & 7;
|
|
CPTR rn1 = regs.regs[(extra >> 28) & 0x0F];
|
|
CPTR rn2 = regs.regs[(extra >> 12) & 0x0F];
|
|
si5b src = m68k_dreg(dc1);
|
|
si5r dst1;
|
|
si5r dst2;
|
|
|
|
ReportAbnormal("DoCAS2 instruction");
|
|
switch ((regs.opcode >> 9) & 3) {
|
|
case 1 :
|
|
op_illg();
|
|
return;
|
|
break;
|
|
case 2 :
|
|
regs.opsize = 2;
|
|
break;
|
|
case 3 :
|
|
regs.opsize = 4;
|
|
break;
|
|
}
|
|
if (regs.opsize == 2) {
|
|
dst1 = get_word(rn1);
|
|
dst2 = get_word(rn2);
|
|
src = (si5b)(si4b)src;
|
|
} else {
|
|
dst1 = get_long(rn1);
|
|
dst2 = get_long(rn2);
|
|
}
|
|
{
|
|
int flgs = src < 0;
|
|
int flgo = dst1 < 0;
|
|
si5b newv = dst1 - src;
|
|
if (regs.opsize == 2) {
|
|
newv = (ui4b)newv;
|
|
}
|
|
ZFLG = (newv == 0);
|
|
NFLG = (newv < 0);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
CFLG = (flgs && ! flgo) || (NFLG && ((! flgo) || flgs));
|
|
if (ZFLG) {
|
|
src = m68k_dreg(dc2);
|
|
if (regs.opsize == 2) {
|
|
src = (si5b)(si4b)src;
|
|
}
|
|
flgs = src < 0;
|
|
flgo = dst2 < 0;
|
|
newv = dst2 - src;
|
|
if (regs.opsize == 2) {
|
|
newv = (ui4b)newv;
|
|
}
|
|
ZFLG = (newv == 0);
|
|
NFLG = (newv < 0);
|
|
VFLG = (flgs != flgo) && (NFLG != flgo);
|
|
CFLG = (flgs && ! flgo) || (NFLG && ((! flgo) || flgs));
|
|
if (ZFLG) {
|
|
if (regs.opsize == 2) {
|
|
put_word(rn1, m68k_dreg(du1));
|
|
put_word(rn2, m68k_dreg(du2));
|
|
} else {
|
|
put_word(rn1, m68k_dreg(du1));
|
|
put_word(rn2, m68k_dreg(du2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (! ZFLG) {
|
|
if (regs.opsize == 2) {
|
|
m68k_dreg(du1) =
|
|
(m68k_dreg(du1) & ~ 0xffff) | ((ui5b)dst1 & 0xffff);
|
|
m68k_dreg(du2) =
|
|
(m68k_dreg(du2) & ~ 0xffff) | ((ui5b)dst2 & 0xffff);
|
|
} else {
|
|
m68k_dreg(du1) = dst1;
|
|
m68k_dreg(du2) = dst2;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoMOVES(void)
|
|
{
|
|
/* MoveS 00001110ssmmmrrr */
|
|
ReportAbnormal("MoveS instruction");
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
ui4b extra = nextiword();
|
|
FindOpSizeFromb76();
|
|
DecodeModeRegister(mode, reg);
|
|
if (extra & 0x0800) {
|
|
ui5b src = regs.regs[(extra >> 12) & 0x0F];
|
|
SetArgValue(src);
|
|
} else {
|
|
ui5b rr = (extra >> 12) & 7;
|
|
si5b srcvalue = GetArgValue();
|
|
if (extra & 0x8000) {
|
|
m68k_areg(rr) = srcvalue;
|
|
} else {
|
|
DecodeModeRegister(0, rr);
|
|
SetArgValue(srcvalue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#define ui5b_lo(x) ((x) & 0x0000FFFF)
|
|
#define ui5b_hi(x) (((x) >> 16) & 0x0000FFFF)
|
|
|
|
#if Use68020
|
|
struct ui6r0 {
|
|
ui5b hi;
|
|
ui5b lo;
|
|
};
|
|
typedef struct ui6r0 ui6r0;
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC Ui6r_Negate(ui6r0 *v)
|
|
{
|
|
v->hi = ~ v->hi;
|
|
v->lo = - v->lo;
|
|
if (v->lo == 0) {
|
|
v->hi++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALFUNC blnr Ui6r_IsZero(ui6r0 *v)
|
|
{
|
|
return (v->hi == 0) && (v->lo == 0);
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALFUNC blnr Ui6r_IsNeg(ui6r0 *v)
|
|
{
|
|
return ((si5b)v->hi) < 0;
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC mul_unsigned(ui5b src1, ui5b src2, ui6r0 *dst)
|
|
{
|
|
ui5b src1_lo = ui5b_lo(src1);
|
|
ui5b src2_lo = ui5b_lo(src2);
|
|
ui5b src1_hi = ui5b_hi(src1);
|
|
ui5b src2_hi = ui5b_hi(src2);
|
|
|
|
ui5b r0 = src1_lo * src2_lo;
|
|
ui5b r1 = src1_hi * src2_lo;
|
|
ui5b r2 = src1_lo * src2_hi;
|
|
ui5b r3 = src1_hi * src2_hi;
|
|
|
|
ui5b ra1 = ui5b_hi(r0) + ui5b_lo(r1) + ui5b_lo(r2);
|
|
|
|
dst->lo = (ui5b_lo(ra1) << 16) | ui5b_lo(r0);
|
|
dst->hi = ui5b_hi(ra1) + ui5b_hi(r1) + ui5b_hi(r2) + r3;
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALFUNC blnr div_unsigned(ui6r0 *src, ui5b div,
|
|
ui5b *quot, ui5b *rem)
|
|
{
|
|
int i;
|
|
ui5b q = 0;
|
|
ui5b cbit = 0;
|
|
ui5b src_hi = src->hi;
|
|
ui5b src_lo = src->lo;
|
|
|
|
if (div <= src_hi) {
|
|
return trueblnr;
|
|
}
|
|
for (i = 0 ; i < 32 ; i++) {
|
|
cbit = src_hi & 0x80000000ul;
|
|
src_hi <<= 1;
|
|
if (src_lo & 0x80000000ul) {
|
|
src_hi++;
|
|
}
|
|
src_lo <<= 1;
|
|
q = q << 1;
|
|
if (cbit || div <= src_hi) {
|
|
q |= 1;
|
|
src_hi -= div;
|
|
}
|
|
}
|
|
*quot = q;
|
|
*rem = src_hi;
|
|
return falseblnr;
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoMulL(void)
|
|
{
|
|
ui6r0 dst;
|
|
ui5r srcvalue;
|
|
ui4b extra = nextiword();
|
|
ui5b r2 = (extra >> 12) & 7;
|
|
ui5b dstvalue = m68k_dreg(r2);
|
|
|
|
DecodeModeRegister(mode, reg);
|
|
srcvalue = GetArgValue();
|
|
|
|
if (extra & 0x800) {
|
|
/* MULS.L - signed */
|
|
|
|
si5b src1 = (si5b)srcvalue;
|
|
si5b src2 = (si5b)dstvalue;
|
|
flagtype s1 = src1 < 0;
|
|
flagtype s2 = src2 < 0;
|
|
flagtype sr = s1 != s2;
|
|
|
|
/* ReportAbnormal("MULS.L"); */
|
|
/* used by Sys 7.5.5 boot extensions */
|
|
if (s1) {
|
|
src1 = - src1;
|
|
}
|
|
if (s2) {
|
|
src2 = - src2;
|
|
}
|
|
mul_unsigned((ui5b)src1, (ui5b)src2, &dst);
|
|
if (sr) {
|
|
Ui6r_Negate(&dst);
|
|
}
|
|
VFLG = CFLG = 0;
|
|
ZFLG = Ui6r_IsZero(&dst);
|
|
NFLG = Ui6r_IsNeg(&dst);
|
|
if (extra & 0x400) {
|
|
m68k_dreg(extra & 7) = dst.hi;
|
|
} else {
|
|
if ((dst.lo & 0x80000000) != 0) {
|
|
if ((dst.hi & 0xffffffff) != 0xffffffff) {
|
|
VFLG = 1;
|
|
}
|
|
} else {
|
|
if (dst.hi != 0) {
|
|
VFLG = 1;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* MULU.L - unsigned */
|
|
|
|
/* ReportAbnormal("MULU.U"); */
|
|
/* Used by various Apps */
|
|
|
|
mul_unsigned(srcvalue, dstvalue, &dst);
|
|
|
|
VFLG = CFLG = 0;
|
|
ZFLG = Ui6r_IsZero(&dst);
|
|
NFLG = Ui6r_IsNeg(&dst);
|
|
if (extra & 0x400) {
|
|
m68k_dreg(extra & 7) = dst.hi;
|
|
} else {
|
|
if (dst.hi != 0) {
|
|
VFLG = 1;
|
|
}
|
|
}
|
|
}
|
|
m68k_dreg(r2) = dst.lo;
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoDivL(void)
|
|
{
|
|
ui6r0 v2;
|
|
ui5b src;
|
|
ui5b quot;
|
|
ui5b rem;
|
|
ui4b extra = nextiword();
|
|
ui5b rDr = extra & 7;
|
|
ui5b rDq = (extra >> 12) & 7;
|
|
|
|
DecodeModeRegister(mode, reg);
|
|
src = (ui5b)(si5b)GetArgValue();
|
|
|
|
if (src == 0) {
|
|
Exception(5);
|
|
#if m68k_logExceptions
|
|
dbglog_StartLine();
|
|
dbglog_writeCStr("*** zero devide exception");
|
|
dbglog_writeReturn();
|
|
#endif
|
|
return;
|
|
}
|
|
if (0 != (extra & 0x0800)) {
|
|
/* signed variant */
|
|
flagtype sr;
|
|
flagtype s2;
|
|
flagtype s1 = ((si5b)src < 0);
|
|
|
|
v2.lo = (si5b)m68k_dreg(rDq);
|
|
if (extra & 0x0400) {
|
|
v2.hi = (si5b)m68k_dreg(rDr);
|
|
} else {
|
|
v2.hi = ((si5b)v2.lo) < 0 ? -1 : 0;
|
|
}
|
|
s2 = Ui6r_IsNeg(&v2);
|
|
sr = (s1 != s2);
|
|
if (s2) {
|
|
Ui6r_Negate(&v2);
|
|
}
|
|
if (s1) {
|
|
src = - src;
|
|
}
|
|
if (div_unsigned(&v2, src, ", &rem)
|
|
|| (sr ? quot > 0x80000000 : quot > 0x7fffffff))
|
|
{
|
|
VFLG = NFLG = 1;
|
|
CFLG = 0;
|
|
} else {
|
|
if (sr) {
|
|
quot = - quot;
|
|
}
|
|
if (((si5b)rem < 0) != s2) {
|
|
rem = - rem;
|
|
}
|
|
VFLG = CFLG = 0;
|
|
ZFLG = ((si5b)quot) == 0;
|
|
NFLG = ((si5b)quot) < 0;
|
|
m68k_dreg(rDr) = rem;
|
|
m68k_dreg(rDq) = quot;
|
|
}
|
|
} else {
|
|
/* unsigned */
|
|
|
|
v2.lo = (ui5b)m68k_dreg(rDq);
|
|
if (extra & 0x400) {
|
|
v2.hi = (ui5b)m68k_dreg(rDr);
|
|
} else {
|
|
v2.hi = 0;
|
|
}
|
|
if (div_unsigned(&v2, src, ", &rem)) {
|
|
VFLG = NFLG = 1;
|
|
CFLG = 0;
|
|
} else {
|
|
VFLG = CFLG = 0;
|
|
ZFLG = ((si5b)quot) == 0;
|
|
NFLG = ((si5b)quot) < 0;
|
|
m68k_dreg(rDr) = rem;
|
|
m68k_dreg(rDq) = quot;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoMoveToControl(void)
|
|
{
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
ui4b src = nextiword();
|
|
int regno = (src >> 12) & 0x0F;
|
|
ui5b v = regs.regs[regno];
|
|
|
|
switch (src & 0x0FFF) {
|
|
case 0x0000:
|
|
regs.sfc = v & 7;
|
|
/* ReportAbnormal("DoMoveToControl: sfc"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0001:
|
|
regs.dfc = v & 7;
|
|
/* ReportAbnormal("DoMoveToControl: dfc"); */
|
|
break;
|
|
case 0x0002:
|
|
regs.cacr = v & 0x3;
|
|
/* ReportAbnormal("DoMoveToControl: cacr"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
break;
|
|
case 0x0800:
|
|
regs.usp = v;
|
|
ReportAbnormal("DoMoveToControl: usp");
|
|
break;
|
|
case 0x0801:
|
|
regs.vbr = v;
|
|
/* ReportAbnormal("DoMoveToControl: vbr"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0802:
|
|
regs.caar = v &0xfc;
|
|
/* ReportAbnormal("DoMoveToControl: caar"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0803:
|
|
regs.msp = v;
|
|
if (regs.m == 1) {
|
|
m68k_areg(7) = regs.msp;
|
|
}
|
|
/* ReportAbnormal("DoMoveToControl: msp"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0804:
|
|
regs.isp = v;
|
|
if (regs.m == 0) {
|
|
m68k_areg(7) = regs.isp;
|
|
}
|
|
ReportAbnormal("DoMoveToControl: isp");
|
|
break;
|
|
default:
|
|
op_illg();
|
|
ReportAbnormal("DoMoveToControl: unknown reg");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoMoveFromControl(void)
|
|
{
|
|
if (! regs.s) {
|
|
DoPrivilegeViolation();
|
|
} else {
|
|
ui5b v;
|
|
ui4b src = nextiword();
|
|
int regno = (src >> 12) & 0x0F;
|
|
|
|
switch (src & 0x0FFF) {
|
|
case 0x0000:
|
|
v = regs.sfc;
|
|
/* ReportAbnormal("DoMoveFromControl: sfc"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0001:
|
|
v = regs.dfc;
|
|
/* ReportAbnormal("DoMoveFromControl: dfc"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0002:
|
|
v = regs.cacr;
|
|
/* ReportAbnormal("DoMoveFromControl: cacr"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
break;
|
|
case 0x0800:
|
|
v = regs.usp;
|
|
ReportAbnormal("DoMoveFromControl: usp");
|
|
break;
|
|
case 0x0801:
|
|
v = regs.vbr;
|
|
/* ReportAbnormal("DoMoveFromControl: vbr"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0802:
|
|
v = regs.caar;
|
|
/* ReportAbnormal("DoMoveFromControl: caar"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0803:
|
|
v = (regs.m == 1)
|
|
? m68k_areg(7)
|
|
: regs.msp;
|
|
/* ReportAbnormal("DoMoveFromControl: msp"); */
|
|
/* happens on entering macsbug */
|
|
break;
|
|
case 0x0804:
|
|
v = (regs.m == 0)
|
|
? m68k_areg(7)
|
|
: regs.isp;
|
|
ReportAbnormal("DoMoveFromControl: isp");
|
|
break;
|
|
default:
|
|
v = 0;
|
|
ReportAbnormal("DoMoveFromControl: unknown reg");
|
|
op_illg();
|
|
break;
|
|
}
|
|
regs.regs[regno] = v;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeMoveC(void)
|
|
{
|
|
/* MOVEC 010011100111101m */
|
|
/* ReportAbnormal("MOVEC"); */
|
|
switch (reg) {
|
|
case 2:
|
|
DoMoveFromControl();
|
|
break;
|
|
case 3:
|
|
DoMoveToControl();
|
|
break;
|
|
default:
|
|
op_illg();
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeChkL(void)
|
|
{
|
|
/* Chk.L 0100ddd100mmmrrr */
|
|
ReportAbnormal("CHK.L instruction");
|
|
regs.opsize = 4;
|
|
DoCheck();
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeBkpt(void)
|
|
{
|
|
/* BKPT 0100100001001rrr */
|
|
ReportAbnormal("BKPT instruction");
|
|
op_illg();
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeDivL(void)
|
|
{
|
|
regs.opsize = 4;
|
|
/* DIVU 0100110001mmmrrr 0rrr0s0000000rrr */
|
|
/* DIVS 0100110001mmmrrr 0rrr1s0000000rrr */
|
|
/* ReportAbnormal("DIVS/DIVU long"); */
|
|
DoDivL();
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeMulL(void)
|
|
{
|
|
regs.opsize = 4;
|
|
/* MULU 0100110000mmmrrr 0rrr0s0000000rrr */
|
|
/* MULS 0100110000mmmrrr 0rrr1s0000000rrr */
|
|
DoMulL();
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeRtd(void)
|
|
{
|
|
/* Rtd 0100111001110100 */
|
|
ui5r NewPC = get_long(m68k_areg(7));
|
|
si5b offs = (si5b)(si4b)nextiword();
|
|
/* ReportAbnormal("RTD"); */
|
|
/* used by Sys 7.5.5 boot */
|
|
m68k_areg(7) += (4 + offs);
|
|
m68k_setpc(NewPC);
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeLinkL(void)
|
|
{
|
|
/* Link.L 0100100000001rrr */
|
|
|
|
ui5b srcreg = reg;
|
|
CPTR stackp = m68k_areg(7);
|
|
|
|
ReportAbnormal("Link.L");
|
|
|
|
stackp -= 4;
|
|
m68k_areg(7) = stackp; /* only matters if srcreg == 7 */
|
|
put_long(stackp, m68k_areg(srcreg));
|
|
m68k_areg(srcreg) = stackp;
|
|
m68k_areg(7) += (si5b)nextilong();
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeTRAPcc(void)
|
|
{
|
|
/* TRAPcc 0101cccc11111sss */
|
|
/* ReportAbnormal("TRAPcc"); */
|
|
switch (reg) {
|
|
case 2:
|
|
ReportAbnormal("TRAPcc word data");
|
|
(void) nextiword();
|
|
break;
|
|
case 3:
|
|
ReportAbnormal("TRAPcc long data");
|
|
(void) nextilong();
|
|
break;
|
|
case 4:
|
|
/* no optional data */
|
|
break;
|
|
default:
|
|
ReportAbnormal("TRAPcc illegal format");
|
|
op_illg();
|
|
break;
|
|
}
|
|
if (cctrue()) {
|
|
ReportAbnormal("TRAPcc trapping");
|
|
Exception(7);
|
|
/* pc pushed onto stack wrong */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoUNPK(void)
|
|
{
|
|
ui5r val;
|
|
ui5r m1 = ((regs.opcode >> 3) & 1) << 2;
|
|
ui5r srcreg = reg;
|
|
ui5r dstreg = rg9;
|
|
ui5r offs = ui5r_FromSWord(nextiword());
|
|
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(m1, srcreg);
|
|
val = GetArgValue();
|
|
|
|
val = (((val & 0xF0) << 4) | (val & 0x0F)) + offs;
|
|
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(m1, dstreg);
|
|
SetArgValue(val);
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoPACK(void)
|
|
{
|
|
ui5r val;
|
|
ui5r m1 = ((regs.opcode >> 3) & 1) << 2;
|
|
ui5r srcreg = reg;
|
|
ui5r dstreg = rg9;
|
|
ui5r offs = ui5r_FromSWord(nextiword());
|
|
|
|
regs.opsize = 2;
|
|
DecodeModeRegister(m1, srcreg);
|
|
val = GetArgValue();
|
|
|
|
val += offs;
|
|
val = ((val >> 4) & 0xf0) | (val & 0xf);
|
|
|
|
regs.opsize = 1;
|
|
DecodeModeRegister(m1, dstreg);
|
|
SetArgValue(val);
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodePack(void)
|
|
{
|
|
ReportAbnormal("PACK");
|
|
DoPACK();
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROCUSEDONCE DoCodeUnpk(void)
|
|
{
|
|
ReportAbnormal("UNPK");
|
|
DoUNPK();
|
|
}
|
|
#endif
|
|
|
|
#if Use68020
|
|
LOCALPROC DoBitField(void)
|
|
{
|
|
ui5b tmp;
|
|
ui5b newtmp;
|
|
si5b dsta;
|
|
ui5b bf0;
|
|
ui3b bf1;
|
|
ui5b dstreg = regs.opcode & 7;
|
|
ui4b extra = nextiword();
|
|
si5b offset = ((extra & 0x0800) != 0)
|
|
? m68k_dreg((extra >> 6) & 7)
|
|
: ((extra >> 6) & 0x1f);
|
|
ui5b width = ((extra & 0x0020) != 0)
|
|
? m68k_dreg(extra & 7)
|
|
: extra;
|
|
ui3b bfa[5];
|
|
ui5b offwid;
|
|
|
|
/* ReportAbnormal("Bit Field operator"); */
|
|
/* width = ((width - 1) & 0x1f) + 1; */ /* 0 -> 32 */
|
|
width &= 0x001F; /* except width == 0 really means 32 */
|
|
if (mode == 0) {
|
|
bf0 = m68k_dreg(dstreg);
|
|
offset &= 0x1f;
|
|
tmp = bf0;
|
|
if (0 != offset) {
|
|
tmp = (tmp << offset) | (tmp >> (32 - offset));
|
|
}
|
|
} else {
|
|
DecodeModeRegister(mode, reg);
|
|
/*
|
|
regs.ArgKind == AKMemory,
|
|
otherwise illegal and don't get here
|
|
*/
|
|
dsta = regs.ArgAddr.mem;
|
|
dsta +=
|
|
(offset >> 3) | (offset & 0x80000000 ? ~ 0x1fffffff : 0);
|
|
offset &= 7;
|
|
offwid = offset + ((width == 0) ? 32 : width);
|
|
|
|
/* if (offwid > 0) */ {
|
|
bf1 = get_byte(dsta);
|
|
bfa[0] = bf1;
|
|
tmp = ((ui5b)bf1) << (24 + offset);
|
|
}
|
|
if (offwid > 8) {
|
|
bf1 = get_byte(dsta + 1);
|
|
bfa[1] = bf1;
|
|
tmp |= ((ui5b)bf1) << (16 + offset);
|
|
}
|
|
if (offwid > 16) {
|
|
bf1 = get_byte(dsta + 2);
|
|
bfa[2] = bf1;
|
|
tmp |= ((ui5r)bf1) << (8 + offset);
|
|
}
|
|
if (offwid > 24) {
|
|
bf1 = get_byte(dsta + 3);
|
|
bfa[3] = bf1;
|
|
tmp |= ((ui5r)bf1) << (offset);
|
|
}
|
|
if (offwid > 32) {
|
|
bf1 = get_byte(dsta + 4);
|
|
bfa[4] = bf1;
|
|
tmp |= ((ui5r)bf1) >> (8 - offset);
|
|
}
|
|
}
|
|
|
|
NFLG = ((si5b)tmp) < 0;
|
|
if (width != 0) {
|
|
tmp >>= (32 - width);
|
|
}
|
|
ZFLG = tmp == 0;
|
|
VFLG = 0;
|
|
CFLG = 0;
|
|
|
|
newtmp = tmp;
|
|
|
|
switch ((regs.opcode >> 8) & 7) {
|
|
case 0: /* BFTST */
|
|
/* do nothing */
|
|
break;
|
|
case 1: /* BFEXTU */
|
|
m68k_dreg((extra >> 12) & 7) = tmp;
|
|
break;
|
|
case 2: /* BFCHG */
|
|
newtmp = ~ newtmp;
|
|
if (width != 0) {
|
|
newtmp &= ((1 << width) - 1);
|
|
}
|
|
break;
|
|
case 3: /* BFEXTS */
|
|
if (NFLG) {
|
|
m68k_dreg((extra >> 12) & 7) = tmp
|
|
| ((width == 0) ? 0 : (-1 << width));
|
|
} else {
|
|
m68k_dreg((extra >> 12) & 7) = tmp;
|
|
}
|
|
break;
|
|
case 4: /* BFCLR */
|
|
newtmp = 0;
|
|
break;
|
|
case 5: /* BFFFO */
|
|
{
|
|
ui5b mask = 1 << ((width == 0) ? 31 : (width - 1));
|
|
si5b i = offset;
|
|
|
|
while ((0 != mask) && (0 == (tmp & mask))) {
|
|
mask >>= 1;
|
|
i++;
|
|
}
|
|
m68k_dreg((extra >> 12) & 7) = i;
|
|
}
|
|
break;
|
|
case 6: /* BFSET */
|
|
newtmp = (width == 0) ? ~ 0 : ((1 << width) - 1);
|
|
break;
|
|
case 7: /* BFINS */
|
|
newtmp = m68k_dreg((extra >> 12) & 7);
|
|
if (width != 0) {
|
|
newtmp &= ((1 << width) - 1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (newtmp != tmp) {
|
|
|
|
if (width != 0) {
|
|
newtmp <<= (32 - width);
|
|
}
|
|
|
|
if (mode == 0) {
|
|
ui5b mask = ~ 0;
|
|
|
|
if (width != 0) {
|
|
mask <<= (32 - width);
|
|
}
|
|
|
|
if (0 != offset) {
|
|
newtmp = (newtmp >> offset) | (newtmp << (32 - offset));
|
|
mask = (mask >> offset) | (mask << (32 - offset));
|
|
}
|
|
|
|
bf0 = (bf0 & ~ mask) | (newtmp);
|
|
m68k_dreg(dstreg) = bf0;
|
|
} else {
|
|
|
|
/* if (offwid > 0) */ {
|
|
ui3b mask = ~ (0xFF >> offset);
|
|
|
|
bf1 = newtmp >> (24 + offset);
|
|
if (offwid < 8) {
|
|
mask |= (0xFF >> offwid);
|
|
}
|
|
if (mask != 0) {
|
|
bf1 |= bfa[0] & mask;
|
|
}
|
|
put_byte(dsta + 0, bf1);
|
|
}
|
|
if (offwid > 8) {
|
|
bf1 = newtmp >> (16 + offset);
|
|
if (offwid < 16) {
|
|
bf1 |= (bfa[1] & (0xFF >> (offwid - 8)));
|
|
}
|
|
put_byte(dsta + 1, bf1);
|
|
}
|
|
if (offwid > 16) {
|
|
bf1 = newtmp >> (8 + offset);
|
|
if (offwid < 24) {
|
|
bf1 |= (bfa[2] & (0xFF >> (offwid - 16)));
|
|
}
|
|
put_byte(dsta + 2, bf1);
|
|
}
|
|
if (offwid > 24) {
|
|
bf1 = newtmp >> (offset);
|
|
if (offwid < 32) {
|
|
bf1 |= (bfa[3] & (0xFF >> (offwid - 24)));
|
|
}
|
|
put_byte(dsta + 3, bf1);
|
|
}
|
|
if (offwid > 32) {
|
|
bf1 = newtmp << (8 - offset);
|
|
bf1 |= (bfa[4] & (0xFF >> (offwid - 32)));
|
|
put_byte(dsta + 4, bf1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef WantDumpTable
|
|
#define WantDumpTable 0
|
|
#endif
|
|
|
|
#if WantDumpTable
|
|
LOCALVAR ui5b DumpTable[kNumIKinds];
|
|
|
|
LOCALPROC InitDumpTable(void)
|
|
{
|
|
si5b i;
|
|
|
|
for (i = 0; i < kNumIKinds; ++i) {
|
|
DumpTable[i] = 0;
|
|
}
|
|
}
|
|
|
|
LOCALPROC DumpATable(ui5b *p, ui5b n)
|
|
{
|
|
si5b i;
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
dbglog_writeNum(p[i]);
|
|
dbglog_writeReturn();
|
|
}
|
|
}
|
|
|
|
EXPORTPROC DoDumpTable(void);
|
|
GLOBALPROC DoDumpTable(void)
|
|
{
|
|
DumpATable(DumpTable, kNumIKinds);
|
|
}
|
|
#endif
|
|
|
|
LOCALPROC m68k_go_MaxCycles(void)
|
|
{
|
|
/*
|
|
Main loop of emulator.
|
|
|
|
Always execute at least one instruction,
|
|
even if regs.MaxInstructionsToGo == 0.
|
|
Needed for trace flag to work.
|
|
*/
|
|
|
|
do {
|
|
|
|
#if WantDisasm
|
|
DisasmOneOrSave(m68k_getpc());
|
|
#endif
|
|
|
|
regs.opcode = nextiword();
|
|
|
|
regs.CurDecOp = regs.disp_table[regs.opcode];
|
|
#if WantDumpTable
|
|
DumpTable[GetDcoMainClas(®s.CurDecOp)] ++;
|
|
#endif
|
|
regs.MaxCyclesToGo -= GetDcoCycles(®s.CurDecOp);
|
|
|
|
switch (GetDcoMainClas(®s.CurDecOp)) {
|
|
case kIKindTst :
|
|
DoCodeTst();
|
|
break;
|
|
case kIKindCmpB :
|
|
DoCodeCmpB();
|
|
break;
|
|
case kIKindCmpW :
|
|
DoCodeCmpW();
|
|
break;
|
|
case kIKindCmpL :
|
|
DoCodeCmpL();
|
|
break;
|
|
case kIKindBccB :
|
|
DoCodeBccB();
|
|
break;
|
|
case kIKindBccW :
|
|
DoCodeBccW();
|
|
break;
|
|
#if Use68020
|
|
case kIKindBccL :
|
|
DoCodeBccL();
|
|
break;
|
|
#endif
|
|
case kIKindBraB :
|
|
DoCodeBraB();
|
|
break;
|
|
case kIKindBraW :
|
|
DoCodeBraW();
|
|
break;
|
|
#if Use68020
|
|
case kIKindBraL :
|
|
DoCodeBraL();
|
|
break;
|
|
#endif
|
|
case kIKindDBcc :
|
|
DoCodeDBcc();
|
|
break;
|
|
case kIKindDBF :
|
|
DoCodeDBcc();
|
|
break;
|
|
case kIKindSwap :
|
|
DoCodeSwap();
|
|
break;
|
|
case kIKindMoveL :
|
|
DoCodeMove();
|
|
break;
|
|
case kIKindMoveW :
|
|
DoCodeMove();
|
|
break;
|
|
case kIKindMoveB :
|
|
DoCodeMove();
|
|
break;
|
|
case kIKindMoveAL :
|
|
DoCodeMoveA();
|
|
break;
|
|
case kIKindMoveAW :
|
|
DoCodeMoveA();
|
|
break;
|
|
case kIKindMoveQ:
|
|
DoCodeMoveQ();
|
|
break;
|
|
case kIKindAddB :
|
|
DoCodeAddB();
|
|
break;
|
|
case kIKindAddW :
|
|
DoCodeAddW();
|
|
break;
|
|
case kIKindAddL :
|
|
DoCodeAddL();
|
|
break;
|
|
case kIKindSubB :
|
|
DoCodeSubB();
|
|
break;
|
|
case kIKindSubW :
|
|
DoCodeSubW();
|
|
break;
|
|
case kIKindSubL :
|
|
DoCodeSubL();
|
|
break;
|
|
case kIKindLea :
|
|
DoCodeLea();
|
|
break;
|
|
case kIKindPEA :
|
|
DoCodePEA();
|
|
break;
|
|
case kIKindA :
|
|
DoCodeA();
|
|
break;
|
|
case kIKindBsrB :
|
|
DoCodeBsrB();
|
|
break;
|
|
case kIKindBsrW :
|
|
DoCodeBsrW();
|
|
break;
|
|
#if Use68020
|
|
case kIKindBsrL :
|
|
DoCodeBsrL();
|
|
break;
|
|
#endif
|
|
case kIKindJsr :
|
|
DoCodeJsr();
|
|
break;
|
|
case kIKindLinkA6 :
|
|
DoCodeLinkA6();
|
|
break;
|
|
case kIKindMOVEMRmML :
|
|
DoCodeMOVEMRmML();
|
|
break;
|
|
case kIKindMOVEMApRL :
|
|
DoCodeMOVEMApRL();
|
|
break;
|
|
case kIKindUnlkA6 :
|
|
DoCodeUnlkA6();
|
|
break;
|
|
case kIKindRts :
|
|
DoCodeRts();
|
|
break;
|
|
case kIKindJmp :
|
|
DoCodeJmp();
|
|
break;
|
|
case kIKindClr :
|
|
DoCodeClr();
|
|
break;
|
|
case kIKindAddA :
|
|
DoCodeAddA();
|
|
break;
|
|
case kIKindAddQA :
|
|
DoCodeAddA();
|
|
/* DoCodeAddQA(); */
|
|
break;
|
|
case kIKindSubA :
|
|
DoCodeSubA();
|
|
break;
|
|
case kIKindSubQA :
|
|
DoCodeSubA();
|
|
/* DoCodeSubQA(); */
|
|
break;
|
|
case kIKindCmpA :
|
|
DoCodeCmpA();
|
|
break;
|
|
case kIKindAddXB :
|
|
DoCodeAddXB();
|
|
break;
|
|
case kIKindAddXW :
|
|
DoCodeAddXW();
|
|
break;
|
|
case kIKindAddXL :
|
|
DoCodeAddXL();
|
|
break;
|
|
case kIKindSubXB :
|
|
DoCodeSubXB();
|
|
break;
|
|
case kIKindSubXW :
|
|
DoCodeSubXW();
|
|
break;
|
|
case kIKindSubXL :
|
|
DoCodeSubXL();
|
|
break;
|
|
|
|
case kIKindRolopNM :
|
|
DoCodeRolopNM();
|
|
break;
|
|
case kIKindRolopND :
|
|
DoCodeRolopND();
|
|
break;
|
|
case kIKindRolopDD :
|
|
DoCodeRolopDD();
|
|
break;
|
|
case kIKindBitOpDD :
|
|
DoCodeBitOpDD();
|
|
break;
|
|
case kIKindBitOpDM :
|
|
DoCodeBitOpDM();
|
|
break;
|
|
case kIKindBitOpND :
|
|
DoCodeBitOpND();
|
|
break;
|
|
case kIKindBitOpNM :
|
|
DoCodeBitOpNM();
|
|
break;
|
|
|
|
case kIKindAndI :
|
|
DoCodeAnd();
|
|
/* DoCodeAndI(); */
|
|
break;
|
|
case kIKindAndEaD :
|
|
DoCodeAnd();
|
|
/* DoCodeAndEaD(); */
|
|
break;
|
|
case kIKindAndDEa :
|
|
DoCodeAnd();
|
|
/* DoCodeAndDEa(); */
|
|
break;
|
|
case kIKindOrI :
|
|
DoCodeOr();
|
|
break;
|
|
case kIKindOrEaD :
|
|
/* DoCodeOrEaD(); */
|
|
DoCodeOr();
|
|
break;
|
|
case kIKindOrDEa :
|
|
/* DoCodeOrDEa(); */
|
|
DoCodeOr();
|
|
break;
|
|
case kIKindEor :
|
|
DoCodeEor();
|
|
break;
|
|
case kIKindEorI :
|
|
DoCodeEor();
|
|
break;
|
|
case kIKindNot :
|
|
DoCodeNot();
|
|
break;
|
|
|
|
case kIKindScc :
|
|
DoCodeScc();
|
|
break;
|
|
case kIKindEXTL :
|
|
DoCodeEXTL();
|
|
break;
|
|
case kIKindEXTW :
|
|
DoCodeEXTW();
|
|
break;
|
|
case kIKindNegB :
|
|
DoCodeNegB();
|
|
break;
|
|
case kIKindNegW :
|
|
DoCodeNegW();
|
|
break;
|
|
case kIKindNegL :
|
|
DoCodeNegL();
|
|
break;
|
|
case kIKindNegXB :
|
|
DoCodeNegXB();
|
|
break;
|
|
case kIKindNegXW :
|
|
DoCodeNegXW();
|
|
break;
|
|
case kIKindNegXL :
|
|
DoCodeNegXL();
|
|
break;
|
|
|
|
case kIKindMulU :
|
|
DoCodeMulU();
|
|
break;
|
|
case kIKindMulS :
|
|
DoCodeMulS();
|
|
break;
|
|
case kIKindDivU :
|
|
DoCodeDivU();
|
|
break;
|
|
case kIKindDivS :
|
|
DoCodeDivS();
|
|
break;
|
|
case kIKindExgdd :
|
|
DoCodeExgdd();
|
|
break;
|
|
case kIKindExgaa :
|
|
DoCodeExgaa();
|
|
break;
|
|
case kIKindExgda :
|
|
DoCodeExgda();
|
|
break;
|
|
|
|
case kIKindMoveCCREa :
|
|
DoCodeMoveCCREa();
|
|
break;
|
|
case kIKindMoveEaCCR :
|
|
DoCodeMoveEaCR();
|
|
break;
|
|
case kIKindMoveSREa :
|
|
DoCodeMoveSREa();
|
|
break;
|
|
case kIKindMoveEaSR :
|
|
DoCodeMoveEaSR();
|
|
break;
|
|
case kIKindBinOpStatusCCR :
|
|
DoBinOpStatusCCR();
|
|
break;
|
|
|
|
case kIKindMOVEMApRW :
|
|
DoCodeMOVEMApRW();
|
|
break;
|
|
case kIKindMOVEMRmMW :
|
|
DoCodeMOVEMRmMW();
|
|
break;
|
|
case kIKindMOVEMrm :
|
|
DoCodeMOVEMrm();
|
|
break;
|
|
case kIKindMOVEMmr :
|
|
DoCodeMOVEMmr();
|
|
break;
|
|
|
|
case kIKindAbcdr :
|
|
DoCodeAbcdr();
|
|
break;
|
|
case kIKindAbcdm :
|
|
DoCodeAbcdm();
|
|
break;
|
|
case kIKindSbcdr :
|
|
DoCodeSbcdr();
|
|
break;
|
|
case kIKindSbcdm :
|
|
DoCodeSbcdm();
|
|
break;
|
|
case kIKindNbcd :
|
|
DoCodeNbcd();
|
|
break;
|
|
|
|
case kIKindRte :
|
|
DoCodeRte();
|
|
break;
|
|
case kIKindNop :
|
|
DoCodeNop();
|
|
break;
|
|
case kIKindMoveP :
|
|
DoCodeMoveP();
|
|
break;
|
|
case kIKindIllegal :
|
|
op_illg();
|
|
break;
|
|
|
|
case kIKindChkW :
|
|
DoCodeChkW();
|
|
break;
|
|
case kIKindTrap :
|
|
DoCodeTrap();
|
|
break;
|
|
case kIKindTrapV :
|
|
DoCodeTrapV();
|
|
break;
|
|
case kIKindRtr :
|
|
DoCodeRtr();
|
|
break;
|
|
case kIKindLink :
|
|
DoCodeLink();
|
|
break;
|
|
case kIKindUnlk :
|
|
DoCodeUnlk();
|
|
break;
|
|
case kIKindMoveRUSP :
|
|
DoCodeMoveRUSP();
|
|
break;
|
|
case kIKindMoveUSPR :
|
|
DoCodeMoveUSPR();
|
|
break;
|
|
case kIKindTas :
|
|
DoCodeTas();
|
|
break;
|
|
case kIKindF :
|
|
DoCodeF();
|
|
break;
|
|
case kIKindCallMorRtm :
|
|
DoCodeCallMorRtm();
|
|
break;
|
|
case kIKindStop :
|
|
DoCodeStop();
|
|
break;
|
|
case kIKindReset :
|
|
DoCodeReset();
|
|
break;
|
|
#if Use68020
|
|
case kIKindEXTBL :
|
|
DoCodeEXTBL();
|
|
break;
|
|
case kIKindTRAPcc :
|
|
DoCodeTRAPcc();
|
|
break;
|
|
case kIKindChkL :
|
|
DoCodeChkL();
|
|
break;
|
|
case kIKindBkpt :
|
|
DoCodeBkpt();
|
|
break;
|
|
case kIKindDivL :
|
|
DoCodeDivL();
|
|
break;
|
|
case kIKindMulL :
|
|
DoCodeMulL();
|
|
break;
|
|
case kIKindRtd :
|
|
DoCodeRtd();
|
|
break;
|
|
case kIKindMoveC :
|
|
DoCodeMoveC();
|
|
break;
|
|
case kIKindLinkL :
|
|
DoCodeLinkL();
|
|
break;
|
|
case kIKindPack :
|
|
DoCodePack();
|
|
break;
|
|
case kIKindUnpk :
|
|
DoCodeUnpk();
|
|
break;
|
|
case kIKindCHK2orCMP2 :
|
|
DoCHK2orCMP2();
|
|
break;
|
|
case kIKindCAS2 :
|
|
DoCAS2();
|
|
break;
|
|
case kIKindCAS :
|
|
DoCAS();
|
|
break;
|
|
case kIKindMoveS :
|
|
DoMOVES();
|
|
break;
|
|
case kIKindBitField :
|
|
DoBitField();
|
|
break;
|
|
#endif
|
|
}
|
|
} while (regs.MaxCyclesToGo > 0);
|
|
}
|
|
|
|
GLOBALFUNC si5r GetCyclesRemaining(void)
|
|
{
|
|
return regs.MoreCyclesToGo + regs.MaxCyclesToGo;
|
|
}
|
|
|
|
GLOBALPROC SetCyclesRemaining(si5r n)
|
|
{
|
|
if (regs.MaxCyclesToGo >= n) {
|
|
regs.MoreCyclesToGo = 0;
|
|
regs.MaxCyclesToGo = n;
|
|
} else {
|
|
regs.MoreCyclesToGo = n - regs.MaxCyclesToGo;
|
|
}
|
|
}
|
|
|
|
GLOBALFUNC ui3r get_vm_byte(CPTR addr)
|
|
{
|
|
return (ui3b) get_byte(addr);
|
|
}
|
|
|
|
GLOBALFUNC ui4r get_vm_word(CPTR addr)
|
|
{
|
|
return (ui4b) get_word(addr);
|
|
}
|
|
|
|
GLOBALFUNC ui5r get_vm_long(CPTR addr)
|
|
{
|
|
return (ui5b) get_long(addr);
|
|
}
|
|
|
|
GLOBALPROC put_vm_byte(CPTR addr, ui3r b)
|
|
{
|
|
put_byte(addr, ui5r_FromSByte(b));
|
|
}
|
|
|
|
GLOBALPROC put_vm_word(CPTR addr, ui4r w)
|
|
{
|
|
put_word(addr, ui5r_FromSWord(w));
|
|
}
|
|
|
|
GLOBALPROC put_vm_long(CPTR addr, ui5r l)
|
|
{
|
|
put_long(addr, ui5r_FromSLong(l));
|
|
}
|
|
|
|
GLOBALPROC SetHeadATTel(ATTep p)
|
|
{
|
|
regs.MATCrdB.cmpmask = 0;
|
|
regs.MATCrdB.cmpvalu = 0xFFFFFFFF;
|
|
regs.MATCwrB.cmpmask = 0;
|
|
regs.MATCwrB.cmpvalu = 0xFFFFFFFF;
|
|
regs.MATCrdW.cmpmask = 0;
|
|
regs.MATCrdW.cmpvalu = 0xFFFFFFFF;
|
|
regs.MATCwrW.cmpmask = 0;
|
|
regs.MATCwrW.cmpvalu = 0xFFFFFFFF;
|
|
regs.MATCex.cmpmask = 0;
|
|
regs.MATCex.cmpvalu = 0xFFFFFFFF;
|
|
regs.HeadATTel = p;
|
|
}
|
|
|
|
LOCALPROC do_trace(void)
|
|
{
|
|
regs.TracePending = trueblnr;
|
|
NeedToGetOut();
|
|
}
|
|
|
|
GLOBALPROC DiskInsertedPsuedoException(CPTR newpc, ui5b data)
|
|
{
|
|
ExceptionTo(newpc
|
|
#if Use68020
|
|
, 0
|
|
#endif
|
|
);
|
|
m68k_areg(7) -= 4;
|
|
put_long(m68k_areg(7), data);
|
|
}
|
|
|
|
LOCALPROC DoCheckExternalInterruptPending(void)
|
|
{
|
|
ui3r level = *regs.fIPL;
|
|
if ((level > regs.intmask) || (level == 7)) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -=
|
|
(44 * kCycleScale + 5 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
Exception(24 + level);
|
|
regs.intmask = level;
|
|
}
|
|
}
|
|
|
|
GLOBALPROC m68k_IPLchangeNtfy(void)
|
|
{
|
|
ui3r level = *regs.fIPL;
|
|
if ((level > regs.intmask) || (level == 7)) {
|
|
SetExternalInterruptPending();
|
|
}
|
|
}
|
|
|
|
#if WantDumpTable
|
|
FORWARDPROC InitDumpTable(void);
|
|
#endif
|
|
|
|
GLOBALPROC m68k_reset(void)
|
|
{
|
|
#if WantDumpTable
|
|
InitDumpTable();
|
|
#endif
|
|
regs.MaxCyclesToGo = 0;
|
|
regs.MoreCyclesToGo = 0;
|
|
regs.ResidualCycles = 0;
|
|
|
|
do_put_mem_word(regs.fakeword, 0x4AFC);
|
|
/* illegal instruction opcode */
|
|
|
|
#if 0
|
|
regs.ResetPending = trueblnr;
|
|
NeedToGetOut();
|
|
#else
|
|
/* Sets the MC68000 reset jump vector... */
|
|
m68k_setpc(get_long(0x00000004));
|
|
|
|
/* Sets the initial stack vector... */
|
|
m68k_areg(7) = get_long(0x00000000);
|
|
|
|
regs.s = 1;
|
|
#if Use68020
|
|
regs.m = 0;
|
|
regs.t0 = 0;
|
|
#endif
|
|
regs.t1 = 0;
|
|
ZFLG = CFLG = NFLG = VFLG = 0;
|
|
regs.ExternalInterruptPending = falseblnr;
|
|
regs.TracePending = falseblnr;
|
|
regs.intmask = 7;
|
|
|
|
#if Use68020
|
|
regs.sfc = 0;
|
|
regs.dfc = 0;
|
|
regs.vbr = 0;
|
|
regs.cacr = 0;
|
|
regs.caar = 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#if SmallGlobals
|
|
GLOBALPROC MINEM68K_ReserveAlloc(void)
|
|
{
|
|
ReserveAllocOneBlock((ui3p *)®s.disp_table,
|
|
disp_table_sz * 8, 6, falseblnr);
|
|
}
|
|
#endif
|
|
|
|
GLOBALPROC MINEM68K_Init(
|
|
ui3b *fIPL)
|
|
{
|
|
regs.fIPL = fIPL;
|
|
|
|
M68KITAB_setup(regs.disp_table);
|
|
}
|
|
|
|
GLOBALPROC m68k_go_nCycles(ui5b n)
|
|
{
|
|
regs.MaxCyclesToGo += (n + regs.ResidualCycles);
|
|
while (regs.MaxCyclesToGo > 0) {
|
|
|
|
#if 0
|
|
if (regs.ResetPending) {
|
|
m68k_DoReset();
|
|
}
|
|
#endif
|
|
if (regs.TracePending) {
|
|
#if WantCloserCyc
|
|
regs.MaxCyclesToGo -= (34 * kCycleScale
|
|
+ 4 * RdAvgXtraCyc + 3 * WrAvgXtraCyc);
|
|
#endif
|
|
Exception(9);
|
|
}
|
|
if (regs.ExternalInterruptPending) {
|
|
regs.ExternalInterruptPending = falseblnr;
|
|
DoCheckExternalInterruptPending();
|
|
}
|
|
if (regs.t1) {
|
|
do_trace();
|
|
}
|
|
m68k_go_MaxCycles();
|
|
regs.MaxCyclesToGo += regs.MoreCyclesToGo;
|
|
regs.MoreCyclesToGo = 0;
|
|
}
|
|
|
|
regs.ResidualCycles = regs.MaxCyclesToGo;
|
|
regs.MaxCyclesToGo = 0;
|
|
}
|