static int feature_test_rounds = 2;
static int feature_flag_mode = 0;
static int feature_usp = 0;
+static int feature_exception_vectors = 0;
static TCHAR *feature_instruction_size = NULL;
static uae_u32 feature_addressing_modes[2];
static int ad8r[2], pc8r[2];
static int test_exception;
static int test_exception_extra;
static int exception_stack_frame_size;
+static uae_u8 exception_extra_frame[100];
+static int exception_extra_frame_size;
static uaecptr test_exception_addr;
static int test_exception_3_w;
static int test_exception_3_fc;
cpu_halted = -1;
}
-static void doexcstack(void)
+static void doexcstack2(void)
{
// generate exception but don't store it with test results
noaccesshistory = noac;
}
+static void doexcstack(void)
+{
+ bool changed = false;
+ doexcstack2();
+ if (cpu_lvl >= 2)
+ return;
+ if (test_exception < 4)
+ return;
+
+ int original_exception = test_exception;
+ int opcode = (opcode_memory[0] << 8) | (opcode_memory[1]);
+ if (opcode == 0x419f)
+ printf("");
+
+ // did we got bus error or address error
+ // when fetching exception vector?
+ // (bus error not yet tested)
+ if (regs.vbr & 1) {
+ test_exception = 3;
+ changed = true;
+ } else if (feature_exception_vectors & 1) {
+ test_exception = 3;
+ test_exception_addr = feature_exception_vectors;
+ changed = true;
+ }
+ if (!changed)
+ return;
+
+ // store original exception stack (which may not be complete)
+ uae_u8 *sf = test_memory + test_memory_size + EXTRA_RESERVED_SPACE - exception_stack_frame_size;
+ exception_extra_frame_size = exception_stack_frame_size;
+ memcpy(exception_extra_frame, sf, exception_extra_frame_size);
+
+ MakeSR();
+ regs.sr |= 0x2000;
+ regs.sr &= ~0x8000;
+ MakeFromSR();
+
+ int flags = 0;
+ if (cpu_lvl == 1) {
+ // IF = 1
+ flags |= 0x40000;
+ // low word of address
+ regs.irc = (uae_u16)test_exception_addr;
+ // low word of address
+ regs.read_buffer = regs.irc;
+ // vector offset (not vbr + offset)
+ regs.write_buffer = original_exception * 4;
+ }
+
+ exception3_read(regs.ir | flags, test_exception_addr, 1, 2);
+}
+
uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode)
{
if ((opcode & 0xf000) == 0xf000) {
return true;
}
+static void markfile(const TCHAR *dir)
+{
+ TCHAR path[1000];
+ if (filecount <= 1)
+ return;
+ _stprintf(path, _T("%s/%04d.dat"), dir, filecount - 1);
+ FILE *f = _tfopen(path, _T("r+b"));
+ if (f) {
+ fseek(f, -1, SEEK_END);
+ uae_u8 b = CT_END_FINISH;
+ fwrite(&b, 1, 1, f);
+ fclose(f);
+ }
+}
+
static void save_data(uae_u8 *dst, const TCHAR *dir)
{
TCHAR path[1000];
fwrite(data, 1, 4, f);
pl(data, super_stack_memory);
fwrite(data, 1, 4, f);
+ pl(data, feature_exception_vectors);
+ fwrite(data, 1, 4, f);
+ data[0] = data[1] = data[2] = data[3] = 0;
+ fwrite(data, 1, 4, f);
+ fwrite(data, 1, 4, f);
+ fwrite(data, 1, 4, f);
fwrite(inst_name, 1, sizeof(inst_name) - 1, f);
+ data[0] = CT_END_FINISH;
+ data[1] = 0;
+ fwrite(data, 1, 2, f);
fclose(f);
filecount++;
save_data(dst, dir);
fwrite(data, 1, 4, f);
fwrite(data, 1, 4, f);
*dst++ = CT_END_FINISH;
+ *dst++ = filecount;
fwrite(storage_buffer, 1, dst - storage_buffer, f);
fclose(f);
filecount++;
read_buffer_prev = regs.ir;
regs.read_buffer = regs.irc;
regs.write_buffer = 0xf00d;
+ exception_extra_frame_size = 0;
int cnt = (feature_loop_mode + 1) * 2;
if (multi_mode)
if (feature_usp == 2) {
skipped = 1;
}
+ if (feature_exception_vectors) {
+ skipped = 1;
+ }
}
if (cpu_stopped) {
}
// got exception 3 but didn't want them?
if (test_exception == 3) {
- if ((feature_usp != 1 && feature_usp != 2) && !feature_exception3_data && !(test_exception_3_fc & 2)) {
+ if ((feature_usp != 1 && feature_usp != 2) && !feature_exception3_data && !(test_exception_3_fc & 2) && !feature_exception_vectors) {
skipped = 1;
}
- if ((feature_usp != 1 && feature_usp != 2) && !feature_exception3_instruction && (test_exception_3_fc & 2)) {
+ if ((feature_usp != 1 && feature_usp != 2) && !feature_exception3_instruction && (test_exception_3_fc & 2) && !feature_exception_vectors) {
skipped = 1;
}
}
}
}
+ markfile(dir);
+
wprintf(_T("- %d tests\n"), subtest_count);
}
ini_getval(ini, INISECTION, _T("feature_flags_mode"), &feature_flag_mode);
feature_usp = 0;
ini_getval(ini, INISECTION, _T("feature_usp"), &feature_usp);
+ feature_exception_vectors = 0;
+ ini_getval(ini, INISECTION, _T("feature_exception_vectors"), &feature_exception_vectors);
feature_full_extension_format = 0;
if (currprefs.cpu_model >= 68020) {
-#define DATA_VERSION 13
+#define DATA_VERSION 14
#define CT_FPREG 0
#define CT_DREG 0
; Multiple values supported (max 8), separated by commas.
; Useful for bus error and address error testing
; Disables above exception3 modes.
+; If odd value and 68000/010: skip all tests that don't cause address error
; Supports 68000 addressing modes only.
; If instruction only has destination EA, source Areg, Dreg or immediate is generated.
feature_target_src_ea=
; 3 = take stack from feature_target_opcode_offset
feature_usp=0
+; exception vector bus error/address error test
+; 0: normal
+; non-zero: replace exception vectors with this value (except vectors 2 and 3)
+;feature_exception_vectors=0x0007321
+
; CCR/FPU status flags mode
; 0 = all combinations (32 CCR loops, 256 FPU loops)
; 1 = all zeros and all ones only (2 CCR loops, 32 FPU loops)
static uae_u8 *safe_memory_start, *safe_memory_end;
static int safe_memory_mode;
static uae_u32 user_stack_memory, super_stack_memory;
+static uae_u32 exception_vectors;
static int test_data_size;
static uae_u32 oldvbr;
static uae_u8 *vbr_zero = 0;
uae_u32 *p = (uae_u32 *)vbr_zero;
for (int i = 2; i < 12; i++) {
p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2);
+ if (exception_vectors && i >= 4) {
+ p[i] = exception_vectors;
+ }
if (i < 12 + 2) {
error_vectors[i - 2] = p[i];
}
}
for (int i = 32; i < 48; i++) {
p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2);
+ if (exception_vectors) {
+ p[i] = exception_vectors;
+ }
}
exceptiontableinuse = (uae_u32)&exceptiontable000;
} else {
if (i >= 2 && i < 12) {
error_vectors[i - 2] = vbr[i];
}
+ if (exception_vectors && i >= 4) {
+ vbr[i] = exception_vectors;
+ }
}
}
setcpu(cpu_lvl, cpustatearraynew, cpustatearraystore);
safe_memory_end = (uae_u8*)read_u32(headerfile, &headoffset);
user_stack_memory = read_u32(headerfile, &headoffset);
super_stack_memory = read_u32(headerfile, &headoffset);
+ exception_vectors = read_u32(headerfile, &headoffset);
+ read_u32(headerfile, &headoffset);
+ read_u32(headerfile, &headoffset);
+ read_u32(headerfile, &headoffset);
memcpy(inst_name, headerfile + headoffset, sizeof(inst_name) - 1);
inst_name[sizeof(inst_name) - 1] = 0;
free(headerfile);
}
}
}
+ quit = 1;
break;
}
if (gl(test_data) != DATA_VERSION) {
printf("Test data file header mismatch (old test data file?)\n");
break;
}
- if (test_data[test_data_size - 1] != CT_END_FINISH) {
+ if (test_data[test_data_size - 2] != CT_END_FINISH) {
printf("Invalid test data file (footer)\n");
free(test_data);
exit(0);
}
+
+ // last file?
+ int last = test_data[test_data_size - 1] == CT_END_FINISH;
+
test_data_size -= 16;
if (test_data_size <= 0)
break;
free(test_data);
- if (errors || quit) {
+ if (errors || quit || last) {
break;
}
printf("ccrmask = ignore CCR bits that are not set.\n");
printf("nodisasm = do not disassemble failed test.\n");
printf("basicexc = do only basic checks when exception is 2 or 3.\n");
+ printf("askifmissing = ask for new path if dat file is missing.\n");
return 0;
}
break;
case i_TRAPV:
sync_m68k_pc();
+ // TRAPV is really weird
// If V is set but prefetch causes bus error: S is set.
// for some reason T is also cleared!
+ if (using_prefetch) {
+ printf("\tuae_u16 opcode_v = opcode;\n");
+ }
fill_prefetch_next_after(1,
"\t\tif (GET_VFLG()) {\n"
"\t\t\tMakeSR();\n"
"\t\t\tif(regs.t1) opcode |= 0x10000;\n"
"\t\t}\n");
printf("\tif (GET_VFLG()) {\n");
+ if (using_prefetch) {
+ // If exception vector is odd,
+ // stacked opcode is TRAPV
+ printf("\t\tregs.ir = opcode_v;\n");
+ }
printf("\t\tException_cpu(7);\n");
write_return_cycles("\t\t", 0);
printf("\t}\n");
exception_in_exception = -1;
frame_id = 8;
x_put_word(m68k_areg(regs, 7) + 0, ssw); // ssw
- x_put_long(m68k_areg(regs, 7) + 2, last_addr_for_exception_3); // fault addr
+ x_put_long(m68k_areg(regs, 7) + 2, last_fault_for_exception_3); // fault addr
x_put_word(m68k_areg(regs, 7) + 6, 0); // unused
x_put_word(m68k_areg(regs, 7) + 8, regs.write_buffer); // data output buffer
x_put_word(m68k_areg(regs, 7) + 10, 0); // unused
// if exception vector is odd:
// opcode is last opcode executed, address is address of exception vector
// pc is last prefetch address
- exception3b(regs.opcode, newpc, false, true, regs.vbr + 4 * vector_nr);
+ regs.t1 = 0;
+ MakeSR();
+ m68k_setpc(regs.vbr + 4 * vector_nr);
+ exception3_read(regs.ir | 0x40000, newpc, 1, 2);
} else if (currprefs.cpu_model == 68010) {
- regs.write_buffer = regs.vbr + 4 * vector_nr;
+ // offset, not vbr + offset
+ regs.t1 = 0;
+ MakeSR();
+ regs.write_buffer = 4 * vector_nr;
regs.read_buffer = newpc;
regs.irc = regs.read_buffer;
exception3b(regs.opcode, newpc, false, true, newpc);
ssw |= last_writeaccess_for_exception_3 ? 0x0000 : 0x0100; // RW
if (last_op_for_exception_3 & 0x20000)
ssw &= 0x00ff;
- regs.mmu_fault_addr = last_addr_for_exception_3;
+ regs.mmu_fault_addr = last_fault_for_exception_3;
Exception_build_stack_frame(oldpc, currpc, ssw, nr, 0x08);
used_exception_build_stack_frame = true;
}
return;
}
if (currprefs.cpu_model == 68000) {
- exception3b(regs.opcode, newpc, false, true, regs.vbr + 4 * vector_nr);
+ regs.t1 = 0;
+ MakeSR();
+ m68k_setpc(regs.vbr + 4 * vector_nr);
+ exception3_read(regs.ir | 0x40000, newpc, 1, 2);
} else if (currprefs.cpu_model == 68010) {
- regs.write_buffer = regs.vbr + 4 * vector_nr;
+ regs.t1 = 0;
+ MakeSR();
+ regs.write_buffer = 4 * vector_nr;
regs.read_buffer = newpc;
regs.irc = regs.read_buffer;
- exception3b(regs.opcode, newpc, false, true, newpc);
+ exception3b(regs.ir, newpc, false, true, newpc);
} else {
exception3_notinstruction(regs.ir, newpc);
}
void exception3_notinstruction(uae_u32 opcode, uaecptr addr)
{
+ last_di_for_exception_3 = 1;
exception3f (opcode, addr, true, false, true, 0xffffffff, 1, false, -1);
}
static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc)
void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc)
{
bool ni = false;
+ bool ia = false;
if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
if (generates_group1_exception(regs.ir) && !(opcode & 0x20000)) {
ni = true;
}
if (opcode & 0x10000)
ni = true;
+ if (opcode & 0x40000)
+ ia = true;
opcode = regs.ir;
}
- exception3f (opcode, addr, false, 0, ni, 0xffffffff, size, false, fc);
+ last_di_for_exception_3 = 1;
+ exception3f (opcode, addr, false, ia, ni, 0xffffffff, size, false, fc);
}
void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc)
{
bool ni = false;
+ bool ia = false;
if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
if (generates_group1_exception(regs.ir) && !(opcode & 0x20000)) {
ni = true;
}
if (opcode & 0x10000)
ni = true;
+ if (opcode & 0x40000)
+ ia = true;
opcode = regs.ir;
}
- exception3f (opcode, addr, true, 0, ni, 0xffffffff, size, false, fc);
+ last_di_for_exception_3 = 1;
+ exception3f (opcode, addr, true, ia, ni, 0xffffffff, size, false, fc);
regs.write_buffer = val;
}
-void exception3i (uae_u32 opcode, uaecptr addr)
+void exception3i(uae_u32 opcode, uaecptr addr)
{
+ last_di_for_exception_3 = 0;
exception3f (opcode, addr, 0, 1, false, 0xffffffff, 1, true, -1);
}
-void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
+void exception3b(uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
{
+ last_di_for_exception_3 = 0;
exception3f (opcode, addr, w, i, false, pc, 1, true, -1);
}