/* -- MMU instructions -- */
+static bool mmu_op30_invea(uae_u32 opcode)
+{
+ int eamode = (opcode >> 3) & 7;
+ int rreg = opcode & 7;
+
+ // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
+ if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || eamode == 6 || (eamode == 7 && rreg > 1))
+ return true;
+ return false;
+}
+
bool mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
{
int preg = (next >> 10) & 31;
int rw = (next >> 9) & 1;
int fd = (next >> 8) & 1;
-
+ int unused = (next & 0xff);
+
+ if (mmu_op30_invea(opcode))
+ return true;
+ // unused low 8 bits must be zeroed
+ if (unused)
+ return true;
+ // read and fd set?
+ if (rw && fd)
+ return true;
+
#if MMU030_OP_DBG_MSG
switch (preg) {
case 0x10:
}
break;
case 0x18: // MMUSR
+ if (fd) {
+ // FD must be always zero when MMUSR read or write
+ return true;
+ }
if (rw)
x_put_word (extra, mmusr_030);
else
break;
default:
write_log (_T("Bad PMOVE at %08x\n"),m68k_getpc());
- op_illg (opcode);
return true;
}
- if (!fd && !rw && !(preg==0x18)) {
+ if (!fd && !rw) {
mmu030_flush_atc_all();
}
tt_enabled = (tt0_030 & TT_ENABLE) || (tt1_030 & TT_ENABLE);
int a = (next >> 8) & 1;
int areg = (next&0xE0)>>5;
uae_u32 fc = mmu_op30_helper_get_fc(next);
-
bool write = rw ? false : true;
-
uae_u32 ret = 0;
-
- /* Check this - datasheet says:
- * "When the instruction specifies an address translation cache search
- * with an address register operand, the MC68030 takes an F-line
- * unimplemented instruction exception."
- */
- if (!level && a) { /* correct ? */
+
+ if (mmu_op30_invea(opcode))
+ return true;
+ if (!level && a) {
write_log(_T("PTEST: Bad instruction causing F-line unimplemented instruction exception!\n"));
- Exception(11); /* F-line unimplemented instruction exception */
return true;
}
return false;
}
-bool mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
+static bool mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
{
int rw = (next >> 9) & 1;
- uae_u32 fc = mmu_op30_helper_get_fc(next);
-
+ int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
+ uae_u32 fc = mmu_op30_helper_get_fc(next);
bool write = rw ? false : true;
+ if (mmu_op30_invea(opcode))
+ return true;
+ if (unused)
+ return true;
+
#if 0
write_log (_T("PLOAD%c: Create ATC entry for %08X, FC = %i\n"), write?'W':'R', extra, fc);
#endif
bool mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
{
- uae_u16 mode = (next&0x1C00)>>10;
- uae_u32 fc_mask = (uae_u32)(next&0x00E0)>>5;
+ uae_u16 mode = (next >> 8) & 31;
+ uae_u32 fc_mask = (uae_u32)(next & 0x00E0) >> 5;
uae_u32 fc_base = mmu_op30_helper_get_fc(next);
+ uae_u32 fc_bits = next & 0x7f;
#if 0
switch (mode) {
#endif
switch (mode) {
- case 0x1:
+ case 0x00:
+ return mmu_op30_pload(pc, opcode, next, extra);
+ case 0x04:
+ if (fc_bits)
+ return true;
mmu030_flush_atc_all();
break;
- case 0x4:
+ case 0x10:
mmu030_flush_atc_fc(fc_base, fc_mask);
break;
- case 0x6:
+ case 0x18:
+ if (mmu_op30_invea(opcode))
+ return true;
mmu030_flush_atc_page_fc(extra, fc_base, fc_mask);
break;
-
default:
write_log(_T("PFLUSH ERROR: bad mode! (%i)\n"),mode);
- break;
+ return true;
}
return false;
}
#ifdef CPUEMU_0
-static bool mmu_op30fake_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
+static bool mmu_op30_invea(uae_u32 opcode)
{
- int mode = (opcode >> 3) & 7;
+ int eamode = (opcode >> 3) & 7;
int rreg = opcode & 7;
+
+ // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
+ if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || eamode == 6 || (eamode == 7 && rreg > 1))
+ return true;
+ return false;
+}
+
+static bool mmu_op30fake_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
+{
int preg = (next >> 10) & 31;
int rw = (next >> 9) & 1;
int fd = (next >> 8) & 1;
+ int unused = (next & 0xff);
const TCHAR *reg = NULL;
uae_u32 otc = fake_tc_030;
int siz;
- // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
- if (mode == 0 || mode == 1 || mode == 3 || mode == 4 || mode == 6 || (mode == 7 && rreg > 1)) {
- op_illg (opcode);
+ if (mmu_op30_invea(opcode))
+ return true;
+ // unused low 8 bits must be zeroed
+ if (unused)
+ return true;
+ // read and fd set?
+ if (rw && fd)
return true;
- }
switch (preg)
{
}
break;
case 0x18: // MMUSR
+ if (fd) {
+ // FD must be always zero when MMUSR read or write
+ return true;
+ }
reg = _T("MMUSR");
siz = 2;
if (rw)
break;
}
- if (!reg) {
- op_illg (opcode);
+ if (!reg)
return true;
- }
+
#if MMUOP_DEBUG > 0
{
uae_u32 val;
static bool mmu_op30fake_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
{
+ int eamode = (opcode >> 3) & 7;
+ int rreg = opcode & 7;
+ int level = (next&0x1C00)>>10;
+ int a = (next >> 8) & 1;
+
+ if (mmu_op30_invea(opcode))
+ return true;
+ if (!level && a)
+ return true;
+
#if MMUOP_DEBUG > 0
TCHAR tmp[10];
return false;
}
+static bool mmu_op30fake_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
+{
+ int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
+
+ if (mmu_op30_invea(opcode))
+ return true;
+ if (unused)
+ return true;
+ write_log(_T("PLOAD\n"));
+ return false;
+}
+
static bool mmu_op30fake_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
{
- int mode = (opcode >> 3) & 7;
- int rreg = opcode & 7;
- int flushmode = (next >> 10) & 7;
+ int flushmode = (next >> 8) & 31;
int fc = next & 31;
int mask = (next >> 5) & 3;
+ int fc_bits = next & 0x7f;
TCHAR fname[100];
switch (flushmode)
{
- case 6:
- // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
- if (mode == 0 || mode == 1 || mode == 3 || mode == 4 || mode == 6 || (mode == 7 && rreg > 1)) {
- op_illg (opcode);
+ case 0x00:
+ return mmu_op30fake_pload(pc, opcode, next, extra);
+ case 0x18:
+ if (mmu_op30_invea(opcode))
return true;
- }
_stprintf (fname, _T("FC=%x MASK=%x EA=%08x"), fc, mask, 0);
break;
- case 4:
+ case 0x10:
_stprintf (fname, _T("FC=%x MASK=%x"), fc, mask);
break;
- case 1:
+ case 0x04:
+ if (fc_bits)
+ return true;
_tcscpy (fname, _T("ALL"));
break;
default:
- op_illg (opcode);
return true;
}
#if MMUOP_DEBUG > 0
// 68030 (68851) MMU instructions only
bool mmu_op30 (uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa)
{
- if (currprefs.mmu_model) {
- if (extra & 0x8000) {
- return mmu_op30_ptest (pc, opcode, extra, extraa);
- } else if ((extra&0xE000)==0x2000 && (extra & 0x1C00)) {
- return mmu_op30_pflush (pc, opcode, extra, extraa);
- } else if ((extra&0xE000)==0x2000 && !(extra & 0x1C00)) {
- return mmu_op30_pload (pc, opcode, extra, extraa);
- } else {
- return mmu_op30_pmove (pc, opcode, extra, extraa);
- }
- return false;
- }
-
int type = extra >> 13;
+ bool fline = false;
switch (type)
{
case 0:
case 2:
case 3:
- return mmu_op30fake_pmove (pc, opcode, extra, extraa);
+ if (currprefs.mmu_model)
+ fline = mmu_op30_pmove (pc, opcode, extra, extraa);
+ else
+ fline = mmu_op30fake_pmove (pc, opcode, extra, extraa);
break;
case 1:
- return mmu_op30fake_pflush (pc, opcode, extra, extraa);
+ if (currprefs.mmu_model)
+ fline = mmu_op30_pflush (pc, opcode, extra, extraa);
+ else
+ fline = mmu_op30fake_pflush (pc, opcode, extra, extraa);
break;
case 4:
- return mmu_op30fake_ptest (pc, opcode, extra, extraa);
- break;
- default:
- op_illg (opcode);
- return true;
+ if (currprefs.mmu_model)
+ fline = mmu_op30_ptest (pc, opcode, extra, extraa);
+ else
+ fline = mmu_op30fake_ptest (pc, opcode, extra, extraa);
break;
}
+ if (fline) {
+ m68k_setpc(pc);
+ op_illg(opcode);
+ }
+ return fline;
}
/* check if an address matches a ttr */