]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
More undefined flags emulated. CPU tester MULL.L->MULU.L/MULS.L, DIVL.L->DIVS.L/DIVU...
authorToni Wilen <twilen@winuae.net>
Wed, 4 Sep 2019 18:53:27 +0000 (21:53 +0300)
committerToni Wilen <twilen@winuae.net>
Wed, 4 Sep 2019 18:53:27 +0000 (21:53 +0300)
cputest.cpp
disasm.cpp
newcpu_common.cpp

index 0bbbf09ff1968d478b554c8b25edf42c640df3b4..acfbdf84535942c3aeb90ce6ecbc0a37f45d9d40 100644 (file)
@@ -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 == 0x4c4
-               && 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);
        }
 }
 
index b173ced6185dd6a685bd0f5e523ca43122c54109..318ca19726dde94601aee84d0a6944444fd12ed4 100644 (file)
@@ -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)
index 7561d5f15ce91088aead3ed9a1ab94c5df73daa4..01fa5462a60746d5cd90f3f2583d3bd4ccc903a2 100644 (file)
@@ -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, &quot, &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, &quot, &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;
 }