From 00398faea71e3adb1fee23987e32271868fcbda7 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Fri, 27 Dec 2019 22:49:20 +0200 Subject: [PATCH] Stack read/write bus error support. --- cputest.cpp | 93 ++++++++++++++++++++++++++++++++---------- cputest/cputestgen.ini | 7 ++-- cputest/main.c | 10 ++++- gencpu.cpp | 43 ++++++++++++++----- 4 files changed, 116 insertions(+), 37 deletions(-) diff --git a/cputest.cpp b/cputest.cpp index d65603b8..bf13c8f1 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -66,7 +66,7 @@ static int feature_loop_mode_register = -1; static int feature_full_extension_format = 0; static int feature_test_rounds = 2; static int feature_flag_mode = 0; -static int feature_odd_usp = 0; +static int feature_usp = 0; static TCHAR *feature_instruction_size = NULL; static uae_u32 feature_addressing_modes[2]; static int ad8r[2], pc8r[2]; @@ -299,6 +299,10 @@ static void check_bus_error(uaecptr addr, int write, int fc) cpu_bus_error |= 2; cpu_bus_error_fake |= 2; } + if (!write && (fc & 2) && feature_usp == 3) { + out_of_test_space = true; + out_of_test_space_addr = addr; + } } } @@ -2353,7 +2357,8 @@ static uaecptr handle_specials_extra(uae_u16 opcode, uaecptr pc, struct instr *d static uae_u32 generate_stack_return(int cnt) { uae_u32 v; - if (target_ea[0] != 0xffffffff) { + // if targer sp mode: generate random return address + if (target_ea[0] != 0xffffffff && feature_usp < 3) { v = target_ea[0]; } else { v = rand32(); @@ -2446,9 +2451,9 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i int offset = 0; if (dp->mnemo == i_RTE || dp->mnemo == i_RTD || dp->mnemo == i_RTS || dp->mnemo == i_RTR || dp->mnemo == i_UNLK) { uae_u32 v; - uaecptr addr = regs.regs[8 + 7]; + uaecptr addr = regs.regs[15]; // RTE, RTD, RTS and RTR - if (dp->mnemo == i_RTR) { + if (dp->mnemo == i_RTR) { // RTR v = imm_special++; uae_u16 ccr = v & 31; @@ -2649,6 +2654,26 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) } } +// instruction that reads or writes stack +static int stackinst(struct instr *dp) +{ + switch (dp->mnemo) + { + case i_RTS: + case i_RTR: + case i_RTD: + case i_RTE: + case i_UNLK: + return 1; + case i_BSR: + case i_JSR: + case i_LINK: + case i_PEA: + return 2; + } + return 0; +} + // any instruction that can branch execution static int isbranchinst(struct instr *dp) { @@ -2958,16 +2983,23 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int count = 0; registers[8 + 6] = opcode_memory_start - 0x100; - registers[8 + 7] = user_stack_memory_use; + registers[15] = user_stack_memory_use; uae_u32 target_address = 0xffffffff; uae_u32 target_opcode_address = 0xffffffff; + uae_u32 target_usp_address = 0xffffffff; target_ea[0] = 0xffffffff; target_ea[1] = 0xffffffff; target_ea[2] = 0xffffffff; if (feature_target_ea[0][2] && feature_target_ea[0][2] != 0xffffffff) { - target_opcode_address = feature_target_ea[0][2]; - target_ea[2] = target_opcode_address; + if (feature_usp == 3) { + target_usp_address = feature_target_ea[0][2]; + target_ea[2] = target_usp_address; + target_usp_address += opcode_memory_start; + } else { + target_opcode_address = feature_target_ea[0][2]; + target_ea[2] = target_opcode_address; + } } if (feature_target_ea[0][0] != 0xffffffff) { target_address = feature_target_ea[0][0]; @@ -3185,6 +3217,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi target_address = target_address_bak; target_opcode_address = target_opcode_address_bak; + if (target_usp_address != 0xffffffff) { + cur_registers[15] = target_usp_address; + regs.regs[15] = target_usp_address; + } + if (opc == 0x4a53) printf(""); if (subtest_count >= 700) @@ -3282,7 +3319,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } // requested target address but no EA? skip - if (target_address != 0xffffffff && isbranchinst(dp) != 2) { + if (target_address != 0xffffffff && isbranchinst(dp) != 2 && (feature_usp < 3 || !stackinst(dp))) { if (srcea != target_address && dstea != target_address) { memcpy(opcode_memory, oldcodebytes, sizeof(oldcodebytes)); continue; @@ -3383,6 +3420,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi for (int i = 0; i < 8; i++) { regs.fp[i].fpx = cur_fpuregisters[i]; } + uaecptr nextpc; srcaddr = 0xffffffff; dstaddr = 0xffffffff; @@ -3438,10 +3476,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi constant_loops++; quick = 0; } - srcaddr = get_long_test(regs.regs[8 + 7] + stackoffset); + srcaddr = get_long_test(regs.regs[15] + stackoffset); } // branch target is not accessible? skip. - if ((srcaddr >= cur_registers[15] - 16 && srcaddr <= cur_registers[15] + 16) || ((srcaddr & 1) && !feature_exception3_instruction && feature_odd_usp < 2)) { + if ((srcaddr >= cur_registers[15] - 16 && srcaddr <= cur_registers[15] + 16) || ((srcaddr & 1) && !feature_exception3_instruction && feature_usp < 2)) { // lets not jump directly to stack.. if (verbose) { if (srcaddr & 1) @@ -3527,6 +3565,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi *dst++ = branch_target_swap_mode; } + if (feature_usp >= 3) { + dst = store_reg(dst, CT_AREG + 7, 0, target_usp_address, sz_long); + } + // pre-test data end *dst++ = CT_END_INIT; @@ -3669,7 +3711,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi regs.sr = ((ccr & 1) ? 31 : 0) | sr_mask; } regs.sr |= feature_min_interrupt_mask << 8; - regs.usp = regs.regs[8 + 7]; + regs.usp = regs.regs[15]; regs.isp = super_stack_memory - 0x80; // copy user stack to super stack, for RTE etc support memcpy(test_memory + (regs.isp - test_memory_start), test_memory + (regs.usp - test_memory_start), 0x20); @@ -3716,6 +3758,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi ((cpu_bus_error & 2) && !(safe_memory_mode & 2))) { skipped = 1; } + // skip if feature_target_opcode_offset mode and non-prefetch bus error if (target_opcode_address != 0xffffffff && (cpu_bus_error & 3)) { skipped = 1; @@ -3729,7 +3772,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (feature_exception3_instruction == 2) { skipped = 1; } - if (feature_odd_usp > 1) { + if (feature_usp == 2) { skipped = 1; } } @@ -3759,10 +3802,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_odd_usp && !feature_exception3_data && !(test_exception_3_fc & 2)) { + if ((feature_usp != 1 && feature_usp != 2) && !feature_exception3_data && !(test_exception_3_fc & 2)) { skipped = 1; } - if (!feature_odd_usp && !feature_exception3_instruction && (test_exception_3_fc & 2)) { + if ((feature_usp != 1 && feature_usp != 2) && !feature_exception3_instruction && (test_exception_3_fc & 2)) { skipped = 1; } } @@ -3976,7 +4019,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } dst = storage_buffer; - if (opcodecnt == 1 && target_address == 0xffffffff && target_opcode_address == 0xffffffff) + if (opcodecnt == 1 && target_address == 0xffffffff && target_opcode_address == 0xffffffff && target_usp_address == 0xffffffff) break; if (lookup->mnemo == i_ILLG) break; @@ -4013,7 +4056,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi nextround = true; } - if (target_opcode_address != 0xffffffff) { + if (target_opcode_address != 0xffffffff || target_usp_address != 0xffffffff) { nextround = false; target_ea_opcode_cnt++; if (target_ea_opcode_cnt >= target_ea_opcode_max) { @@ -4023,8 +4066,14 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } else { quick = 0; } - target_opcode_address = feature_target_ea[target_ea_opcode_cnt][2]; - target_ea[2] = opcode_memory_address + target_opcode_address; + if (feature_usp == 3) { + target_usp_address = feature_target_ea[target_ea_opcode_cnt][2]; + target_usp_address += opcode_memory_start; + target_ea[2] = target_usp_address; + } else { + target_opcode_address = feature_target_ea[target_ea_opcode_cnt][2]; + target_ea[2] = opcode_memory_address + target_opcode_address; + } } if (nextround) { @@ -4036,7 +4085,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi cur_registers[0] &= 0xffff; cur_registers[8] &= 0xffff; cur_registers[8 + 6]--; - cur_registers[8 + 7] -= 2; + cur_registers[15] -= 2; if (fpumode) { for (int i = 0; i < 8; i++) { @@ -4345,8 +4394,8 @@ int __cdecl main(int argc, char *argv[]) } feature_flag_mode = 0; ini_getval(ini, INISECTION, _T("feature_flags_mode"), &feature_flag_mode); - feature_odd_usp = 0; - ini_getval(ini, INISECTION, _T("feature_odd_usp"), &feature_odd_usp); + feature_usp = 0; + ini_getval(ini, INISECTION, _T("feature_usp"), &feature_usp); feature_full_extension_format = 0; if (currprefs.cpu_model >= 68020) { @@ -4493,7 +4542,7 @@ int __cdecl main(int argc, char *argv[]) user_stack_memory = test_memory_start + RESERVED_SUPERSTACK; } user_stack_memory_use = user_stack_memory; - if (feature_odd_usp) { + if (feature_usp == 1 || feature_usp == 2) { user_stack_memory_use |= 1; } diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 0353df5c..97ef082d 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -78,11 +78,12 @@ feature_safe_memory_size=0x80000 ; if enabled, all tests that don't generate matching bus error are skipped. feature_safe_memory_mode=R -; force odd user stack -; 0 = even stack +; user stack modes +; 0 = normal even stack ; 1 = odd stack (original stack + 1) ; 2 = odd stack and skip all tests that didn't generate address error exception -feature_odd_usp=0 +; 3 = take stack from feature_target_opcode_offset +feature_usp=0 ; CCR/FPU status flags mode ; 0 = all combinations (32 CCR loops, 256 FPU loops) diff --git a/cputest/main.c b/cputest/main.c index 7cda24f5..0ee3e55f 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -1816,6 +1816,13 @@ static void process_test(uae_u8 *p) break; p++; + int stackcopysize = 0; + for (int i = 0; i < 32; i += 2) { + if (!is_valid_test_addr_readwrite(regs.regs[15] + i)) + break; + stackcopysize += 2; + } + store_addr(regs.srcaddr, srcaddr); store_addr(regs.dstaddr, dstaddr); store_addr(regs.branchtarget, branchtarget); @@ -1884,7 +1891,8 @@ static void process_test(uae_u8 *p) regs.fpiar = startpc; #ifdef M68K - xmemcpy((void*)regs.ssp, (void*)regs.regs[15], 0x20); + if (stackcopysize > 0) + xmemcpy((void*)regs.ssp, (void*)regs.regs[15], stackcopysize); #endif xmemcpy(&test_regs, ®s, sizeof(struct registers)); diff --git a/gencpu.cpp b/gencpu.cpp index 568be11e..241eac40 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -1016,7 +1016,7 @@ static void fill_prefetch_next_t(void) if (using_prefetch) { irc2ir(); if (using_bus_error) { - printf("\topcode = regs.ir;\n"); + copy_opcode(); strcat(bus_error_code, "\t\tif (regs.t1) opcode |= 0x10000;\n"); } fill_prefetch_1(m68k_pc_offset + 2); @@ -1031,7 +1031,7 @@ static void fill_prefetch_next_extra(const char *cond, const char *format, ...) if (using_bus_error) { if (cond) printf("\t%s\n\t", cond); - printf("\topcode = regs.ir;\n"); + copy_opcode(); bus_error_code[0] = 0; if (format) { va_list parms; @@ -1598,7 +1598,11 @@ static int do_bus_error_fixes(const char *name, int offset, int write) break; case 2: case -2: - printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset); + if (g_instr->mnemo == i_RTR) { + ; + } else { + printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset); + } break; case 3: case -3: @@ -1611,6 +1615,15 @@ static int do_bus_error_fixes(const char *name, int offset, int write) if ((g_instr->mnemo == i_ADDX || g_instr->mnemo == i_SUBX) && g_instr->size == sz_long) { // ADDX.L/SUBX.L -(an),-(an) source: stack frame decreased by 2, not 4. offset += 2; + } else if (g_instr->mnemo == i_RTR) { + if (offset) { + printf("\t\tm68k_areg(regs, %s) += 4;\n", bus_error_reg); + printf("\t\tregs.sr &= 0xFF00; sr &= 0xFF;\n"); + printf("\t\tregs.sr |= sr;\n"); + printf("\t\tMakeFromSR();\n"); + } else { + printf("\t\tm68k_areg(regs, %s) -= 2;\n", bus_error_reg); + } } else { printf("\t\tm68k_areg(regs, %s) = %sa;\n", bus_error_reg, name); } @@ -1685,7 +1698,13 @@ static void check_bus_error(const char *name, int offset, int write, int size, c if (mnemo == i_LINK) { // a7 -> a0 copy done before A7 address error check - printf("\tm68k_areg(regs, srcreg) = olda;\n"); + if (write) { + printf("\t\tm68k_areg(regs, 7) += 4;\n"); + } + printf("\t\tm68k_areg(regs, srcreg) = olda;\n"); + } + if (mnemo == i_PEA && write && offset && g_instr->smode != absw && g_instr->smode != absl) { + printf("\t\tif (regs.t1) opcode |= 0x10000;\n"); // I/N set } if (cpu_level == 1 && g_instr->mnemo == i_MVSR2 && !write) { @@ -1700,8 +1719,10 @@ static void check_bus_error(const char *name, int offset, int write, int size, c // write causing bus error and trace: set I/N if (write && g_instr->size <= sz_word && mnemo != i_MOVE && + mnemo != i_BSR && + mnemo != i_LINK && mnemo != i_MVMEL && mnemo != i_MVMLE && - mnemo != i_MVPRM && mnemo != i_MVPMR) { + mnemo != i_MVPRM && mnemo != i_MVPMR) { printf("\t\tif (regs.t1) opcode |= 0x10000;\n"); // I/N set } @@ -5679,7 +5700,7 @@ static void gen_opcode (unsigned int opcode) printf("\tuaecptr oldpc = %s;\n", getpc); printf("\tMakeSR();\n"); genamode (NULL, Aipi, "7", sz_word, "sr", 1, 0, 0); - genamode (NULL, Aipi, "7", sz_long, "pc", 1, 0, 0); + genamode(NULL, Aipi, "7", sz_long, "pc", 1, 0, 0); if (cpu_level >= 4) { printf("\tif (pc & 1) {\n"); printf("\t\tm68k_areg(regs, 7) -= 6;\n"); @@ -5689,8 +5710,8 @@ static void gen_opcode (unsigned int opcode) } printf("\tregs.sr &= 0xFF00; sr &= 0xFF;\n"); printf("\tregs.sr |= sr;\n"); - setpc ("pc"); makefromsr(); + setpc ("pc"); if (cpu_level < 4) { printf("\tif (%s & 1) {\n", getpc); printf("\t\tuaecptr faultpc = %s;\n", getpc); @@ -5783,7 +5804,7 @@ static void gen_opcode (unsigned int opcode) if (using_prefetch || using_ce) { int sp = (curi->smode == Ad16 || curi->smode == absw || curi->smode == absl || curi->smode == PC16 || curi->smode == Ad8r || curi->smode == PC8r) ? -1 : 0; irc2ir(); - printf("\topcode = regs.ir;\n"); + copy_opcode(); if (sp < 0) printf("\tif(regs.t1) opcode |= 0x10000;\n"); printf("\t%s(%d);\n", prefetch_word, 2); @@ -5821,7 +5842,7 @@ static void gen_opcode (unsigned int opcode) irc2ir(); printf("\t%s(%d);\n", prefetch_word, 2); int sp = (curi->smode == Ad16 || curi->smode == absw || curi->smode == absl || curi->smode == PC16 || curi->smode == Ad8r || curi->smode == PC8r) ? -1 : 0; - printf("\topcode = regs.ir;\n"); + copy_opcode(); if (sp < 0) printf("\tif(regs.t1) opcode |= 0x10000;\n"); check_prefetch_bus_error(-2, sp); @@ -6015,7 +6036,7 @@ bccl_not68020: genamode (curi, curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA); genamode (NULL, Apdi, "7", sz_long, "dst", 2, 0, GF_AA); if (!(curi->smode == absw || curi->smode == absl)) - fill_prefetch_next_after(1, "m68k_areg(regs, 7) += 4;\n"); + fill_prefetch_next_after(0, "m68k_areg(regs, 7) += 4;\n"); if (curi->smode == Ad8r || curi->smode == PC8r) addcycles000 (2); genastore ("srca", Apdi, "7", sz_long, "dst"); @@ -6063,7 +6084,7 @@ bccl_not68020: add_head_cycs (6); if (using_prefetch || using_ce) { - printf("\topcode = regs.ir;\n"); + copy_opcode(); printf("\tif(regs.t1) opcode |= 0x10000;\n"); printf("\t%s(%d);\n", prefetch_word, 2); check_prefetch_bus_error(-2, -1); -- 2.47.3