From: Toni Wilen Date: Mon, 6 Jan 2020 12:54:02 +0000 (+0200) Subject: 68000/010 odd exception vector address error emulation and tester support. X-Git-Tag: 4400~186 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=fe93025d4d5472432dcaf2d5c0052d39a1864316;p=francis%2Fwinuae.git 68000/010 odd exception vector address error emulation and tester support. --- diff --git a/cputest.cpp b/cputest.cpp index 0027b522..399e58e2 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -67,6 +67,7 @@ static int feature_full_extension_format = 0; 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]; @@ -117,6 +118,8 @@ static int forced_immediate_mode; 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; @@ -811,7 +814,7 @@ void cpureset(void) cpu_halted = -1; } -static void doexcstack(void) +static void doexcstack2(void) { // generate exception but don't store it with test results @@ -877,6 +880,59 @@ static void doexcstack(void) 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) { @@ -1431,6 +1487,21 @@ static bool load_file(const TCHAR *path, const TCHAR *file, uae_u8 *p, int size, 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]; @@ -1485,7 +1556,16 @@ static void save_data(uae_u8 *dst, const TCHAR *dir) 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); @@ -1499,6 +1579,7 @@ static void save_data(uae_u8 *dst, const TCHAR *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++; @@ -2547,6 +2628,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) 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) @@ -3806,6 +3888,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (feature_usp == 2) { skipped = 1; } + if (feature_exception_vectors) { + skipped = 1; + } } if (cpu_stopped) { @@ -3833,10 +3918,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } // 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; } } @@ -4129,6 +4214,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } + markfile(dir); + wprintf(_T("- %d tests\n"), subtest_count); } @@ -4427,6 +4514,8 @@ int __cdecl main(int argc, char *argv[]) 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) { diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index 037dddd7..9677bb27 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -1,5 +1,5 @@ -#define DATA_VERSION 13 +#define DATA_VERSION 14 #define CT_FPREG 0 #define CT_DREG 0 diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 97ef082d..b5fc18b2 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -61,6 +61,7 @@ feature_exception3_instruction=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= @@ -85,6 +86,11 @@ feature_safe_memory_mode=R ; 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) diff --git a/cputest/main.c b/cputest/main.c index c613cd34..66af4925 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -74,6 +74,7 @@ static uae_u8 *test_data; 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; @@ -366,12 +367,18 @@ static void start_test(void) 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 { @@ -390,6 +397,9 @@ static void start_test(void) 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); @@ -2287,6 +2297,10 @@ static int test_mnemo(const char *opcode) 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); @@ -2378,6 +2392,7 @@ static int test_mnemo(const char *opcode) } } } + quit = 1; break; } if (gl(test_data) != DATA_VERSION) { @@ -2388,11 +2403,15 @@ static int test_mnemo(const char *opcode) 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; @@ -2403,7 +2422,7 @@ static int test_mnemo(const char *opcode) free(test_data); - if (errors || quit) { + if (errors || quit || last) { break; } @@ -2503,6 +2522,7 @@ int main(int argc, char *argv[]) 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; } diff --git a/gencpu.cpp b/gencpu.cpp index f786b8bb..435c1b90 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -6138,8 +6138,12 @@ static void gen_opcode (unsigned int opcode) 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" @@ -6151,6 +6155,11 @@ static void gen_opcode (unsigned int opcode) "\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"); diff --git a/newcpu.cpp b/newcpu.cpp index a3e81617..ad316f2c 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -2541,7 +2541,7 @@ static void Exception_ce000 (int nr) 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 @@ -2594,9 +2594,15 @@ kludge_me_do: // 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); @@ -2973,7 +2979,7 @@ static void Exception_normal (int nr) 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; } @@ -3029,12 +3035,17 @@ kludge_me_do: 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); } @@ -6953,6 +6964,7 @@ static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool in 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) @@ -6962,6 +6974,7 @@ static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int 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; @@ -6969,13 +6982,17 @@ void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc) } 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; @@ -6983,17 +7000,22 @@ void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int f } 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); }