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;
{
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)
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;
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;
}
}
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);
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
if (regs.sr & 0x2000)
prev_s_cnt++;
- if (subtest_count == 353)
+ if (subtest_count == 23360)
printf("");
execute_ins(opc, pc - 2, branch_target, dp);
int fpuopcode = -1;
int sizes = -1;
+ extra_and = 0;
+ extra_or = 0;
+
_tcscpy(modetxt, mode);
my_trim(modetxt);
TCHAR *s = _tcschr(modetxt, '.');
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;
}
}
}
+
if (mnemo < 0) {
wprintf(_T("Couldn't find '%s'\n"), modetxt);
return;
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);
}
}
#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)
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);
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);
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);
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)
{
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);
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 {
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 {
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;
}