static uae_u8 imm8_cnt;
static uae_u16 imm16_cnt;
static uae_u32 imm32_cnt;
+static uae_u32 immabsl_cnt;
static uae_u32 addressing_mask;
static int opcodecnt;
static int cpu_stopped;
static time_t starttime;
static int filecount;
static uae_u16 sr_undefined_mask;
+static int low_memory_accessed;
+static int high_memory_accessed;
+static int test_memory_accessed;
struct uae_prefs currprefs;
goto oob;
if (w && lmem_rom)
goto oob;
+ low_memory_accessed = w ? -1 : 1;
return 1;
}
if (addr >= HIGH_MEMORY_START && addr < HIGH_MEMORY_START + 0x8000) {
goto oob;
if (w && hmem_rom)
goto oob;
+ high_memory_accessed = w ? -1 : 1;
return 1;
}
if (addr >= test_memory_end && addr + size < test_memory_end + EXTRA_RESERVED_SPACE) {
if (addr >= opcode_memory_start && addr + size < opcode_memory_start + OPCODE_AREA)
goto oob;
}
+ test_memory_accessed = w ? -1 : 1;
return 1;
}
oob:
} else if (cpu_lvl == 2) {
if (test_exception == 3) {
uae_u16 ssw = (sv ? 4 : 0) | test_exception_3_fc;
- ssw |= test_exception_3_w ? 0 : 0x40;
ssw |= 0x20;
regs.mmu_fault_addr = test_exception_addr;
- Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, 3, 0x0a);
+ Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, 3, 0x0b);
} else {
Exception_build_stack_frame_common(regs.instruction_pc, regs.pc, 0, test_exception);
}
static uaecptr putfpuimm(uaecptr pc, int opcodesize, int *isconstant)
{
- // TODO: generate FPU immediates
+ // TODO: generate sane FPU immediates
switch (opcodesize)
{
case 0: // L
pc += 2;
break;
case 1: // S
- put_long(pc, 0);
+ put_long(pc, rand32());
pc += 4;
break;
case 2: // X
- put_long(pc, 0);
- put_long(pc + 4, 0);
- put_long(pc + 8, 0);
+ put_long(pc, rand32());
+ put_long(pc + 4, rand32());
+ put_long(pc + 8, rand32());
pc += 12;
break;
case 3: // P
- put_long(pc, 0);
- put_long(pc + 4, 0);
- put_long(pc + 8, 0);
+ put_long(pc, rand32());
+ put_long(pc + 4, rand32());
+ put_long(pc + 8, rand32());
pc += 12;
break;
case 5: // D
- put_long(pc, 0);
- put_long(pc + 4, 0);
+ put_long(pc, rand32());
+ put_long(pc + 4, rand32());
pc += 8;
break;
}
pc += 2;
break;
case absl:
- put_long_test(pc, rand32());
- *isconstant = 32;
- pc += 4;
+ {
+ uae_u32 v = rand32();
+ if ((immabsl_cnt & 7) == 0) {
+ v &= 0x0000ffff;
+ } else if ((immabsl_cnt & 7) >= 4) {
+ int offset = 0;
+ for (;;) {
+ offset = (uae_s16)rand16();
+ if (offset < -OPCODE_AREA || offset > OPCODE_AREA)
+ break;
+ }
+ v = opcode_memory_start + offset;
+ }
+ immabsl_cnt++;
+ put_long_test(pc, v);
+ *isconstant = 32;
+ pc += 4;
+ }
break;
case imm:
if (fpuopcode >= 0 && opcodesize < 8) {
{
// long immediate
uae_u32 v = rand32();
- if ((imm32_cnt & 7) == 0)
+ if ((imm32_cnt & 7) == 0) {
v &= 0x0000ffff;
+ }
imm32_cnt++;
put_long_test(pc, v);
if (imm32_cnt < 256)
imm_special++;
return 2;
}
+ if (dp->mnemo == i_MOVE16) {
+ if (opcode & 0x20) {
+ uae_u16 v = 0;
+ v |= imm_special << 12;
+ put_word_test(pc, v);
+ imm_special++;
+ return 2;
+ }
+ }
return 0;
}
if (extra != extra2) {
put_word_test(opcode_memory_start + 4, extra);
}
-
}
if (dp->mnemo == i_CHK2) {
uae_u16 extra = get_word_test(opcode_memory_start + 2);
if (extra != extra2) {
put_word_test(opcode_memory_start + 2, extra);
}
-
}
}
addr += 2;
offset += 2;
*isconstant = imm_special >= (1 << (0 + 5)) * 4 ? 0 : -1;
- } else if (dp->mnemo == i_RTD) {
- // RTD
- v = imm_special >> 2;
- uae_u16 sr = v & 31;
- sr |= (v >> 5) << 12;
- put_word_test(addr + 4, sr);
- *isconstant = imm_special >= (1 << (4 + 5)) * 4 ? 0 : -1;
} else if (dp->mnemo == i_RTE) {
// RTE
if (currprefs.cpu_model == 68000) {
return offset;
}
-static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc)
+static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct instr *dp)
{
uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
- if (opc == 0x61ff
- && opw1 == 0x0000
- && opw2 == 0x9908
+ if (opc == 0xf601
+// && opw1 == 0x0000
+// && opw2 == 0x9908
)
printf("");
if (regs.sr & 0x2000)
MakeFromSR();
+ low_memory_accessed = 0;
+ high_memory_accessed = 0;
+ test_memory_accessed = 0;
testing_active = 1;
int cnt = feature_loop_mode * 2;
}
}
+ if (dp->mnemo == i_TAS && low_memory_accessed) {
+ test_exception = -1;
+ break;
+ }
+
if (regs.pc == endpc || regs.pc == targetpc)
break;
// FSLW or PC of faulted instruction
p = store_rel(p, 0, opcode_memory_start, gl(sf + 12), 1);
break;
- case 0x0a: // 68020/030 address error. Only check SSW.
- // SSW
- p = store_reg(p, 0, 0, gw(sf + 0x0a), sz_word);
- exception_stack_frame_size = 0x0c;
- sf[8] = sf[9] = 0;
- last_exception[8] = last_exception[9] = 0;
+ case 0x0a: // 68020/030 address error.
+ case 0x0b: // Don't save anything extra, too many undefined fields and bits..
+ exception_stack_frame_size = 0x08;
break;
default:
wprintf(_T("Unknown frame %04x!\n"), frame);
return ccrignoremask;
}
+static int isfpp(int mnemo)
+{
+ switch (mnemo)
+ {
+ case i_FPP:
+ case i_FBcc:
+ case i_FDBcc:
+ case i_FTRAPcc:
+ case i_FScc:
+ case i_FRESTORE:
+ case i_FSAVE:
+ return 1;
+ }
+ return 0;
+}
+
static const TCHAR *sizes[] = { _T("B"), _T("W"), _T("L") };
opcodecnt++;
if (isunsupported(dp))
return;
- if ((opcode & 0xf000) == 0xf000 && !currprefs.fpu_model)
+ if (isfpp(lookup->mnemo) && !currprefs.fpu_model)
return;
- fpumode = currprefs.fpu_model && (opcode & 0xf000) == 0xf000;
+ fpumode = currprefs.fpu_model && isfpp(lookup->mnemo);
}
if (!opcodecnt)
imm8_cnt = 0;
imm16_cnt = 0;
imm32_cnt = 0;
+ immabsl_cnt = 0;
imm_special = 0;
// retry few times if out of bounds access
out_of_test_space = 0;
ahcnt = 0;
- if (opc == 0xf228)
+ if (opc == 0xf620)
printf("");
if (subtest_count == 1537)
printf("");
if (subtest_count == 353)
printf("");
- execute_ins(opc, pc - 2, branch_target);
+ execute_ins(opc, pc - 2, branch_target, dp);
if (regs.s)
s_cnt++;
currprefs.cpu_model = 68000;
ini_getval(ini, INISECTION, _T("cpu"), &currprefs.cpu_model);
- if (currprefs.cpu_model != 68000 && currprefs.cpu_model != 68010 && currprefs.cpu_model != 68020) {
+ if (currprefs.cpu_model != 68000 && currprefs.cpu_model != 68010 && currprefs.cpu_model != 68020 && currprefs.cpu_model != 68040) {
wprintf(_T("Unsupported CPU model.\n"));
return 0;
}
addressing_mask = 0x00ffffff;
v = 24;
ini_getval(ini, INISECTION, _T("cpu_address_space"), &v);
- if (v == 32) {
+ if (v == 32 || currprefs.cpu_model >= 68030) {
currprefs.address_space_24 = 0;
addressing_mask = 0xffffffff;
}
currprefs.fpu_mode = 1;
ini_getval(ini, INISECTION, _T("fpu"), &currprefs.fpu_model);
if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
- wprintf(_T("FPU requires 68020 CPU.\n"));
+ wprintf(_T("FPU requires 68020 or 68040 CPU.\n"));
return 0;
}
if (currprefs.fpu_model != 0 && currprefs.fpu_model != 68881 && currprefs.fpu_model != 68882 && currprefs.fpu_model != 68040 && currprefs.fpu_model != 68060) {
xorshiftstate = 1;
+ feature_test_rounds = 2;
+ ini_getval(ini, INISECTION, _T("test_rounds"), &feature_test_rounds);
+
v = 0;
ini_getval(ini, INISECTION, _T("test_memory_start"), &v);
if (!v) {
} else if (currprefs.cpu_model == 68020) {
tbl = op_smalltbl_92_test_ff;
cpu_lvl = 2;
+ } else if (currprefs.cpu_model == 68040) {
+ tbl = op_smalltbl_94_test_ff;
+ cpu_lvl = 4;
} else {
wprintf(_T("Unsupported CPU model.\n"));
abort();
continue;
}
- if (!currprefs.fpu_model && (opcode & 0xf000) == 0xf000) {
- continue;
+ if (!currprefs.fpu_model) {
+ int fppskip = isfpp(table->mnemo);
+ if (fppskip)
+ continue;
}
if (table->handler != -1) {
move.l (sp)+,a6
rts
- | return CPU model (68000=0, 68010=1, 68020=2)
+ | return CPU model (68000=0, 68010=1, 68020=2, 68030=3, 68040=4, 68060=5)
_get_cpu_model:
move.l 4.w,a0
- moveq #0,d0
move.w 0x128(a0),d1
- and.w #3,d1
- beq.s .cpudone
- moveq #2,d0
- btst #1,d1
+ moveq #5,d0
+ tst.b d1
+ bmi.s .cpudone2
+ moveq #3,d0
+.cpucheck:
+ btst d0,d1
bne.s .cpudone
- moveq #1,d0
+ dbf d0,.cpucheck
.cpudone:
+ addq.l #1,d0
+.cpudone2:
rts
.globl _setvbr
.globl _setcpu
.globl _flushcache
+ .globl _msp_address1
+ .globl _msp_address2
+ .globl _msp_address3
+ .globl _msp_address4
| must match main.c
S_DREG = 0
bcs.s .scend1
movec cacr,d0
move.l d0,(a0)+
+ moveq #0,d0
+ cmp.w #4,d1
+ bcc.s .scend1b
movec caar,d0
+.scend1b:
move.l d0,(a0)+
+ moveq #0,d0
+ cmp.w #5,d1
+ bcc.s .scend1c
movec msp,d0
+.scend1c:
move.l d0,(a0)+
.scend1:
move.l a1,d0
move.l (a1)+,d0
movec d0,cacr
move.l (a1)+,d0
+ cmp.w #4,d1
+ bcc.s .scend2b
movec d0,caar
+.scend2b:
move.l (a1)+,d0
+ cmp.w #5,d1
+ bcc.s .scend2
move.c d0,msp
.scend2:
rts
_flushcache:
+ move.l 4(sp),d1 | cpu_lvl
+ cmp.w #4,d1
+ bcc.s .fc040
movec cacr,d0
bset #3,d0
movec d0,cacr
rts
+.fc040:
+ .arch 68040
+ cpusha bc
+ .arch 68020
+ rts
| set and return old VBR
_setvbr:
movem.l (a0),d0-d7/a0-a6
rte
- | 68020 test entrypoint
+ | 68020+ test entrypoint
_execute_test020:
movem.l d1-d7/a0-a6,-(sp)
move.l 14*4+4(sp),a0 | register struct
move.w S_SR+2(a0),-(sp)
move.l S_AREG+7*4(a0),a1
move.l a1,USP
+
move.l S_MSP(a0),a1
+_msp_address1:
movec a1,MSP
+
movem.l (a0),d0-d7/a0-a6
rte
move.w S_SR+2(a0),-(sp)
move.l S_AREG+7*4(a0),a1
move.l a1,USP
+
move.l S_MSP(a0),a1
+_msp_address2:
movec a1,MSP
+
fmovem.x S_FPU(a0),fp0-fp7
lea S_FPIAR(a0),a1
fmove.l (a1)+,fpiar
lsr.w #2,d0
move.w d0,S_EXC+2(a0)
+_msp_address3:
movec MSP,a1
move.l a1,S_MSP(a0)
+
move.l USP,a1
move.l a1,S_AREG+7*4(a0)
lsr.w #2,d0
move.w d0,S_EXC+2(a0)
+_msp_address4:
movec MSP,a1
move.l a1,S_MSP(a0)
+
move.l USP,a1
move.l a1,S_AREG+7*4(a0)
[cputest]
-; CPU model (68000, 68020).
+; CPU model (68000, 68020 or 68040).
; Always select 68020 when testing FPU instructions, even if test hardware CPU is 68040 or 68060.
cpu=68020
; main test memory start and size (real hardware must have RAM in this address space)
test_memory_start=0x780000
+;test_memory_start=0x68800000
test_memory_size=0x080000
+; number of test rounds (registers are re-randomized after each round)
+test_rounds=2
+
; test word or long odd data access address errors (68000/010 only)
; 0 = do not generate address errors
; 1 = include address errors
; test branches to odd addresses
; same options as above
-feature_exception3_instruction=0
+feature_exception3_instruction=1
; SR extra mask.
; 0x8000 = T1
; mnemonics separated by comma or all/fall.
; all = generate all CPU tests. tst = generate tst.b, tst.w and tst.l. tst.l = generate only tst.l
; fall = generate all FPU tests.
-mode=chk2.b
+mode=all
static void setcpu(uae_u32 v, uae_u32 *s, uae_u32 *d)
{
}
-static void flushcache(void)
+static void flushcache(uae_u32 v)
{
}
#else
extern uae_u32 setvbr(uae_u32);
extern uae_u32 get_cpu_model(void);
extern void setcpu(uae_u32, uae_u32*, uae_u32*);
-extern void flushcache(void);
+extern void flushcache(uae_u32);
#endif
exclen = 16;
break;
case 0x0a:
- v = 0;
- p = restore_value(p, &v, &size);
- pw(exc + 0x0a, v);
- exclen = 0x0c;
+ case 0x0b:
+ exclen = 8;
break;
default:
end_test();
int fpumode = fpu_model && (opcode_memory[0] & 0xf0) == 0xf0;
if (cpu_lvl >= 2)
- flushcache();
+ flushcache(cpu_lvl);
uae_u32 pc = opcode_memory_addr;
char fname[256], tfname[256];
int filecnt = 1;
uae_u32 starttimeid;
+ int lvl;
errors = 0;
quit = 0;
fread(data, 1, 4, f);
opcode_memory_addr = gl(data) + test_memory_addr;
fread(data, 1, 4, f);
- cpu_lvl = gl(data) >> 16;
+ lvl = gl(data) >> 16;
sr_undefined_mask = gl(data);
fread(data, 1, 4, f);
fpu_model = gl(data);
fread(inst_name, 1, sizeof(inst_name) - 1, f);
inst_name[sizeof(inst_name) - 1] = 0;
+ int lvl2 = cpu_lvl;
+ if (lvl2 == 5 && lvl2 != lvl)
+ lvl2 = 4;
+
+ if (lvl != lvl2) {
+ printf("Mismatched CPU model: %lu <> %lu\n", 68000 + 10 * cpu_lvl, 68000 + lvl * 10);
+ exit(0);
+ }
+
if (!check_undefined_sr) {
sr_undefined_mask = ~sr_undefined_mask;
} else {
#endif
+ int lvl = cpu_lvl;
+ if (lvl == 3) {
+ lvl = 2;
+ } else if (lvl == 5) {
+ lvl = 4;
+#ifdef M68K
+ // Overwrite MOVEC to/from MSP
+ // with NOP if 68060
+ extern void *msp_address1;
+ extern void *msp_address2;
+ extern void *msp_address3;
+ extern void *msp_address4;
+ *((uae_u32*)&msp_address1) = 0x4e714e71;
+ *((uae_u32*)&msp_address2) = 0x4e714e71;
+ *((uae_u32*)&msp_address3) = 0x4e714e71;
+ *((uae_u32*)&msp_address4) = 0x4e714e71;
+#endif
+ }
+
if (argc < 2) {
printf("cputest <all/mnemonic> (<start mnemonic>) (continue)\n");
printf("mnemonic = test single mnemonic\n");
return 0;
}
- sprintf(path + strlen(path), "%lu/", 68000 + cpu_lvl * 10);
+ sprintf(path + strlen(path), "%lu/", 68000 + lvl * 10);
strcpy(opcode, argv[1]);
{
}
+void flush_cpu_caches_040(uae_u16 opcode)
+{
+}
+
void mmu_tt_modified(void)
{
}
return 0;
}
+void mmu_op(uae_u32 opcode, uae_u32 extra)
+{
+}
+
uae_u16 mmu030_state[3];
int mmu030_opcode;
int mmu030_idx;
_stprintf(p, _T("(A%d)+,(A%d)+"), opcode & 7, (extra >> 12) & 7);
pc += 2;
} else {
- uae_u32 addr = get_long_debug(pc + 2);
+ uae_u32 addr = get_long_debug(pc);
int ay = opcode & 7;
pc += 4;
switch ((opcode >> 3) & 3)
}
} else if (g_instr->mnemo == i_MVSR2) {
// If MOVE from SR generates address error exception,
- // RW field is set to Read!
+ // Change it to read because it does dummy read first.
exp3rw = 0;
}
fill_prefetch_next ();
addcycles000 (2);
} else {
- // write to memory, dummy write to same address, X-flag seems to be always set
+ // read first and ignore result
if (cpu_level <= 1 && curi->size == sz_word) {
- printf ("\t%s (srca, regs.sr | 0x0010);\n", dstw);
+ printf ("\t%s (srca);\n", srcw);
count_write++;
}
fill_prefetch_next ();
start_brace ();
printf("\tuaecptr oldpc = %s;\n", getpc);
printf("\tuaecptr nextpc = oldpc + %d;\n", m68k_pc_offset);
- if (using_exception_3) {
+ if (using_exception_3 && cpu_level <= 1) {
printf("\tif (srca & 1) {\n");
printf("\t\texception3i (opcode, srca);\n");
printf("\t\tgoto %s;\n", endlabelstr);
printf("\t\texception3_write(opcode, m68k_areg(regs, 7), 1);\n");
printf("\t\tgoto %s;\n", endlabelstr);
printf("\t}\n");
+ need_endlabel = 1;
}
setpc ("srca");
+ if (using_exception_3 && cpu_level >= 2) {
+ printf("\tif (%s & 1) {\n", getpc);
+ printf("\t\texception3i (opcode, %s);\n", getpc);
+ printf("\t\tgoto %s;\n", endlabelstr);
+ printf("\t}\n");
+ need_endlabel = 1;
+ }
clear_m68k_offset();
fill_prefetch_1 (0);
if (using_ce || using_prefetch) {
printf("\t\texception3b(opcode, m68k_areg(regs, 7), true, false, %s + 2);\n", getpc);
printf("\t\tgoto %s;\n", endlabelstr);
printf("\t}\n");
- } else {
+ } else if (0) {
printf("\tif (src & 1) {\n");
printf("\t\texception3b(opcode, %s + s, 0, 1, %s + s);\n", getpc, getpc);
printf("\t\tgoto %s;\n", endlabelstr);
addcycles000 (2);
printf("\tuaecptr oldpc = %s;\n", getpc);
printf("\tuaecptr nextpc = oldpc + %d;\n", m68k_pc_offset);
+ if (using_exception_3 && cpu_level >= 2) {
+ printf("\tif (s & 1) {\n");
+ printf("\t\tm68k_areg(regs, 7) -= 4;\n");
+ printf("\t\texception3b(opcode, %s + s, 0, 1, %s + s);\n", getpc, getpc);
+ printf("\t\tgoto %s;\n", endlabelstr);
+ printf("\t}\n");
+ need_endlabel = 1;
+ }
if (using_indirect > 0 && !using_ce020 && !using_prefetch_020 && !using_ce && !using_test) {
printf("\tm68k_do_bsri_jit (nextpc, s);\n");
} else if (using_mmu) {
printf("\t\texception3b(opcode, %s, 0, 1, %s);\n", getpc, getpc);
printf("\t\tgoto %s;\n", endlabelstr);
printf("\t}\n");
+ need_endlabel = 1;
}
if (using_debugmem) {
printf("\tif (debugmem_trace)\n");
printf ("\t}}\n");
pop_braces (old_brace_level);
printf ("\tif (! GET_ZFLG ()) {\n");
- printf ("\tm68k_dreg (regs, (extra >> 0) & 7) = (m68k_dreg (regs, (extra >> 6) & 7) & ~0xffff) | (dst2 & 0xffff);\n");
- printf ("\tm68k_dreg (regs, (extra >> 16) & 7) = (m68k_dreg (regs, (extra >> 22) & 7) & ~0xffff) | (dst1 & 0xffff);\n");
+ printf ("\tm68k_dreg (regs, (extra >> 0) & 7) = (m68k_dreg (regs, (extra >> 0) & 7) & ~0xffff) | (dst2 & 0xffff);\n");
+ printf ("\tm68k_dreg (regs, (extra >> 16) & 7) = (m68k_dreg (regs, (extra >> 16) & 7) & ~0xffff) | (dst1 & 0xffff);\n");
printf ("\t}\n");
} else {
int old_brace_level = n_braces;
cpu_level = 2;
using_prefetch = 0;
using_simple_cycles = 0;
+ } else if (mode == 4) {
+ cpu_level = 4;
+ using_prefetch = 0;
+ using_simple_cycles = 0;
}
-
read_counts();
for (rp = 0; rp < nr_cpuop_funcs; rp++)
opcode_next_clev[rp] = cpu_level;
generate_cpu_test(0);
generate_cpu_test(1);
generate_cpu_test(2);
+ generate_cpu_test(4);
#else
extern const struct cputbl op_smalltbl_90_test_ff[];
extern const struct cputbl op_smalltbl_91_test_ff[];
extern const struct cputbl op_smalltbl_92_test_ff[];
+extern const struct cputbl op_smalltbl_94_test_ff[];
extern struct flag_struct regflags;
regs.mmu_fault_addr = last_fault_for_exception_3;
mmu030_state[0] = mmu030_state[1] = 0;
mmu030_data_buffer_out = 0;
- Exception_build_stack_frame (last_fault_for_exception_3, currpc, MMU030_SSW_RW | MMU030_SSW_SIZE_W | (regs.s ? 6 : 2), nr, 0xA);
+ Exception_build_stack_frame (last_fault_for_exception_3, currpc, MMU030_SSW_RW | MMU030_SSW_SIZE_W | (regs.s ? 6 : 2), nr, 0xB);
} else {
Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
}
}
} else if (currprefs.cpu_model >= 68020) {
// 68020/030 odd PC address error (partially implemented only)
+ // annoyingly this generates frame B, not A.
uae_u16 ssw = (sv ? 4 : 0) | last_fc_for_exception_3;
- ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40;
- ssw |= 0x20;
+ ssw |= MMU030_SSW_RW | MMU030_SSW_SIZE_W;
regs.mmu_fault_addr = last_fault_for_exception_3;
- Exception_build_stack_frame(oldpc, currpc, ssw, nr, 0x0a);
+ mmu030_state[0] = mmu030_state[1] = 0;
+ mmu030_data_buffer_out = 0;
+ Exception_build_stack_frame(last_fault_for_exception_3, currpc, ssw, nr, 0x0b);
used_exception_build_stack_frame = true;
} else {
// 68010 address error (partially implemented only)