From 77dc382b9720c5c54a087060b99d3bf8d6120762 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Fri, 23 Aug 2019 22:39:07 +0300 Subject: [PATCH] More 68040/060 fixes. (Undefined fields in some instructions, MUL.L/DIV.L -(an)/(an)+ an restore if unimplemented) --- cputest.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++--- gencpu.cpp | 42 ++++++++++++++++++++++++++++++++++------ include/newcpu.h | 1 + newcpu.cpp | 28 +++------------------------ newcpu_common.cpp | 24 ++++++++++++++++++++++- 5 files changed, 109 insertions(+), 35 deletions(-) diff --git a/cputest.cpp b/cputest.cpp index 173a18c5..921b851c 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -40,6 +40,7 @@ const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 }; int movem_index1[256]; int movem_index2[256]; int movem_next[256]; +struct mmufixup mmufixup[2]; cpuop_func *cpufunctbl[65536]; struct cputbl_data { @@ -1558,15 +1559,20 @@ static void handle_specials_extra(uae_u16 opcode, uaecptr pc, struct instr *dp) // 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); @@ -1579,14 +1585,49 @@ static void handle_specials_extra(uae_u16 opcode, uaecptr pc, struct instr *dp) 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; + } } } @@ -1662,6 +1703,8 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins // execute instruction SPCFLAG_TRACE = 0; SPCFLAG_DOTRACE = 0; + mmufixup[0].reg = -1; + mmufixup[1].reg = -1; MakeFromSR(); diff --git a/gencpu.cpp b/gencpu.cpp index 4cdb9944..8d7ed33d 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -48,6 +48,7 @@ static int using_waitstates; 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; @@ -861,11 +862,28 @@ static void sync_m68k_pc_noreset (void) 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); @@ -5450,8 +5468,8 @@ bccl_not68020: 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); @@ -5608,14 +5626,22 @@ bccl_not68020: 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: @@ -6404,6 +6430,7 @@ static void generate_cpu_test(int mode) cpu_level = 5; using_prefetch = 0; using_simple_cycles = 0; + need_special_fixup = 1; } read_counts(); @@ -6466,6 +6493,7 @@ static void generate_cpu (int id, int mode) 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; @@ -6572,6 +6600,7 @@ static void generate_cpu (int id, int mode) } 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; @@ -6584,6 +6613,7 @@ static void generate_cpu (int id, int mode) } 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++) diff --git a/include/newcpu.h b/include/newcpu.h index ecd331c0..71757ef7 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -691,6 +691,7 @@ extern void Exception_build_stack_frame_common(uae_u32 oldpc, uae_u32 currpc, ua extern void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format); extern void Exception_build_68000_address_error_stack_frame(uae_u16 mode, uae_u16 opcode, uaecptr fault_addr, uaecptr pc); extern uae_u32 exception_pc(int nr); +extern void cpu_restore_fixup(void); void ccr_68000_long_move_ae_LZN(uae_s32 src); void ccr_68000_long_move_ae_LN(uae_s32 src); diff --git a/newcpu.cpp b/newcpu.cpp index 4f61b88a..55d8f85e 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -5080,16 +5080,7 @@ static void m68k_run_mmu060 (void) 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) { @@ -5140,12 +5131,7 @@ static void m68k_run_mmu040 (void) 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) { @@ -5275,15 +5261,7 @@ insretry: } 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); diff --git a/newcpu_common.cpp b/newcpu_common.cpp index 7befe622..3187cd21 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -860,12 +860,13 @@ void setdivsoverflowflags(uae_s32 dividend, uae_s16 divisor) * * 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) @@ -873,6 +874,7 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size) 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); @@ -896,6 +898,11 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size) SET_CFLG(src >= 0); } } + } else { + SET_NFLG(0); + if (dst < 0 || dst > src) { + SET_NFLG(dst < 0); + } } } @@ -963,6 +970,9 @@ bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra) return false; } if (src == 0) { + if (currprefs.cpu_model == 68060) { + SET_CFLG(0); + } Exception_cpu(5); return false; } @@ -1473,6 +1483,18 @@ void Exception_build_68000_address_error_stack_frame(uae_u16 mode, uae_u16 opcod 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) { -- 2.47.3