int movem_index1[256];
int movem_index2[256];
int movem_next[256];
+struct mmufixup mmufixup[2];
cpuop_func *cpufunctbl[65536];
struct cputbl_data
{
// cas undocumented (marked as zero in document) fields do something weird, for example
// setting bit 9 will make "Du" address register but results are not correct.
// so lets make sure unused zero bits are zeroed.
- if (dp->mnemo == i_CAS) {
+ switch (dp->mnemo)
+ {
+ case i_CAS:
+ {
uae_u16 extra = get_word_test(opcode_memory_start + 2);
uae_u16 extra2 = extra;
extra &= (7 << 6) | (7 << 0);
if (extra != extra2) {
put_word_test(opcode_memory_start + 2, extra);
}
+ break;
}
- if (dp->mnemo == i_CAS2) {
+ case i_CAS2:
+ {
uae_u16 extra = get_word_test(opcode_memory_start + 2);
uae_u16 extra2 = extra;
extra &= (7 << 6) | (7 << 0) | (15 << 12);
if (extra != extra2) {
put_word_test(opcode_memory_start + 4, extra);
}
+ break;
}
- if (dp->mnemo == i_CHK2) {
+ case i_CHK2:
+ {
uae_u16 extra = get_word_test(opcode_memory_start + 2);
uae_u16 extra2 = extra;
extra &= (15 << 12);
if (extra != extra2) {
put_word_test(opcode_memory_start + 2, extra);
}
+ break;
+ }
+ case i_BFINS:
+ case i_BFFFO:
+ case i_BFEXTS:
+ case i_BFEXTU:
+ {
+ if (cpu_lvl >= 4) {
+ // 68040+ and extra word bit 15 not zero (hidden A/D field):
+ // REGISTER field becomes address register in some internal
+ // operations, results are also wrong. So clear it here..
+ uae_u16 extra = get_word_test(opcode_memory_start + 2);
+ if (extra & 0x8000) {
+ extra &= ~0x8000;
+ put_word_test(opcode_memory_start + 2, extra);
+ }
+ }
+ break;
+ }
+ case i_DIVL:
+ case i_MULL:
+ {
+ if (cpu_lvl >= 4) {
+ // same as BF instructions but also other bits need clearing
+ // or results are unexplained..
+ uae_u16 extra = get_word_test(opcode_memory_start + 2);
+ if (extra & 0x83f8) {
+ extra &= ~0x83f8;
+ put_word_test(opcode_memory_start + 2, extra);
+ }
+ }
+ break;
+ }
}
}
// execute instruction
SPCFLAG_TRACE = 0;
SPCFLAG_DOTRACE = 0;
+ mmufixup[0].reg = -1;
+ mmufixup[1].reg = -1;
MakeFromSR();
static int using_simple_cycles;
static int using_debugmem;
static int using_test;
+static int need_special_fixup;
static int cpu_level, cpu_generic;
static int count_read, count_write, count_cycles, count_ncycles;
static int count_cycles_ce020;
m68k_pc_offset = m68k_pc_offset_old;
}
-static void addmmufixup (const char *reg)
+static bool needmmufixup(void)
{
+ if (need_special_fixup) {
+ // need to restore -(an)/(an)+ if unimplemented
+ switch (g_instr->mnemo)
+ {
+ case i_MULL:
+ case i_DIVL:
+ case i_CAS:
+ return true;
+ }
+ }
if (!using_mmu)
- return;
+ return false;
if (using_mmu == 68040 && (mmufixupstate || mmufixupcnt > 0))
+ return false;
+ return true;
+}
+
+static void addmmufixup (const char *reg)
+{
+ if (!needmmufixup())
return;
printf ("\tmmufixup[%d].reg = %s;\n", mmufixupcnt, reg);
printf ("\tmmufixup[%d].value = m68k_areg (regs, %s);\n", mmufixupcnt, reg);
genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_LRMW);
if (cpu_level == 5 && curi->size > 0) {
printf ("\tif ((dsta & %d) && currprefs.int_no_unimplemented && get_cpu_model () == 68060) {\n", curi->size == 1 ? 1 : 3);
- if (curi->dmode == Aipi || curi->dmode == Apdi)
- printf ("\t\tm68k_areg (regs, dstreg) %c= %d;\n", curi->dmode == Aipi ? '-' : '+', 1 << curi->size);
+ if (mmufixupcnt)
+ printf("\t\tcpu_restore_fixup();\n");
sync_m68k_pc_noreset ();
printf ("\t\top_unimpl (opcode);\n");
printf ("\t\tgoto %s;\n", endlabelstr);
genamode (curi, curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
sync_m68k_pc ();
- printf ("\tif (!m68k_divl(opcode, dst, extra)) goto %s;\n", endlabelstr);
+ printf("\tif (!m68k_divl(opcode, dst, extra)) {\n");
+ if (mmufixupcnt)
+ printf("\t\tcpu_restore_fixup();\n");
+ printf("\t\tgoto %s;\n", endlabelstr);
+ printf("\t}\n");
need_endlabel = 1;
break;
case i_MULL:
genamode (curi, curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0);
sync_m68k_pc ();
- printf ("\tif (!m68k_mull(opcode, dst, extra)) goto %s;\n", endlabelstr);
+ printf("\tif (!m68k_mull(opcode, dst, extra)) {\n");
+ if (mmufixupcnt)
+ printf("\t\tcpu_restore_fixup();\n");
+ printf("\t\tgoto %s;\n", endlabelstr);
+ printf("\t}\n");
need_endlabel = 1;
break;
case i_BFTST:
cpu_level = 5;
using_prefetch = 0;
using_simple_cycles = 0;
+ need_special_fixup = 1;
}
read_counts();
using_simple_cycles = 0;
using_indirect = 0;
cpu_generic = false;
+ need_special_fixup = 0;
if (id == 11 || id == 12) { // 11 = 68010 prefetch, 12 = 68000 prefetch
cpu_level = id == 11 ? 1 : 0;
} else if (id < 6) {
cpu_level = 5 - (id - 0); // "generic"
cpu_generic = true;
+ need_special_fixup = 1;
} else if (id >= 40 && id < 46) {
cpu_level = 5 - (id - 40); // "generic" + direct
cpu_generic = true;
} else if (id >= 50 && id < 56) {
cpu_level = 5 - (id - 50); // "generic" + indirect
cpu_generic = true;
+ need_special_fixup = 1;
if (id == 50) {
read_counts();
for (rp = 0; rp < nr_cpuop_funcs; rp++)
m68k_setpci (regs.instruction_pc);
regflags.cznv = f.cznv;
regflags.x = f.x;
-
- if (mmufixup[0].reg >= 0) {
- m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
- mmufixup[0].reg = -1;
- }
- if (mmufixup[1].reg >= 0) {
- m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
- mmufixup[1].reg = -1;
- }
-
+ cpu_restore_fixup();
TRY (prb2) {
Exception (prb);
} CATCH (prb2) {
regflags.x = f.x;
m68k_setpci (regs.instruction_pc);
}
-
- if (mmufixup[0].reg >= 0) {
- m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
- mmufixup[0].reg = -1;
- }
-
+ cpu_restore_fixup();
TRY (prb2) {
Exception (prb);
} CATCH (prb2) {
} else {
regflags.cznv = f.cznv;
regflags.x = f.x;
-
- if (mmufixup[0].reg >= 0) {
- m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
- mmufixup[0].reg = -1;
- }
- if (mmufixup[1].reg >= 0) {
- m68k_areg(regs, mmufixup[1].reg) = mmufixup[1].value;
- mmufixup[1].reg = -1;
- }
+ cpu_restore_fixup();
}
m68k_setpci (regs.instruction_pc);
*
* 68000: CV=0. Z: dst==0. N: dst < 0. !N: dst > src.
* 68020: Z: dst==0. N: dst < 0. V: src-dst overflow. C: if dst < 0: (dst > src || src >= 0), if dst > src: (src >= 0).
+ * 68040: N=0. If exception: N=dst < 0
*
*/
void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size)
{
- CLEAR_CZNV();
if (currprefs.cpu_model < 68020) {
+ CLEAR_CZNV();
if (dst == 0)
SET_ZFLG(1);
if (dst < 0)
else if (dst > src)
SET_NFLG(0);
} else if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) {
+ CLEAR_CZNV();
if (dst == 0)
SET_ZFLG(1);
SET_NFLG(dst < 0);
SET_CFLG(src >= 0);
}
}
+ } else {
+ SET_NFLG(0);
+ if (dst < 0 || dst > src) {
+ SET_NFLG(dst < 0);
+ }
}
}
return false;
}
if (src == 0) {
+ if (currprefs.cpu_model == 68060) {
+ SET_CFLG(0);
+ }
Exception_cpu(5);
return false;
}
x_put_long(m68k_areg(regs, 7) + 10, pc);
}
+void cpu_restore_fixup(void)
+{
+ if (mmufixup[0].reg >= 0) {
+ m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
+ mmufixup[0].reg = -1;
+ }
+ if (mmufixup[1].reg >= 0) {
+ m68k_areg(regs, mmufixup[1].reg) = mmufixup[1].value;
+ mmufixup[1].reg = -1;
+ }
+}
+
// Low word: Z and N
void ccr_68000_long_move_ae_LZN(uae_s32 src)
{