From: Toni Wilen Date: Wed, 4 Sep 2019 18:53:27 +0000 (+0300) Subject: More undefined flags emulated. CPU tester MULL.L->MULU.L/MULS.L, DIVL.L->DIVS.L/DIVU... X-Git-Tag: 4300~127 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=cfb30f4102916874be854585abd08207588ed9d5;p=francis%2Fwinuae.git More undefined flags emulated. CPU tester MULL.L->MULU.L/MULS.L, DIVL.L->DIVS.L/DIVU.L/DIVSL.L/DIVUL.L and CHK2->CHK2/CMP2 support. --- diff --git a/cputest.cpp b/cputest.cpp index 0bbbf09f..acfbdf84 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -116,6 +116,7 @@ static uae_u16 sr_undefined_mask; static int low_memory_accessed; static int high_memory_accessed; static int test_memory_accessed; +static uae_u16 extra_or, extra_and; struct uae_prefs currprefs; @@ -1692,9 +1693,9 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins { uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0); uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0); - if (opc == 0x4c40 - && opw1 == 0x2406 -// && opw2 == 0x618d + if (opc == 0x4c42 + && opw1 == 0xcf19 + //&& opw2 == 0x504e ) printf(""); if (regs.sr & 0x2000) @@ -1924,8 +1925,8 @@ static uae_u8 *save_exception(uae_u8 *p, struct instr *dp) static uae_u16 get_ccr_ignore(struct instr *dp) { uae_u16 ccrignoremask = 0; - if (cpu_lvl == 2 && test_exception == 5 && dp->mnemo == i_DIVS) { - // 68020/030 DIVS + Divide by Zero: V state is not stable. + if ((cpu_lvl == 2 || cpu_lvl == 3) && test_exception == 5 && (dp->mnemo == i_DIVS || dp->mnemo == i_DIVL)) { + // 68020/030 DIVS.W/.L + Divide by Zero: V state is not stable. ccrignoremask |= 2; // mask CCR=V } return ccrignoremask; @@ -1950,7 +1951,7 @@ static int isfpp(int mnemo) static const TCHAR *sizes[] = { _T("B"), _T("W"), _T("L") }; -static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, int fpuopcode) +static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfilename, int opcodesize, int fpuopcode) { TCHAR dir[1000]; uae_u8 *dst = NULL; @@ -2001,6 +2002,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in } } xorshiftstate += 256 * opcodesize; + if (ovrfilename) { + mns = ovrfilename; + for (int i = 0; i < _tcslen(ovrfilename); i++) { + xorshiftstate <<= 1; + xorshiftstate ^= ovrfilename[i]; + } + } int pathlen = _tcslen(path); _stprintf(dir, _T("%s%s"), path, mns); @@ -2245,6 +2253,14 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in put_word_test(opcode_memory_start, opc); + if (extra_or || extra_and) { + uae_u16 ew = get_word_test(opcode_memory_start + 2); + uae_u16 ew2 = (ew | extra_or) & ~extra_and; + if (ew2 != ew) { + put_word_test(opcode_memory_start + 2, ew2); + } + } + // loop mode if (feature_loop_mode) { // dbf dn, opcode_memory_start @@ -2445,7 +2461,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in if (regs.sr & 0x2000) prev_s_cnt++; - if (subtest_count == 353) + if (subtest_count == 23360) printf(""); execute_ins(opc, pc - 2, branch_target, dp); @@ -2660,6 +2676,9 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) int fpuopcode = -1; int sizes = -1; + extra_and = 0; + extra_or = 0; + _tcscpy(modetxt, mode); my_trim(modetxt); TCHAR *s = _tcschr(modetxt, '.'); @@ -2683,6 +2702,46 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) if (c == 'd') sizes = 5; } + + const TCHAR *ovrname = NULL; + if (!_tcsicmp(modetxt, _T("DIVUL"))) { + _tcscpy(modetxt, _T("DIVL")); + extra_and = 0x0800; + extra_and |= 0x0400; + ovrname = _T("DIVUL"); + } else if (!_tcsicmp(modetxt, _T("DIVSL"))) { + _tcscpy(modetxt, _T("DIVL")); + extra_or = 0x0800; + extra_and = 0x0400; + ovrname = _T("DIVSL"); + } else if (!_tcsicmp(modetxt, _T("DIVS")) && sizes == 0) { + _tcscpy(modetxt, _T("DIVL")); + extra_or = 0x0800; + extra_or |= 0x0400; + ovrname = _T("DIVS"); + } else if (!_tcsicmp(modetxt, _T("DIVU")) && sizes == 0) { + _tcscpy(modetxt, _T("DIVL")); + extra_and = 0x0800; + extra_or |= 0x0400; + ovrname = _T("DIVU"); + } else if (!_tcsicmp(modetxt, _T("CHK2"))) { + _tcscpy(modetxt, _T("CHK2")); + extra_or = 0x0800; + ovrname = _T("CHK2"); + } else if (!_tcsicmp(modetxt, _T("CMP2"))) { + _tcscpy(modetxt, _T("CHK2")); + extra_and = 0x0800; + ovrname = _T("CMP2"); + } else if (!_tcsicmp(modetxt, _T("MULS")) && sizes == 0) { + _tcscpy(modetxt, _T("MULL")); + extra_or = 0x0800; + ovrname = _T("MULS"); + } else if (!_tcsicmp(modetxt, _T("MULU")) && sizes == 0) { + _tcscpy(modetxt, _T("MULL")); + extra_and = 0x0800; + ovrname = _T("MULU"); + } + for (int j = 0; lookuptab[j].name; j++) { if (!_tcsicmp(modetxt, lookuptab[j].name)) { mnemo = j; @@ -2709,6 +2768,7 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) } } } + if (mnemo < 0) { wprintf(_T("Couldn't find '%s'\n"), modetxt); return; @@ -2718,16 +2778,16 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) if (mnemo >= 0 && sizes < 0) { if (fpuopcode >= 0) { for (int i = 0; i < 7; i++) { - test_mnemo(path, lookuptab[mnemo].name, i, fpuopcode); + test_mnemo(path, lookuptab[mnemo].name, ovrname, i, fpuopcode); } } else { - test_mnemo(path, lookuptab[mnemo].name, 0, -1); - test_mnemo(path, lookuptab[mnemo].name, 4, -1); - test_mnemo(path, lookuptab[mnemo].name, 6, -1); - test_mnemo(path, lookuptab[mnemo].name, -1, -1); + test_mnemo(path, lookuptab[mnemo].name, ovrname, 0, -1); + test_mnemo(path, lookuptab[mnemo].name, ovrname, 4, -1); + test_mnemo(path, lookuptab[mnemo].name, ovrname, 6, -1); + test_mnemo(path, lookuptab[mnemo].name, ovrname, -1, -1); } } else { - test_mnemo(path, lookuptab[mnemo].name, sizes, fpuopcode); + test_mnemo(path, lookuptab[mnemo].name, ovrname, sizes, fpuopcode); } } diff --git a/disasm.cpp b/disasm.cpp index b173ced6..318ca197 100644 --- a/disasm.cpp +++ b/disasm.cpp @@ -1723,6 +1723,13 @@ void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cn instrname[3] = 'S'; else instrname[3] = 'U'; + if (lookup->mnemo == i_DIVL && !(extra & 0x0400)) { + // DIVSL.L/DIVUL.L + instrname[7] = 0; + instrname[6] = instrname[5]; + instrname[5] = instrname[4]; + instrname[4] = 'L'; + } pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode); p = instrname + _tcslen(instrname); if (extra & 0x0400) diff --git a/newcpu_common.cpp b/newcpu_common.cpp index 7561d5f1..01fa5462 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -1020,43 +1020,88 @@ void setchk2undefinedflags(uae_s32 lower, uae_s32 upper, uae_s32 val, int size) #ifndef CPUEMU_68000_ONLY -#if !defined (uae_s64) -STATIC_INLINE int div_unsigned (uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem) +static void divsl_overflow(uae_u16 extra, uae_s64 a, uae_s32 divider) { - uae_u32 q = 0, cbit = 0; - int i; - - if (div <= src_hi) { - return 1; - } - 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; + if (currprefs.cpu_model >= 68040) { + SET_VFLG(1); + SET_CFLG(0); + } else { + uae_s32 a32 = (uae_s32)a; + bool neg64 = a < 0; + bool neg32 = a32 < 0; + SET_VFLG(1); + if (extra & 0x0400) { + // this is still missing condition where Z is set + // without none of input parameters being zero. + uae_u32 ahigh = a >> 32; + if (ahigh == 0) { + SET_ZFLG(1); + SET_NFLG(0); + } else if (ahigh < 0 && divider < 0 && ahigh > divider) { + SET_ZFLG(0); + SET_NFLG(0); + } else { + if (a32 == 0) { + SET_ZFLG(1); + SET_NFLG(0); + } else { + SET_ZFLG(0); + SET_NFLG(neg32 ^ neg64); + } + } + } else { + if (a32 == 0) { + SET_ZFLG(1); + SET_NFLG(0); + } else { + SET_NFLG(neg32); + SET_ZFLG(0); + } } + SET_CFLG(0); } - *quot = q; - *rem = src_hi; - return 0; } -#endif -static void divl_overflow(void) +static void divul_overflow(uae_u16 extra, uae_s64 a) { - if (currprefs.cpu_model == 68040) { + if (currprefs.cpu_model >= 68040) { SET_VFLG(1); SET_CFLG(0); } else { + uae_s32 a32 = (uae_s32)a; + bool neg32 = a32 < 0; SET_VFLG(1); - SET_NFLG(1); + SET_NFLG(neg32); + SET_ZFLG(a32 == 0); + SET_CFLG(0); + } +} + +static void divsl_divbyzero(uae_u16 extra, uae_s64 a) +{ + if (currprefs.cpu_model == 68060) { + SET_CFLG(0); + } else { + SET_NFLG(0); + SET_ZFLG(1); SET_CFLG(0); - SET_ZFLG(0); } + Exception_cpu(5); +} + +static void divul_divbyzero(uae_u16 extra, uae_s64 a) +{ + if (currprefs.cpu_model == 68060) { + SET_CFLG(0); + } else { + uae_s32 a32 = (uae_s32)a; + bool neg32 = a32 < 0; + SET_NFLG(neg32); + SET_ZFLG(a32 == 0); + SET_VFLG(1); + SET_CFLG(0); + } + Exception_cpu(5); } bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra) @@ -1065,14 +1110,7 @@ bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra) op_unimpl (opcode); return false; } - if (src == 0) { - if (currprefs.cpu_model == 68060) { - SET_CFLG(0); - } - Exception_cpu(5); - return false; - } -#if defined (uae_s64) + if (extra & 0x800) { /* signed variant */ uae_s64 a = (uae_s64)(uae_s32)m68k_dreg (regs, (extra >> 12) & 7); @@ -1083,15 +1121,20 @@ bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra) a |= (uae_s64)m68k_dreg (regs, extra & 7) << 32; } + if (src == 0) { + divsl_divbyzero(extra, a); + return false; + } + if ((uae_u64)a == 0x8000000000000000UL && src == ~0u) { - divl_overflow(); + divsl_overflow(extra, a, src); } else { rem = a % (uae_s64)(uae_s32)src; quot = a / (uae_s64)(uae_s32)src; if ((quot & UVAL64 (0xffffffff80000000)) != 0 && (quot & UVAL64 (0xffffffff80000000)) != UVAL64 (0xffffffff80000000)) { - divl_overflow(); + divsl_overflow(extra, a, src); } else { if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; SET_VFLG (0); @@ -1111,10 +1154,16 @@ bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra) a &= 0xffffffffu; a |= (uae_u64)m68k_dreg (regs, extra & 7) << 32; } + + if (src == 0) { + divul_divbyzero(extra, a); + return false; + } + rem = a % (uae_u64)src; quot = a / (uae_u64)src; if (quot > 0xffffffffu) { - divl_overflow(); + divul_overflow(extra, a); } else { SET_VFLG (0); SET_CFLG (0); @@ -1124,82 +1173,9 @@ bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra) m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)quot; } } -#else - if (extra & 0x800) { - /* signed variant */ - uae_s32 lo = (uae_s32)m68k_dreg (regs, (extra >> 12) & 7); - uae_s32 hi = lo < 0 ? -1 : 0; - uae_s32 save_high; - uae_u32 quot, rem; - uae_u32 sign; - - if (extra & 0x400) { - hi = (uae_s32)m68k_dreg (regs, extra & 7); - } - save_high = hi; - sign = (hi ^ src); - if (hi < 0) { - hi = ~hi; - lo = -lo; - if (lo == 0) hi++; - } - if ((uae_s32)src < 0) src = -src; - if (div_unsigned (hi, lo, src, ", &rem) || - (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { - divl_overflow(); - } else { - if (sign & 0x80000000) quot = -quot; - if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg (regs, extra & 7) = rem; - m68k_dreg (regs, (extra >> 12) & 7) = quot; - } - } else { - /* unsigned */ - uae_u32 lo = (uae_u32)m68k_dreg (regs, (extra >> 12) & 7); - uae_u32 hi = 0; - uae_u32 quot, rem; - - if (extra & 0x400) { - hi = (uae_u32)m68k_dreg (regs, extra & 7); - } - if (div_unsigned (hi, lo, src, ", &rem)) { - divl_overflow(); - } else { - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg (regs, extra & 7) = rem; - m68k_dreg (regs, (extra >> 12) & 7) = quot; - } - } -#endif return true; } -#if !defined (uae_s64) -STATIC_INLINE void mul_unsigned (uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) -{ - uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff); - uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff); - uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff); - uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff); - uae_u32 lo; - - lo = r0 + ((r1 << 16) & 0xffff0000ul); - if (lo < r0) r3++; - r0 = lo; - lo = r0 + ((r2 << 16) & 0xffff0000ul); - if (lo < r0) r3++; - r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff); - *dst_lo = lo; - *dst_hi = r3; -} -#endif bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) { @@ -1207,7 +1183,6 @@ bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) op_unimpl (opcode); return false; } -#if defined (uae_s64) if (extra & 0x800) { /* signed */ uae_s64 a = (uae_s64)(uae_s32)m68k_dreg (regs, (extra >> 12) & 7); @@ -1218,7 +1193,7 @@ bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) if (extra & 0x400) { // 32 * 32 = 64 // 68040 is different. - if (currprefs.cpu_model == 68040) { + if (currprefs.cpu_model >= 68040) { m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32); m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; } else { @@ -1248,7 +1223,7 @@ bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) if (extra & 0x400) { // 32 * 32 = 64 // 68040 is different. - if (currprefs.cpu_model == 68040) { + if (currprefs.cpu_model >= 68040) { m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32); m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; } else { @@ -1269,60 +1244,6 @@ bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) SET_NFLG(b < 0); } } -#else - if (extra & 0x800) { - /* signed */ - uae_s32 src1, src2; - uae_u32 dst_lo, dst_hi; - uae_u32 sign; - - src1 = (uae_s32)src; - src2 = (uae_s32)m68k_dreg (regs, (extra >> 12) & 7); - sign = (src1 ^ src2); - if (src1 < 0) src1 = -src1; - if (src2 < 0) src2 = -src2; - mul_unsigned ((uae_u32)src1, (uae_u32)src2, &dst_hi, &dst_lo); - if (sign & 0x80000000) { - dst_hi = ~dst_hi; - dst_lo = -dst_lo; - if (dst_lo == 0) dst_hi++; - } - SET_VFLG (0); - SET_CFLG (0); - if (extra & 0x400) { - m68k_dreg(regs, extra & 7) = dst_hi; - SET_ZFLG(dst_hi == 0 && dst_lo == 0); - SET_NFLG(((uae_s32)dst_hi) < 0); - } else { - if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) && ((dst_hi & 0xffffffff) != 0xffffffff || (dst_lo & 0x80000000) != 0x80000000)) { - SET_VFLG(1); - } - SET_ZFLG(dst_lo == 0); - SET_NFLG(((uae_s32)dst_lo) < 0); - } - m68k_dreg (regs, (extra >> 12) & 7) = dst_lo; - } else { - /* unsigned */ - uae_u32 dst_lo, dst_hi; - - mul_unsigned (src, (uae_u32)m68k_dreg (regs, (extra >> 12) & 7), &dst_hi, &dst_lo); - - SET_VFLG (0); - SET_CFLG (0); - if (extra & 0x400) { - m68k_dreg(regs, extra & 7) = dst_hi; - SET_ZFLG(dst_hi == 0 && dst_lo == 0); - SET_NFLG(((uae_s32)dst_hi) < 0); - } else { - if (dst_hi != 0) { - SET_VFLG(1); - } - SET_ZFLG(dst_lo == 0); - SET_NFLG(((uae_s32)dst_lo) < 0); - } - m68k_dreg (regs, (extra >> 12) & 7) = dst_lo; - } -#endif return true; }