From: Toni Wilen Date: Sun, 1 Dec 2019 19:33:42 +0000 (+0200) Subject: Cputester updates. Trace stacked on top of group 1 exception supported. Bus and addre... X-Git-Tag: 4300~33 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=2b5770d8374cf728a12c37be3aba5d1a20f57c57;p=francis%2Fwinuae.git Cputester updates. Trace stacked on top of group 1 exception supported. Bus and address error special cases supported. --- diff --git a/.gitignore b/.gitignore index af888507..d17a92a1 100644 --- a/.gitignore +++ b/.gitignore @@ -48,19 +48,8 @@ aros.rom.cpp /blitfunc.h /blittable.cpp /cpudefs.cpp -/cpuemu_0.cpp -/cpuemu_11.cpp -/cpuemu_13.cpp -/cpuemu_20.cpp -/cpuemu_21.cpp -/cpuemu_22.cpp -/cpuemu_23.cpp -/cpuemu_24.cpp -/cpuemu_31.cpp -/cpuemu_32.cpp -/cpuemu_33.cpp -/cpuemu_40.cpp -/cpuemu_50.cpp +/cpuemu_*.cpp +/cpuemu_*_test.cpp /cpustbl.cpp /cpustbl_test.cpp /cputbl.h diff --git a/cputest.cpp b/cputest.cpp index 606ba093..b5e9fb0c 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -41,7 +41,7 @@ int movem_index1[256]; int movem_index2[256]; int movem_next[256]; int bus_error_offset; -int cpu_bus_error; +int cpu_bus_error, cpu_bus_error_fake; struct mmufixup mmufixup[2]; cpuop_func *cpufunctbl[65536]; @@ -70,7 +70,7 @@ static TCHAR *feature_instruction_size = NULL; static uae_u32 feature_addressing_modes[2]; static int ad8r[2], pc8r[2]; static int multi_mode; -#define MAX_TARGET_EA 8 +#define MAX_TARGET_EA 20 static uae_u32 feature_target_ea[MAX_TARGET_EA][2]; static int target_ea_src_cnt, target_ea_dst_cnt; static int target_ea_src_max, target_ea_dst_max; @@ -113,6 +113,7 @@ static bool out_of_test_space; static uaecptr out_of_test_space_addr; static int forced_immediate_mode; static int test_exception; +static int test_exception_extra; static int exception_stack_frame_size; static uaecptr test_exception_addr; static int test_exception_3_w; @@ -230,7 +231,7 @@ oob: static bool is_nowrite_address(uaecptr addr, int size) { - return addr + size >= safe_memory_start && addr < safe_memory_end; + return addr + size > safe_memory_start && addr < safe_memory_end; } static void validate_addr(uaecptr addr, int size) @@ -283,6 +284,7 @@ static void check_bus_error(uaecptr addr, int write, int fc) if (safe_memory_start == 0xffffffff && safe_memory_end == 0xffffffff) return; if (addr >= safe_memory_start && addr < safe_memory_end) { + cpu_bus_error_fake = 1; if ((safe_memory_mode & 1) && !write) cpu_bus_error = 1; if ((safe_memory_mode & 2) && write) @@ -334,7 +336,7 @@ void put_byte_test(uaecptr addr, uae_u32 v) { check_bus_error(addr, 1, regs.s ? 5 : 1); uae_u8 *p = get_addr(addr, 1, 1); - if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) { + if (!out_of_test_space && !noaccesshistory && !cpu_bus_error_fake) { previoussame(addr, sz_byte); if (ahcnt >= MAX_ACCESSHIST) { wprintf(_T("ahist overflow!")); @@ -357,7 +359,7 @@ void put_word_test(uaecptr addr, uae_u32 v) put_byte_test(addr + 1, v >> 0); } else { uae_u8 *p = get_addr(addr, 2, 1); - if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) { + if (!out_of_test_space && !noaccesshistory && !cpu_bus_error_fake) { previoussame(addr, sz_word); if (ahcnt >= MAX_ACCESSHIST) { wprintf(_T("ahist overflow!")); @@ -386,7 +388,7 @@ void put_long_test(uaecptr addr, uae_u32 v) put_word_test(addr + 2, v >> 0); } else { uae_u8 *p = get_addr(addr, 4, 1); - if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) { + if (!out_of_test_space && !noaccesshistory && !cpu_bus_error_fake) { previoussame(addr, sz_long); if (ahcnt >= MAX_ACCESSHIST) { wprintf(_T("ahist overflow!")); @@ -808,8 +810,12 @@ static void doexcstack(void) testing_active = -1; int opcode = (opcode_memory[0] << 8) | (opcode_memory[1]); - if (test_exception_opcode >= 0) + if (test_exception_opcode >= 0) { opcode = test_exception_opcode; + } + if (SPCFLAG_DOTRACE && test_exception == 9) { + SPCFLAG_DOTRACE = 0; + } int sv = regs.s; uaecptr tmp = m68k_areg(regs, 7); @@ -819,6 +825,7 @@ static void doexcstack(void) uae_u16 mode = (sv ? 4 : 0) | test_exception_3_fc; mode |= test_exception_3_w ? 0 : 16; Exception_build_68000_address_error_stack_frame(mode, opcode, test_exception_addr, regs.pc); + SPCFLAG_DOTRACE = 0; } } else if (cpu_lvl == 1) { if (test_exception == 2 || test_exception == 3) { @@ -832,6 +839,7 @@ static void doexcstack(void) ssw &= 0x00ff; regs.mmu_fault_addr = test_exception_addr; Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, 3, 0x08); + SPCFLAG_DOTRACE = 0; } else { Exception_build_stack_frame_common(regs.instruction_pc, regs.pc, 0, test_exception); } @@ -905,12 +913,19 @@ uae_u32 REGPARAM2 op_illg(uae_u32 opcode) void exception2_fetch(uae_u32 opcode, uaecptr addr) { test_exception = 2; - test_exception_3_w = 1; + test_exception_3_w = 0; test_exception_addr = addr; test_exception_opcode = opcode; test_exception_3_fc = 2; test_exception_3_size = 1; test_exception_3_di = 0; + + if (currprefs.cpu_model == 68000) { + if (generates_group1_exception(regs.ir)) { + test_exception_3_fc |= 8; // set N/I + } + } + doexcstack(); } @@ -923,6 +938,14 @@ void exception2_read(uae_u32 opcode, uaecptr addr, int size, int fc) test_exception_3_fc = fc; test_exception_3_size = size; test_exception_3_di = 1; + + if (currprefs.cpu_model == 68000) { + if (generates_group1_exception(regs.ir)) { + test_exception_3_fc |= 8; // set N/I + } + test_exception_opcode = regs.ir; + } + doexcstack(); } @@ -936,6 +959,14 @@ void exception2_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int f test_exception_3_size = size; regs.write_buffer = val; test_exception_3_di = 1; + + if (currprefs.cpu_model == 68000) { + if (generates_group1_exception(regs.ir)) { + test_exception_3_fc |= 8; // set N/I + } + test_exception_opcode = regs.ir; + } + doexcstack(); } @@ -948,6 +979,16 @@ void exception3_read(uae_u32 opcode, uae_u32 addr, int size, int fc) test_exception_3_fc = fc; test_exception_3_size = size; test_exception_3_di = 1; + + if (currprefs.cpu_model == 68000) { + if (generates_group1_exception(regs.ir)) { + test_exception_3_fc |= 8; // set N/I + } + if (opcode & 0x10000) + test_exception_3_fc |= 8; + test_exception_opcode = regs.ir; + } + doexcstack(); } void exception3_write(uae_u32 opcode, uae_u32 addr, int size, uae_u32 val, int fc) @@ -960,6 +1001,16 @@ void exception3_write(uae_u32 opcode, uae_u32 addr, int size, uae_u32 val, int f test_exception_3_size = size; regs.write_buffer = val; test_exception_3_di = 1; + + if (currprefs.cpu_model == 68000) { + if (generates_group1_exception(regs.ir)) { + test_exception_3_fc |= 8; // set N/I + } + if (opcode & 0x10000) + test_exception_3_fc |= 8; + test_exception_opcode = regs.ir; + } + doexcstack(); } @@ -1464,6 +1515,19 @@ static void reset_ea_state(void) ea_state_found[2] = 0; } +// if other EA is target EA, don't point this EA +// to same address space. +static bool other_targetea_same(int srcdst, uae_u32 v) +{ + if (target_ea[srcdst ^ 1] == 0xffffffff) + return false; + if (!is_nowrite_address(target_ea[srcdst ^ 1], 1)) + return false; + if (!is_nowrite_address(v, 1)) + return false; + return true; +} + // attempt to find at least one zero, positive and negative source value static int analyze_address(struct instr *dp, int srcdst, uae_u32 addr) { @@ -1613,6 +1677,8 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str add <<= (v >> 9) & 3; // SCALE } addr += (uae_s8)(v & 0xff); // DISPLACEMENT + if (other_targetea_same(srcdst, addr)) + continue; if (analyze_address(dp, srcdst, addr)) break; maxcnt--; @@ -1662,8 +1728,10 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str uae_u16 v; for (;;) { v = rand16(); + if (other_targetea_same(srcdst, (uae_s32)(uae_s16)v)) + continue; if (analyze_address(dp, srcdst, v)) - break; + break; } put_word_test(pc, v); *isconstant = 16; @@ -1691,6 +1759,8 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str v = opcode_memory_start + offset; } immabsl_cnt++; + if (other_targetea_same(srcdst, v)) + continue; if (analyze_address(dp, srcdst, v)) break; } @@ -2345,9 +2415,9 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins { uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0); uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0); - if (opc == 0x2191 - && opw1 == 0xdd12 - && opw2 == 0xf78c + if (opc == 0x4ea9 + && opw1 == 0xffff + //&& opw2 == 0xf78c ) printf(""); if (regs.sr & 0x2000) @@ -2367,15 +2437,21 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins testing_active = 1; testing_active_opcode = opc; cpu_bus_error = 0; + cpu_bus_error_fake = 0; regs.read_buffer = regs.irc; regs.write_buffer = 0xf00d; - int cnt = feature_loop_mode * 2; + int cnt = (feature_loop_mode + 1) * 2; if (multi_mode) cnt = 100; for (;;) { + if (cnt <= 0) { + wprintf(_T(" Loop mode didn't end!?\n")); + abort(); + } + if (SPCFLAG_TRACE) do_trace(); @@ -2404,18 +2480,19 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins break; } - if (!test_exception) { - if (SPCFLAG_DOTRACE) - Exception(9); - - if (cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) { - // 68000/68010 undocumented special case: - // if STOP clears S-bit and T was not set: - // cause privilege violation exception, PC pointing to following instruction. - // If T was set before STOP: STOP works as documented. - cpu_stopped = 0; - Exception(8); - } + if (!SPCFLAG_DOTRACE && cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) { + // 68000/68010 undocumented special case: + // if STOP clears S-bit and T was not set: + // cause privilege violation exception, PC pointing to following instruction. + // If T was set before STOP: STOP works as documented. + cpu_stopped = 0; + Exception(8); + } + + // Trace is only added as an exception if there was no other exceptions + // Trace stacked with other exception is handled later + if (SPCFLAG_DOTRACE && !test_exception) { + Exception(9); } // Amiga Chip ram does not support TAS or MOVE16 @@ -2427,15 +2504,15 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins if (regs.pc == endpc || regs.pc == targetpc) break; - if (test_exception) + if (test_exception || SPCFLAG_DOTRACE) break; if (!valid_address(regs.pc, 2, 0)) break; - if (!feature_loop_mode && !multi_mode) { - wprintf(_T(" Test instruction didn't finish in single step in non-loop mode!?\n")); - abort(); + if (regs.pc + 2 == targetpc) { + opc = regs.ir; + continue; } if (cpu_lvl < 2) { @@ -2445,10 +2522,12 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins } cnt--; - if (cnt <= 0) { - wprintf(_T(" Loop mode didn't end!?\n")); + + if (!feature_loop_mode && !multi_mode && opc != 0x4e71) { + wprintf(_T(" Test instruction didn't finish in single step in non-loop mode!?\n")); abort(); } + } testing_active = 0; @@ -2531,11 +2610,13 @@ static int noregistercheck(struct instr *dp) static uae_u8 last_exception[256]; static int last_exception_len; +static int last_exception_extra; static uae_u8 *save_exception(uae_u8 *p, struct instr *dp) { uae_u8 *op = p; p++; + *p++ = test_exception_extra; uae_u8 *sf = test_memory + test_memory_size + EXTRA_RESERVED_SPACE - exception_stack_frame_size; // parse exception and store fields that are unique // SR and PC was already saved with non-exception data @@ -2598,13 +2679,14 @@ static uae_u8 *save_exception(uae_u8 *p, struct instr *dp) abort(); } } - if (last_exception_len > 0 && last_exception_len == exception_stack_frame_size && !memcmp(sf, last_exception, exception_stack_frame_size)) { + if (last_exception_len > 0 && last_exception_len == exception_stack_frame_size && test_exception_extra == last_exception_extra && !memcmp(sf, last_exception, exception_stack_frame_size)) { // stack frame was identical to previous p = op; *p++ = 0xff; } else { int datalen = (p - op) - 1; last_exception_len = exception_stack_frame_size; + last_exception_extra = test_exception_extra; *op = (uae_u8)datalen; memcpy(last_exception, sf, exception_stack_frame_size); } @@ -2829,12 +2911,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int sr_override = 0; uae_u32 target_ea_bak[2], target_address_bak; - target_ea_bak[0] = target_ea[0]; - target_ea_bak[1] = target_ea[1]; - target_address_bak = target_address; for (;;) { + target_ea_bak[0] = target_ea[0]; + target_ea_bak[1] = target_ea[1]; + target_address_bak = target_address; + if (quick) break; @@ -2858,6 +2941,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi uae_u32 dstaddr_old = 0xffffffff; uae_u32 srcaddr = 0xffffffff; uae_u32 dstaddr = 0xffffffff; + uae_u32 branchtarget_old = 0xffffffff; for (int opcode = 0; opcode < 65536; opcode++) { @@ -2916,6 +3000,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // if instruction has immediate(s), repeat instruction test multiple times // each round generates new random immediate(s) int constant_loops = 32; + if (dp->mnemo == i_ILLG) { + constant_loops = 1; + } while (constant_loops-- > 0) { uae_u8 oldbytes[OPCODE_AREA]; @@ -2927,114 +3014,127 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int did_out_of_bounds = 0; uae_u8 *prev_dst2 = dst; + uae_u32 branch_target_swap_address = 0; + int branch_target_swap_mode = 0; + uae_u32 branch_target_data_original = 0x4afc4e71; + uae_u32 branch_target_data = branch_target_data_original; + out_of_test_space = 0; + noaccesshistory = 0; + cpu_bus_error_fake = 0; + cpu_bus_error = 0; ahcnt = 0; + ahcnt2 = 0; multi_mode = 0; target_ea[0] = target_ea_bak[0]; target_ea[1] = target_ea_bak[1]; target_address = target_address_bak; - if (opc == 0x0156) + if (opc == 0x4ed0) printf(""); - if (subtest_count == 416) + if (subtest_count == 2568) printf(""); uaecptr pc = opcode_memory_start + 2; - pc += handle_specials_preea(opc, pc, dp); - + if (dp->mnemo != i_ILLG) { - uae_u32 srcea = 0xffffffff; - uae_u32 dstea = 0xffffffff; + pc += handle_specials_preea(opc, pc, dp); - // create source addressing mode - if (dp->suse) { - int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea); - if (o < 0) { - memcpy(opcode_memory, oldbytes, sizeof(oldbytes)); - if (o == -1) - goto nextopcode; - continue; - } - pc += o; - } - uae_u8 *ao = opcode_memory + 2; - uae_u16 apw1 = (ao[0] << 8) | (ao[1] << 0); - uae_u16 apw2 = (ao[2] << 8) | (ao[3] << 0); - if (opc == 0x4eb1 - && apw1 == 0xee38 - //&& apw2 == 0x7479 - ) - printf(""); + uae_u32 srcea = 0xffffffff; + uae_u32 dstea = 0xffffffff; - if (target_address != 0xffffffff && (dp->mnemo == i_MVMEL || dp->mnemo == i_MVMLE)) { - // if MOVEM and more than 1 register: randomize address so that any MOVEM - // access can hit target address - uae_u16 mask = (opcode_memory[2] << 8) | opcode_memory[3]; - int count = 0; - for (int i = 0; i < 16; i++) { - if (mask & (1 << i)) - count++; - } - if (count > 0) { - int diff = (rand8() % count); - if (dp->dmode == Apdi) { - diff = -diff; + // create source addressing mode + if (dp->suse) { + int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea); + if (o < 0) { + memcpy(opcode_memory, oldbytes, sizeof(oldbytes)); + if (o == -1) + goto nextopcode; + continue; } - uae_u32 ta = target_address; - target_address -= diff * (1 << dp->size); - if (target_ea[0] == ta) - target_ea[0] = target_address; - if (target_ea[1] == ta) - target_ea[1] = target_address; + pc += o; } - } - // if source EA modified opcode - dp = table68k + opc; + uae_u8 *ao = opcode_memory + 2; + uae_u16 apw1 = (ao[0] << 8) | (ao[1] << 0); + uae_u16 apw2 = (ao[2] << 8) | (ao[3] << 0); + if (opc == 0x4eb1 + && apw1 == 0xee38 + //&& apw2 == 0x7479 + ) + printf(""); + + if (target_address != 0xffffffff && (dp->mnemo == i_MVMEL || dp->mnemo == i_MVMLE)) { + // if MOVEM and more than 1 register: randomize address so that any MOVEM + // access can hit target address + uae_u16 mask = (opcode_memory[2] << 8) | opcode_memory[3]; + int count = 0; + for (int i = 0; i < 16; i++) { + if (mask & (1 << i)) + count++; + } + if (count > 0) { + int diff = (rand8() % count); + if (dp->dmode == Apdi) { + diff = -diff; + } + uae_u32 ta = target_address; + target_address -= diff * (1 << dp->size); + if (target_ea[0] == ta) + target_ea[0] = target_address; + if (target_ea[1] == ta) + target_ea[1] = target_address; + } + } - // create destination addressing mode - if (dp->duse) { - int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea); - if (o < 0) { - memcpy(opcode_memory, oldbytes, sizeof(oldbytes)); - if (o == -1) - goto nextopcode; - continue; + // if source EA modified opcode + dp = table68k + opc; + + // create destination addressing mode + if (dp->duse) { + int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea); + if (o < 0) { + memcpy(opcode_memory, oldbytes, sizeof(oldbytes)); + if (o == -1) + goto nextopcode; + continue; + } + pc += o; } - pc += o; - } - // requested target address but no EA? skip - if (target_address != 0xffffffff) { - if (srcea != target_address && dstea != target_address) { - memcpy(opcode_memory, oldbytes, sizeof(oldbytes)); - continue; + // requested target address but no EA? skip + if (target_address != 0xffffffff) { + if (srcea != target_address && dstea != target_address) { + memcpy(opcode_memory, oldbytes, sizeof(oldbytes)); + continue; + } } - } - pc = handle_specials_extra(opc, pc, dp); + pc = handle_specials_extra(opc, pc, dp); - // if destination EA modified opcode - dp = table68k + opc; + // if destination EA modified opcode + dp = table68k + opc; - uae_u8 *bo = opcode_memory + 2; - uae_u16 bopw1 = (bo[0] << 8) | (bo[1] << 0); - uae_u16 bopw2 = (bo[2] << 8) | (bo[3] << 0); - if (opc == 0xf228 - && bopw1 == 0x003a - //&& bopw2 == 0x2770 - ) - printf(""); + uae_u8 *bo = opcode_memory + 2; + uae_u16 bopw1 = (bo[0] << 8) | (bo[1] << 0); + uae_u16 bopw2 = (bo[2] << 8) | (bo[3] << 0); + if (opc == 0xf228 + && bopw1 == 0x003a + //&& bopw2 == 0x2770 + ) + printf(""); + + // bcc.x + pc += handle_specials_branch(opc, pc, dp, &isconstant_src); + // misc + pc += handle_specials_misc(opc, pc, dp, &isconstant_src); - // bcc.x - pc += handle_specials_branch(opc, pc, dp, &isconstant_src); - // misc - pc += handle_specials_misc(opc, pc, dp, &isconstant_src); + } put_word_test(opcode_memory_start, opc); @@ -3055,8 +3155,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // end word, needed to detect if instruction finished normally when // running on real hardware. - put_word_test(pc, 0x4afc); // illegal instruction - pc += 2; + uae_u32 originalendopcode = 0x4afc4e71; + uae_u32 endopcode = originalendopcode; + put_long_test(pc, endopcode); // illegal instruction + nop + pc += 4; if (isconstant_src < 0 || isconstant_dst < 0) { constant_loops++; @@ -3124,6 +3226,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } #endif uaecptr branch_target = 0xffffffff; + uaecptr branch_target_pc = 0xffffffff; int bc = isbranchinst(dp); if (bc) { if (bc < 0) { @@ -3160,12 +3263,20 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi continue; } else { // branch target = generate exception - if (!is_nowrite_address(srcaddr, 2)) { - put_word_test(srcaddr, 0x4afc); + if (!is_nowrite_address(srcaddr, 4)) { + branch_target_swap_address = srcaddr; + branch_target_swap_mode = 1; + put_long_test(srcaddr, branch_target_data); + } else { + if (!is_nowrite_address(srcaddr, 2)) { + put_word_test(srcaddr, branch_target_data >> 16); + branch_target_swap_address = srcaddr; + branch_target_swap_mode = 2; + } } branch_target = srcaddr; dst = store_mem(dst, 1); - memcpy(&ahist2, &ahist, sizeof(struct accesshistory) *MAX_ACCESSHIST); + memcpy(&ahist2, &ahist, sizeof(struct accesshistory) * MAX_ACCESSHIST); ahcnt2 = ahcnt; } testing_active = 0; @@ -3179,6 +3290,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi dst = store_reg(dst, CT_DSTADDR, dstaddr_old, dstaddr, -1); dstaddr_old = dstaddr; } + if (branch_target != branchtarget_old) { + dst = store_reg(dst, CT_BRANCHTARGET, branchtarget_old, branch_target, -1); + branchtarget_old = branch_target; + *dst++ = branch_target_swap_mode; + } *dst++ = CT_END_INIT; @@ -3210,7 +3326,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int maxflag = fpumode ? 256 : 32; // if cc-instruction: always do full test - if (feature_flag_mode == 1 && !dp->ccuse) { + if (feature_flag_mode == 1 && (dp->mnemo == i_ILLG || !dp->ccuse)) { maxflag = fpumode ? 256 / 8 : 2; } @@ -3238,13 +3354,39 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi out_of_test_space = 0; test_exception = 0; + test_exception_extra = 0; cpu_stopped = 0; cpu_halted = 0; ahcnt = 0; memset(®s, 0, sizeof(regs)); + // swap end opcode illegal/nop + endopcode = (endopcode >> 16) | (endopcode << 16); + noaccesshistory++; + put_long_test(pc - 4, endopcode); + noaccesshistory--; + int endopcodesize = (endopcode >> 16) == 0x4e71 ? 2 : 4; + + // swap branch target illegal/nop + if (branch_target_swap_mode) { + noaccesshistory++; + branch_target_data = (branch_target_data >> 16) | (branch_target_data << 16); + branch_target_pc = branch_target; + if (branch_target_swap_mode == 1) { + put_long_test(branch_target_swap_address, branch_target_data); + if ((branch_target_data >> 16) == 0x4e71) + branch_target_pc = branch_target + 2; + else + branch_target_pc = branch_target; + } else if (branch_target_swap_mode == 2) { + put_word_test(branch_target_swap_address, branch_target_data >> 16); + } + noaccesshistory--; + } + regs.pc = opcode_memory_start; + regs.ir = get_word_test(regs.pc + 0); regs.irc = get_word_test(regs.pc + 2); // set up registers @@ -3298,10 +3440,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (regs.sr & 0x2000) prev_s_cnt++; - if (subtest_count == 23360) + if (subtest_count == 220) printf(""); - execute_ins(opc, pc - 2, branch_target, dp); + execute_ins(opc, pc - endopcodesize, branch_target_pc, dp); if (regs.s) s_cnt++; @@ -3348,7 +3490,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi skipped = 1; } } - if (test_exception == 9) { + if (SPCFLAG_DOTRACE || test_exception == 9) { t_cnt++; } } else { @@ -3356,13 +3498,38 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi ok++; // validate branch instructions if (isbranchinst(dp)) { - if ((regs.pc != srcaddr && regs.pc != pc - 2) || pcaddr[0] != 0x4a && pcaddr[1] != 0xfc) { + if ((regs.pc != branch_target_pc && regs.pc != pc - endopcodesize) || ((pcaddr[0] != 0x4a && pcaddr[1] != 0xfc) && (pcaddr[0] != 0x4e && pcaddr[1] != 0x71))) { wprintf(_T("Branch instruction target fault\n")); abort(); } } } + + noaccesshistory++; + put_long_test(pc - 4, originalendopcode); + if (branch_target_data != 0xffffff) { + if (branch_target_swap_address == 1) { + put_long_test(branch_target_swap_address, branch_target_data_original); + } else if (branch_target_swap_mode == 2) { + put_word_test(branch_target_swap_address, branch_target_data_original >> 16); + } + } + noaccesshistory--; + MakeSR(); + + // did we have trace also active? + if (SPCFLAG_DOTRACE) { + if (regs.t1 && (test_exception == 5 || test_exception == 6 || test_exception == 7 || (test_exception >= 32 && test_exception <= 47))) { + test_exception_extra = 9; + } else { + test_exception_extra = 0; + } + // clear trace + regs.t0 = 0; + regs.t1 = 0; + } + if (!skipped) { bool storeregs = true; if (noregistercheck(dp)) { diff --git a/cputest/asm.S b/cputest/asm.S index 164d8c44..e697c921 100644 --- a/cputest/asm.S +++ b/cputest/asm.S @@ -32,6 +32,9 @@ S_FPU = S_EXCFRAME+4 S_FPIAR = S_FPU+8*12 S_FPCR = S_FPIAR+4 S_FPSR = S_FPCR+4 +S_TRACECNT = S_FPSR+4 +S_TRACESTACK = S_TRACECNT+4 +S_NEXT = S_TRACESTACK+12 | set CPU special registers _setcpu: @@ -212,6 +215,17 @@ _msp_address2: movem.l (a0),d0-d7/a0-a6 rte +exception_trace000: + move.l a0,-(sp) + move.l datapointer(pc),a0 + tst.l S_TRACECNT(a0) + bne.s .nexttrace000 + move.l 4(sp),S_TRACESTACK(a0) + move.l 8(sp),S_TRACESTACK+4(a0) +.nexttrace000: + addq.l #1,S_TRACECNT(a0) + move.l (sp)+,a0 + rte _exceptiontable000: bsr.s exception | 2 @@ -221,7 +235,7 @@ _exceptiontable000: bsr.s exception | 6 bsr.s exception | 7 bsr.s exception | 8 - bsr.s exception | 9 + bra.s exception_trace000 | 9 bsr.s exception | 10 bsr.s exception | 11 bsr.s exception | 12 @@ -295,6 +309,19 @@ exception: movem.l (sp)+,d1-d7/a0-a6 rts +exception_trace010: + move.l a0,-(sp) + move.l datapointer(pc),a0 + tst.l S_TRACECNT(a0) + bne.s .nexttrace010 + move.l 4(sp),S_TRACESTACK(a0) + move.l 8(sp),S_TRACESTACK+4(a0) + move.l 12(sp),S_TRACESTACK+8(a0) +.nexttrace010: + addq.l #1,S_TRACECNT(a0) + move.l (sp)+,a0 + rte + _exceptiontable010: bsr.s exception010 | 2 bsr.s exception010 | 3 @@ -303,7 +330,7 @@ _exceptiontable010: bsr.s exception010 | 6 bsr.s exception010 | 7 bsr.s exception010 | 8 - bsr.s exception010 | 9 + bra.s exception_trace010 | 9 bsr.s exception010 | 10 bsr.s exception010 | 11 bsr.s exception010 | 12 @@ -374,6 +401,9 @@ exception010: movem.l (sp)+,d1-d7/a0-a6 rts +exception_trace010t1: + bra exception_trace010 + _exceptiontable020: bsr.s exception020 | 2 bsr.s exception020 | 3 @@ -382,7 +412,7 @@ _exceptiontable020: bsr.s exception020 | 6 bsr.s exception020 | 7 bsr.s exception020 | 8 - bsr.s exception020 | 9 + bra.s exception_trace010t1 | 9 bsr.s exception020 | 10 bsr.s exception020 | 11 bsr.s exception020 | 12 @@ -460,6 +490,9 @@ _msp_address3: movem.l (sp)+,d1-d7/a0-a6 rts +exception_trace010t2: + bra exception_trace010 + _exceptiontablefpu: bsr.s exceptionfpu | 2 bsr.s exceptionfpu | 3 @@ -468,7 +501,7 @@ _exceptiontablefpu: bsr.s exceptionfpu | 6 bsr.s exceptionfpu | 7 bsr.s exceptionfpu | 8 - bsr.s exceptionfpu | 9 + bsr.s exception_trace010t2 | 9 bsr.s exceptionfpu | 10 bsr.s exceptionfpu | 11 bsr.s exceptionfpu | 12 diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index 327c0b9d..3a7c8361 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -1,5 +1,5 @@ -#define DATA_VERSION 6 +#define DATA_VERSION 7 #define CT_FPREG 0 #define CT_DREG 0 @@ -11,6 +11,7 @@ #define CT_FPIAR 20 #define CT_FPSR 21 #define CT_FPCR 22 +#define CT_BRANCHTARGET 27 #define CT_SRCADDR 28 #define CT_DSTADDR 29 #define CT_MEMWRITE 30 diff --git a/cputest/main.c b/cputest/main.c index 1136208d..b5a0211d 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -45,7 +45,10 @@ struct registers uae_u32 excframe; struct fpureg fpuregs[8]; uae_u32 fpiar, fpcr, fpsr; - uae_u32 srcaddr, dstaddr; + uae_u32 tracecnt; + uae_u16 tracedata[6]; + uae_u32 srcaddr, dstaddr, branchtarget; + uae_u8 branchtarget_mode; }; static struct registers test_regs; @@ -90,6 +93,8 @@ static int low_memory_offset; static int high_memory_offset; static uae_u32 vbr[256]; +static int exceptioncount[256]; +static int supercnt; static char inst_name[16+1]; #ifndef M68K @@ -112,6 +117,7 @@ static uae_u32 interrupt_mask; #define SIZE_STORED_ADDRESS 16 static uae_u8 srcaddr[SIZE_STORED_ADDRESS]; static uae_u8 dstaddr[SIZE_STORED_ADDRESS]; +static uae_u8 branchtarget[SIZE_STORED_ADDRESS]; static uae_u8 stackaddr[SIZE_STORED_ADDRESS]; static uae_u32 stackaddr_ptr; @@ -189,6 +195,7 @@ extern void flushcache(uae_u32); extern void *error_vector; #endif +static uae_u32 exceptiontableinuse; struct accesshistory { @@ -208,9 +215,9 @@ static void endinfo(void) uae_u8 *p = opcode_memory; for (int i = 0; i < 32 * 2; i += 2) { uae_u16 v = (p[i] << 8) | (p[i + 1]); + printf(" %04x", v); if (v == 0x4afc && i > 0) break; - printf(" %04x", v); } printf("\n"); } @@ -331,15 +338,19 @@ static void start_test(void) for (int i = 32; i < 48; i++) { p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2); } + exceptiontableinuse = (uae_u32)&exceptiontable000; } else { oldvbr = setvbr((uae_u32)vbr); for (int i = 2; i < 48; i++) { if (fpu_model) { vbr[i] = (uae_u32)(((uae_u32)&exceptiontablefpu) + (i - 2) * 2); + exceptiontableinuse = (uae_u32)&exceptiontablefpu; } else if (cpu_lvl == 1) { vbr[i] = (uae_u32)(((uae_u32)&exceptiontable010) + (i - 2) * 2); + exceptiontableinuse = (uae_u32)&exceptiontable010; } else { vbr[i] = (uae_u32)(((uae_u32)&exceptiontable020) + (i - 2) * 2); + exceptiontableinuse = (uae_u32)&exceptiontable020; } if (i >= 2 && i < 12) { error_vectors[i - 2] = vbr[i]; @@ -736,7 +747,9 @@ static uae_u8 *restore_memory(uae_u8 *p, int storedata) v &= 31; if (v == 0) v = 32; +#ifndef _MSC_VER xmemcpy(addr, p, v); +#endif p += v; break; } @@ -788,6 +801,10 @@ static uae_u8 *restore_data(uae_u8 *p) } else if (mode == CT_DSTADDR) { int size; p = restore_value(p, ®s.dstaddr, &size); + } else if (mode == CT_BRANCHTARGET) { + int size; + p = restore_value(p, ®s.branchtarget, &size); + regs.branchtarget_mode = *p++; } else if (mode < CT_AREG + 8) { int size; if ((v & CT_SIZE_MASK) == CT_SIZE_FPU) { @@ -874,54 +891,64 @@ static void addinfo_bytes(char *name, uae_u8 *src, uae_u32 address, int offset, extern uae_u16 disasm_instr(uae_u16 *, char *); -static void addinfo(void) +static void out_disasm(uae_u8 *mem) { - if (infoadded) - return; - infoadded = 1; - if (!dooutput) - return; - sprintf(outbp, "%lu:", testcnt); - outbp += strlen(outbp); - uae_u16 *code; #ifndef M68K uae_u16 swapped[16]; for (int i = 0; i < 16; i++) { - swapped[i] = (opcode_memory[i * 2 + 0] << 8) | (opcode_memory[i * 2 + 1] << 0); + swapped[i] = (mem[i * 2 + 0] << 8) | (mem[i * 2 + 1] << 0); } code = swapped; #else - code = (uae_u16*)opcode_memory; + code = (uae_u16*)mem; #endif - uae_u8 *p = opcode_memory; + uae_u8 *p = mem; int offset = 0; int lines = 0; while (lines++ < 10) { + if (!is_valid_test_addr((uae_u32)p) || !is_valid_test_addr((uae_u32)p + 1)) + break; tmpbuffer[0] = 0; int v = disasm_instr(code + offset, tmpbuffer); for (int i = 0; i < v; i++) { uae_u16 v = (p[i * 2 + 0] << 8) | (p[i * 2 + 1]); - sprintf(outbp, "%s%04x", i ? " " : (lines == 0 ? "\t\t" : "\t"), v); + sprintf(outbp, "%s %08lx %04x", i ? " " : (lines == 0 ? "\t\t" : "\t"), &p[i * 2], v); outbp += strlen(outbp); } sprintf(outbp, " %s\n", tmpbuffer); outbp += strlen(outbp); - if (v <= 0) + if (v <= 0 || code[offset] == 0x4afc) break; while (v > 0) { offset++; p += 2; - if (code[offset] == 0x4afc) { - v = -1; - break; - } v--; } if (v < 0) break; } *outbp = 0; +} + +static void addinfo(void) +{ + if (infoadded) + return; + infoadded = 1; + if (!dooutput) + return; + sprintf(outbp, "%lu:", testcnt); + outbp += strlen(outbp); + + out_disasm(opcode_memory); + + if (regs.branchtarget != 0xffffffff) { + out_disasm((uae_u8*)regs.branchtarget); + + } + + uae_u16 *code = (uae_u16*)opcode_memory; if (code[0] == 0x4e73 || code[0] == 0x4e74 || code[0] == 0x4e75) { addinfo_bytes("P", stackaddr, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); addinfo_bytes(" ", (uae_u8 *)stackaddr_ptr - SIZE_STORED_ADDRESS_OFFSET, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); @@ -1063,10 +1090,10 @@ static void hexdump(uae_u8 *p, int len) *outbp++ = '\n'; } -static uae_u8 last_exception[256]; +static uae_u8 last_exception[256], last_exception_extra; static int last_exception_len; -static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int sameexc, int *experr) +static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int *gotexcnum, int *experr) { int exclen = 0; uae_u8 *exc; @@ -1076,8 +1103,59 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, uae_u8 excdatalen = *p++; int size; - if (!excdatalen) + if (!excdatalen) { return p; + } + + if (excdatalen != 0xff) { + // check possible extra trace + last_exception_extra = *p++; + // some other exception + trace + if (last_exception_extra == 9) { + exceptioncount[last_exception_extra]++; + if (regs->tracecnt == 0) { + sprintf(outbp, "Expected trace exception but got none\n", regs->tracecnt); + outbp += strlen(outbp); + errors = 1; + *experr = 1; + } else { + uae_u16 sr = regs->tracedata[0]; + if (!(sr & 0x2000) || (sr | 0x2000 | 0xc000) != (regs->sr | 0x2000 | 0xc000)) { + sprintf(outbp, "Trace exception stack frame SR mismatch: %04x != %04x\n", sr, regs->sr); + outbp += strlen(outbp); + errors = 1; + *experr = 1; + } + uae_u32 ret = (regs->tracedata[1] << 16) | regs->tracedata[2]; + uae_u32 retv = exceptiontableinuse + (excnum - 2) * 2; + if (ret != retv) { + sprintf(outbp, "Trace exception stacked PC mismatch: %08lx != %08lx (%ld)\n", ret, retv, excnum); + outbp += strlen(outbp); + errors = 1; + *experr = 1; + } + } + } else if (!last_exception_extra && excnum != 9) { + if (regs->tracecnt > 0) { + sprintf(outbp, "Got unexpected trace exception\n"); + outbp += strlen(outbp); + errors = 1; + *experr = 1; + } + } else if (last_exception_extra) { + end_test(); + printf("Unsupported exception extra %d\n", last_exception_extra); + exit(0); + } + // trace only + if (excnum == 9 && *gotexcnum == 4) { + sp = (uae_u8 *)regs->tracedata; + *gotexcnum = 9; + } + } + + exceptioncount[*gotexcnum]++; + exc = last_exception; if (excdatalen != 0xff) { if (cpu_lvl == 0) { @@ -1184,7 +1262,7 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, } else { exclen = last_exception_len; } - if (exclen == 0 || !sameexc) + if (exclen == 0 || *gotexcnum != excnum) return p; if (memcmp(exc, sp, exclen)) { sprintf(outbp, "Exception %ld stack frame mismatch:\n", excnum); @@ -1277,7 +1355,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) if (ignore_errors) { if (exc) { - p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr); + p = validate_exception(&test_regs, p, exc, &cpuexc, &experr); } break; } @@ -1291,7 +1369,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) break; } if (exc) { - p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr); + p = validate_exception(&test_regs, p, exc, &cpuexc, &experr); } if (exc != cpuexc) { addinfo(); @@ -1359,6 +1437,8 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) sr_changed = 0; last_registers.sr = val; } else if (mode == CT_PC) { + volatile uae_u16 *c = (volatile uae_u16 *)0x100; + *c = 0x1234; uae_u32 val = last_registers.pc; p = restore_rel(p, &val, 0); pc_changed = 0; @@ -1575,6 +1655,7 @@ static void process_test(uae_u8 *p) regs.sr = interrupt_mask << 8; regs.srcaddr = 0xffffffff; regs.dstaddr = 0xffffffff; + regs.branchtarget = 0xffffffff; start_test(); @@ -1599,6 +1680,7 @@ static void process_test(uae_u8 *p) store_addr(regs.srcaddr, srcaddr); store_addr(regs.dstaddr, dstaddr); + store_addr(regs.branchtarget, branchtarget); xmemcpy(&last_registers, ®s, sizeof(struct registers)); @@ -1608,6 +1690,19 @@ static void process_test(uae_u8 *p) flushcache(cpu_lvl); uae_u32 pc = opcode_memory_addr; + uae_u32 originalopcodeend = 0x4afc4e71; + uae_u8 *opcode_memory_end = (uae_u8*)pc; + for (;;) { + if (gl(opcode_memory_end) == originalopcodeend) + break; + opcode_memory_end += 2; + if (opcode_memory_end > (uae_u8*)pc + 32) { + end_test(); + printf("Corrupted opcode memory\n"); + exit(0); + } + } + uae_u32 opcodeend = originalopcodeend; int extraccr = 0; @@ -1630,6 +1725,24 @@ static void process_test(uae_u8 *p) int maxccr = *p++; for (int ccr = 0; ccr < maxccr; ccr++) { + opcodeend = (opcodeend >> 16) | (opcodeend << 16); + pl(opcode_memory_end, opcodeend); + + if (regs.branchtarget != 0xffffffff) { + if (regs.branchtarget_mode == 1) { + uae_u32 bv = gl((uae_u8*)regs.branchtarget); + bv = (bv >> 16) | (bv << 16); + pl((uae_u8*)regs.branchtarget, bv); + } else if (regs.branchtarget_mode == 2) { + uae_u16 bv = gw((uae_u8 *)regs.branchtarget); + if (bv == 0x4e71) + bv = 0x4afc; + else + bv = 0x4e71; + pw((uae_u8 *)regs.branchtarget, bv); + } + } + regs.ssp = super_stack_memory - 0x80; regs.msp = super_stack_memory; regs.pc = opcode_memory_addr; @@ -1714,6 +1827,8 @@ static void process_test(uae_u8 *p) } p = validate_test(p, ignore_errors, ignore_sr); + if (regs.sr & 0x2000) + supercnt++; last_pc = last_registers.pc; last_fpiar = last_registers.fpiar; @@ -1743,6 +1858,8 @@ static void process_test(uae_u8 *p) } + pl(opcode_memory_end, originalopcodeend); + restoreahist(); } @@ -1754,7 +1871,6 @@ end: printf("\n"); printf(outbuffer); } - } static void freestuff(void) @@ -1888,6 +2004,8 @@ static int test_mnemo(const char *path, const char *opcode) printf("%s:\n", inst_name); testcnt = 0; + memset(exceptioncount, 0, sizeof(exceptioncount)); + supercnt = 0; for (;;) { printf("%s. %lu...\n", tfname, testcnt); @@ -1940,6 +2058,14 @@ static int test_mnemo(const char *path, const char *opcode) filecnt++; } + printf("S=%ld", supercnt); + for (int i = 0; i < 256; i++) { + if (exceptioncount[i]) { + printf(" E%02d=%ld", i, exceptioncount[i]); + } + } + printf("\n"); + if (!errors && !quit) { printf("All tests complete (total %lu).\n", testcnt); } diff --git a/gencpu.cpp b/gencpu.cpp index 2b25e5b3..e301630f 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -76,6 +76,7 @@ static int optimized_flags; #define GF_REVERSE 4096 #define GF_REVERSE2 8192 #define GF_SECONDWORDSETFLAGS 16384 +#define GF_SECONDEA 32768 typedef enum { @@ -197,6 +198,22 @@ static instr *curi_ce020; static bool no_prefetch_ce020; static bool got_ea_ce020; +// 68020-30 needs different implementation than 68040/060 +static void next_level_040_to_030(void) +{ + if (cpu_level >= 4) { + if (next_cpu_level < 4) + next_cpu_level = 4 - 1; + } +} + +// 68000 <> 68010 +static void next_level_000(void) +{ + if (next_cpu_level < 0) + next_cpu_level = 0; +} + static void fpulimit (void) { if (limit_braces) @@ -520,7 +537,7 @@ static void check_bus_error_ins(int offset) sprintf(bus_error_text, "\t\texception2_fetch(%s, m68k_getpci() + %d);\n", opcode, offset); } -static void check_prefetch_bus_error(int offset) +static void check_prefetch_bus_error(int offset, int secondprefetchmode) { if (!using_bus_error) return; @@ -530,7 +547,7 @@ static void check_prefetch_bus_error(int offset) else offset = 2; // full prefetch: opcode field is zero - if (offset == 2) { + if ((offset == 2 && !secondprefetchmode) || secondprefetchmode > 0) { bus_error_specials = 1; } } @@ -739,7 +756,7 @@ static void fill_prefetch_2 (void) if (!using_prefetch) return; printf ("\t%s (%d);\n", prefetch_word, m68k_pc_offset + 2); - check_prefetch_bus_error(m68k_pc_offset + 2); + check_prefetch_bus_error(m68k_pc_offset + 2, 0); did_prefetch = 1; ir2irc = 0; count_read++; @@ -750,7 +767,7 @@ static void fill_prefetch_1 (int o) { if (using_prefetch) { printf ("\t%s (%d);\n", prefetch_word, o); - check_prefetch_bus_error(o); + check_prefetch_bus_error(o, 0); did_prefetch = 1; ir2irc = 0; count_read++; @@ -763,7 +780,7 @@ static void fill_prefetch_1_empty(int o) { if (using_prefetch) { printf("\t%s (%d);\n", prefetch_word, o); - check_prefetch_bus_error(o ? -2 : -1); + check_prefetch_bus_error(o ? -2 : -1, 0); did_prefetch = 1; ir2irc = 0; count_read++; @@ -866,7 +883,7 @@ static void fill_prefetch_0 (void) if (!using_prefetch) return; printf ("\t%s (0);\n", prefetch_word); - check_prefetch_bus_error(0); + check_prefetch_bus_error(0, 0); did_prefetch = 1; ir2irc = 0; count_read++; @@ -879,7 +896,7 @@ static void dummy_prefetch (void) if (!using_prefetch) return; printf ("\t%s (%d);\n", srcwi, o); - check_prefetch_bus_error(o); + check_prefetch_bus_error(o, 0); count_read++; insn_n_cycles += 4; } @@ -888,6 +905,9 @@ static void fill_prefetch_next (void) { if (using_prefetch) { irc2ir(); + if (using_bus_error) { + printf("\topcode = regs.ir;\n"); + } fill_prefetch_1(m68k_pc_offset + 2); } // if (using_prefetch_020) { @@ -1273,6 +1293,11 @@ static void move_68000_bus_error(int offset, int size, int *setapdi, int *fcmode // instruction opcode and Instruction/Not field is one! printf("\t\topcode = regs.ir;\n"); *fcmodeflags |= 0x08; // "Not instruction" = 1 + + } else if (dmode == Aipi) { + + // move.w x,(an)+: an is not increased + printf("\t\tm68k_areg(regs, dstreg) -= 2;\n"); } } else if (size == sz_long && ((offset == 0 && dmode != Apdi) || (offset == 2 && dmode == Apdi))) { @@ -1395,36 +1420,39 @@ static void move_68000_bus_error(int offset, int size, int *setapdi, int *fcmode static char const *bus_error_reg; static int bus_error_reg_add; -static void do_bus_error_fixes(const char *name, int offset, int write) +static int do_bus_error_fixes(const char *name, int offset, int write) { switch (bus_error_reg_add) { case 1: - if (g_instr->mnemo == i_CMPM && write) { - ; - } else { + case -1: + if (g_instr->mnemo == i_CMPM && bus_error_reg_add > 0) { + // CMPM.B (an)+,(an)+: first increased normally, second not increased printf("\t\tm68k_areg(regs, %s) += areg_byteinc[%s] + %d;\n", bus_error_reg, bus_error_reg, offset); } break; case 2: + case -2: printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset); break; case 3: - if (g_instr->mnemo == i_CMPM) { - // CMPM.L (an)+,(an)+: increased by 2 + case -3: + if (g_instr->mnemo == i_CMPM && bus_error_reg_add > 0) { + // CMPM.L (an)+,(an)+: first increased normally, second not increased printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset); } break; case 4: + case -4: 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; + offset += 2; } else { printf("\t\tm68k_areg (regs, %s) = %sa;\n", bus_error_reg, name); } break; } - + return offset; } static void check_bus_error(const char *name, int offset, int write, int size, const char *writevar, int fc) @@ -1435,6 +1463,8 @@ static void check_bus_error(const char *name, int offset, int write, int size, c if (!using_prefetch && !using_ce) return; + next_level_000(); + uae_u32 extra = fc & 0xffff0000; fc &= 0xffff; @@ -1456,7 +1486,7 @@ static void check_bus_error(const char *name, int offset, int write, int size, c move_68000_bus_error(offset, g_instr->size, &setapdiback, &fc); } - do_bus_error_fixes(name, offset, write); + offset = do_bus_error_fixes(name, offset, write); if (g_instr->mnemo == i_BTST && (g_instr->dmode == PC16 || g_instr->dmode == PC8r)) { // BTST special case where destination is read access @@ -1476,9 +1506,9 @@ static void check_bus_error(const char *name, int offset, int write, int size, c printf("\t\topcode |= 0x%x;\n", extra); } - if (cpu_level == 0 && write) { - printf("\t\topcode = regs.irc;\n"); - } + //if (cpu_level == 0 && write) { + // printf("\t\topcode = regs.irc;\n"); + //} if (write) { printf("\t\texception2_write(opcode, %sa + %d, %d, %s, %d);\n", @@ -1944,21 +1974,6 @@ static int gence020cycles_jea (instr *curi, amodes mode) return oph; } -// 68020-30 needs different implementation than 68040/060 -static void next_level_040_to_030(void) -{ - if (cpu_level >= 4) { - if (next_cpu_level < 4) - next_cpu_level = 4 - 1; - } -} - -static void next_level_000 (void) -{ - if (next_cpu_level < 0) - next_cpu_level = 0; -} - static void maybeaddop_ce020 (int flags) { if (flags & GF_OPCE020) @@ -1996,10 +2011,11 @@ static void move_68000_address_error(int size, int *setapdi, int *fcmodeflags) break; } if (dmode == Apdi) { - // this is buggy, address error stack frame opcode field contains next - // instruction opcode and Instruction/Not field is one! - printf("\t\topcode = regs.irc;\n"); - *fcmodeflags |= 0x08; // "Not instruction" = 1 + // partial prefetch already done + printf("\t\tregs.ir = regs.irc;\n"); + // if trace, I/N is also set + printf("\t\tif(regs.t1) opcode |= 0x10000;\n"); + } if (set_ccr) { printf("\t\tccr_68000_word_move_ae_normal((uae_s16)(src));\n"); @@ -2399,6 +2415,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char } else if (mode == Apdi) { bus_error_reg_add = 4; } + if (flags & GF_SECONDEA) { + bus_error_reg_add = -bus_error_reg_add; + } } exception_pc_offset = 0; @@ -2418,10 +2437,12 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char int fcmodeflags = 0; int exp3rw = getv == 2; + next_level_000(); + printf("\tif (%sa & 1) {\n", name); if (cpu_level == 1) { - if (bus_error_reg_add == 4) + if (abs(bus_error_reg_add) == 4) bus_error_reg_add = 0; // 68010 CLR : pre and post are not added yet if (g_instr->mnemo == i_CLR) { @@ -2686,7 +2707,7 @@ static void genamodedual (instr *curi, amodes smode, const char *sreg, wordsizes subhead_ce020 = subhead; curi_ce020 = curi; genamode3 (curi, smode, sreg, ssize, sname, sgetv, 0, sflags); - genamode3 (NULL, dmode, dreg, dsize, dname, dgetv, 0, dflags | (eadmode == true ? GF_OPCE020 : 0)); + genamode3 (NULL, dmode, dreg, dsize, dname, dgetv, 0, dflags | (eadmode == true ? GF_OPCE020 : 0) | GF_SECONDEA); if (eadmode == false) maybeaddop_ce020 (GF_OPCE020); } @@ -3246,21 +3267,25 @@ static void genmovemel_ce (uae_u16 opcode) start_brace(); if (table68k[opcode].size == sz_long) { printf("\twhile (dmask) {\n"); - printf("\t\tuae_u32 v = %s (srca) << 16;\n", srcw); + printf("\t\tuae_u32 v = (%s(srca) << 16) | (m68k_dreg(regs, movem_index1[dmask]) & 0xffff);\n", srcw); check_bus_error("src", 0, 0, 1, NULL, 1); - printf("\t\tv |= %s (srca + 2);\n", srcw); + printf("\t\tm68k_dreg(regs, movem_index1[dmask]) = v;\n"); + printf("\t\tv &= 0xffff0000;\n"); + printf("\t\tv |= % s(srca + 2); \n", srcw); check_bus_error("src", 2, 0, 1, NULL, 1); - printf("\t\tm68k_dreg (regs, movem_index1[dmask]) = v;\n"); + printf("\t\tm68k_dreg(regs, movem_index1[dmask]) = v;\n"); printf("\t\tsrca += %d;\n", size); printf("\t\tdmask = movem_next[dmask];\n"); addcycles000_nonce("\t\t", 8); printf("\t}\n"); printf("\twhile (amask) {\n"); - printf("\t\tuae_u32 v = %s (srca) << 16;\n", srcw); + printf("\t\tuae_u32 v = (%s(srca) << 16) | (m68k_areg(regs, movem_index1[amask]) & 0xffff);\n", srcw); check_bus_error("src", 0, 0, 1, NULL, 1); - printf("\t\tv |= %s (srca + 2);\n", srcw); + printf("\t\tm68k_areg(regs, movem_index1[amask]) = v;\n"); + printf("\t\tv &= 0xffff0000;\n"); + printf("\t\tv |= %s(srca + 2);\n", srcw); check_bus_error("src", 2, 0, 1, NULL, 1); - printf("\t\tm68k_areg (regs, movem_index1[amask]) = v;\n"); + printf("\t\tm68k_areg(regs, movem_index1[amask]) = v;\n"); printf("\t\tsrca += %d;\n", size); printf("\t\tamask = movem_next[amask];\n"); addcycles000_nonce("\t\t", 8); @@ -4062,7 +4087,7 @@ static void gen_opcode (unsigned int opcode) if (!isreg (curi->smode)) addcycles000 (2); genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_REVERSE); - genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW); + genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA); fill_prefetch_next (); if (curi->size == sz_long && isreg (curi->smode)) addcycles000 (4); @@ -4160,7 +4185,7 @@ static void gen_opcode (unsigned int opcode) if (!isreg (curi->smode)) addcycles000 (2); genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_REVERSE); - genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW); + genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA); fill_prefetch_next (); if (curi->size == sz_long && isreg (curi->smode)) addcycles000 (4); @@ -5089,75 +5114,89 @@ static void gen_opcode (unsigned int opcode) next_level_040_to_030(); break; case i_JSR: - // possible idle cycle, prefetch from new address, stack high return addr, stack low, prefetch - no_prefetch_ce020 = true; - genamode (curi, curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA|GF_NOREFILL); - start_brace (); - printf("\tuaecptr oldpc = %s;\n", getpc); - printf("\tuaecptr nextpc = oldpc + %d;\n", m68k_pc_offset); - 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}\n"); - need_endlabel = 1; - } - if (using_mmu) { - printf ("\t%s (m68k_areg (regs, 7) - 4, nextpc);\n", dstl); - printf ("\tm68k_areg (regs, 7) -= 4;\n"); - setpc ("srca"); - clear_m68k_offset(); - } else { - if (curi->smode == Ad16 || curi->smode == absw || curi->smode == PC16) - addcycles000 (2); - if (curi->smode == Ad8r || curi->smode == PC8r) { - addcycles000 (6); - if (cpu_level <= 1 && using_prefetch) - printf ("\tnextpc += 2;\n"); - } - setpc ("srca"); - clear_m68k_offset(); - 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; - } - fill_prefetch_1(0); - if (cpu_level < 4) - printf("\tm68k_areg (regs, 7) -= 4;\n"); + { + // possible idle cycle, prefetch from new address, stack high return addr, stack low, prefetch + no_prefetch_ce020 = true; + genamode(curi, curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA | GF_NOREFILL); + start_brace(); + printf("\tuaecptr oldpc = %s;\n", getpc); + printf("\tuaecptr nextpc = oldpc + %d;\n", m68k_pc_offset); if (using_exception_3 && cpu_level <= 1) { - printf("\tif (m68k_areg(regs, 7) & 1) {\n"); - printf("\t\texception3_write(opcode, m68k_areg(regs, 7), 1, m68k_areg(regs, 7) >> 16, 1);\n"); + printf("\tif (srca & 1) {\n"); + printf("\t\texception3i (opcode, srca);\n"); printf("\t\tgoto %s;\n", endlabelstr); printf("\t}\n"); need_endlabel = 1; } - if (using_ce || using_prefetch) { - printf("\tuaecptr dsta = m68k_areg(regs, 7);\n"); - printf("\t%s(dsta, nextpc >> 16);\n", dstw); - check_bus_error("dst", 0, 1, 1, "nextpc >> 16", 1); - printf("\t%s(dsta + 2, nextpc);\n", dstw); - check_bus_error("dst", 2, 1, 1, "nextpc", 1); + if (using_mmu) { + printf("\t%s (m68k_areg (regs, 7) - 4, nextpc);\n", dstl); + printf("\tm68k_areg (regs, 7) -= 4;\n"); + setpc("srca"); + clear_m68k_offset(); } else { + if (curi->smode == Ad16 || curi->smode == absw || curi->smode == PC16) + addcycles000(2); + if (curi->smode == Ad8r || curi->smode == PC8r) { + addcycles000(6); + if (cpu_level <= 1 && using_prefetch) + printf("\tnextpc += 2;\n"); + } + setpc("srca"); + clear_m68k_offset(); + 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; + } + fill_prefetch_1(0); if (cpu_level < 4) - printf("\t%s(m68k_areg(regs, 7), nextpc);\n", dstl); - else - printf("\t%s(m68k_areg(regs, 7) - 4, nextpc);\n", dstl); + printf("\tm68k_areg (regs, 7) -= 4;\n"); + if (using_exception_3 && cpu_level <= 1) { + printf("\tif (m68k_areg(regs, 7) & 1) {\n"); + printf("\t\texception3_write(opcode, m68k_areg(regs, 7), 1, m68k_areg(regs, 7) >> 16, 1);\n"); + printf("\t\tgoto %s;\n", endlabelstr); + printf("\t}\n"); + need_endlabel = 1; + } + if (using_ce || using_prefetch) { + printf("\tuaecptr dsta = m68k_areg(regs, 7);\n"); + printf("\t%s(dsta, nextpc >> 16);\n", dstw); + check_bus_error("dst", 0, 1, 1, "nextpc >> 16", 1); + printf("\t%s(dsta + 2, nextpc);\n", dstw); + check_bus_error("dst", 2, 1, 1, "nextpc", 1); + } else { + if (cpu_level < 4) + printf("\t%s(m68k_areg(regs, 7), nextpc);\n", dstl); + else + printf("\t%s(m68k_areg(regs, 7) - 4, nextpc);\n", dstl); + } + if (cpu_level >= 4) + printf("\tm68k_areg (regs, 7) -= 4;\n"); + if (using_debugmem) { + printf("\tif (debugmem_trace)\n"); + printf("\t\tbranch_stack_push(oldpc, nextpc);\n"); + } } - if (cpu_level >= 4) - printf("\tm68k_areg (regs, 7) -= 4;\n"); - if (using_debugmem) { - printf("\tif (debugmem_trace)\n"); - printf("\t\tbranch_stack_push(oldpc, nextpc);\n"); + count_write += 2; + fill_prefetch_full_020(); + 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"); + printf("\t%s (%d);\n", prefetch_word, 2); + check_prefetch_bus_error(-2, sp); + did_prefetch = 1; + ir2irc = 0; + count_read++; + insn_n_cycles += 4; + } else { + fill_prefetch_next_empty(); } + branch_inst = 1; + next_level_040_to_030(); } - count_write += 2; - fill_prefetch_full_020 (); - fill_prefetch_next_empty(); - branch_inst = 1; - next_level_040_to_030(); break; case i_JMP: no_prefetch_ce020 = true; @@ -5175,7 +5214,21 @@ static void gen_opcode (unsigned int opcode) addcycles000 (6); setpc ("srca"); clear_m68k_offset(); - fill_prefetch_full (); + if (using_prefetch || using_ce) { + printf("\t%s (%d);\n", prefetch_word, 0); + check_prefetch_bus_error(-1, 0); + 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"); + check_prefetch_bus_error(-2, sp); + did_prefetch = 1; + ir2irc = 0; + count_read++; + insn_n_cycles += 4; + } else { + fill_prefetch_full(); + } branch_inst = 1; break; case i_BSR: diff --git a/include/newcpu.h b/include/newcpu.h index 4c8a950f..8b624501 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -695,6 +695,7 @@ extern void Exception_build_68000_address_error_stack_frame(uae_u16 mode, uae_u1 extern uae_u32 exception_pc(int nr); extern void cpu_restore_fixup(void); extern bool privileged_copro_instruction(uae_u16 opcode); +extern bool generates_group1_exception(uae_u16 opcode); void ccr_68000_long_move_ae_LZN(uae_s32 src); void ccr_68000_long_move_ae_LN(uae_s32 src); diff --git a/newcpu.cpp b/newcpu.cpp index 9da12a18..65e486a2 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -80,6 +80,8 @@ static bool last_notinstruction_for_exception_3; /* set when writing exception stack frame */ static int exception_in_exception; +static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc); + int mmu_enabled, mmu_triggered; int cpu_cycles; int bus_error_offset; @@ -2651,7 +2653,7 @@ static void Exception_mmu030 (int nr, uaecptr oldpc) if (nr == 2 || nr == 3) cpu_halt (CPU_HALT_DOUBLE_FAULT); else - exception3_read(regs.ir, newpc, 1, 1); + exception3_read_special(regs.ir, newpc, 1, 1); return; } if (interrupt) @@ -2717,7 +2719,7 @@ static void Exception_mmu (int nr, uaecptr oldpc) if (nr == 2 || nr == 3) cpu_halt (CPU_HALT_DOUBLE_FAULT); else - exception3_read(regs.ir, newpc, 2, 1); + exception3_read_special(regs.ir, newpc, 2, 1); return; } @@ -2861,7 +2863,7 @@ static void Exception_normal (int nr) if (nr == 2 || nr == 3) cpu_halt (CPU_HALT_DOUBLE_FAULT); else - exception3_read(regs.ir, newpc, 2, 1); + exception3_read_special(regs.ir, newpc, 2, 1); return; } m68k_setpc (newpc); @@ -6860,13 +6862,37 @@ void exception3_notinstruction(uae_u32 opcode, uaecptr addr) { exception3f (opcode, addr, true, false, true, 0xffffffff, 1, false, -1); } +static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc) +{ + exception3f(opcode, addr, false, 0, false, 0xffffffff, size, false, fc); +} void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc) { - exception3f (opcode, addr, false, 0, false, 0xffffffff, size, false, fc); + bool ni = false; + if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) { + if (generates_group1_exception(regs.ir)) { + ni = true; + fc = -1; + } + if (opcode & 0x100000) + ni = true; + opcode = regs.ir; + } + exception3f (opcode, addr, false, 0, ni, 0xffffffff, size, false, fc); } void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc) { - exception3f (opcode, addr, true, 0, false, 0xffffffff, size, false, fc); + bool ni = false; + if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) { + if (generates_group1_exception(regs.ir)) { + ni = true; + fc = -1; + } + if (opcode & 0x100000) + ni = true; + opcode = regs.ir; + } + exception3f (opcode, addr, true, 0, ni, 0xffffffff, size, false, fc); regs.write_buffer = val; } void exception3i (uae_u32 opcode, uaecptr addr) @@ -6889,6 +6915,14 @@ void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc) last_size_for_exception_3 = size; last_di_for_exception_3 = 1; cpu_bus_error = 0; + + if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) { + if (generates_group1_exception(regs.ir)) { + last_notinstruction_for_exception_3 = true; + fc = -1; + } + last_op_for_exception_3 = regs.ir; + } } void exception2(uaecptr addr, bool read, int size, uae_u32 fc) diff --git a/newcpu_common.cpp b/newcpu_common.cpp index 74499e3d..56f18f36 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -1642,3 +1642,21 @@ bool privileged_copro_instruction(uae_u16 opcode) } return false; } + +bool generates_group1_exception(uae_u16 opcode) +{ + struct instr *table = &table68k[opcode]; + // illegal/a-line/f-line? + if (table->mnemo == i_ILLG) + return true; + // privilege violation? + if (!regs.s) { + if (table->plev == 1 && currprefs.cpu_model > 68000) + return true; + if (table->plev == 2) + return true; + if (table->plev == 3 && table->size == sz_word) + return true; + } + return false; +}