From: Toni Wilen Date: Sun, 31 May 2020 17:04:56 +0000 (+0300) Subject: CPU tester updates X-Git-Tag: 4400~16 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=f68c3400955eb82ea4aa0208bafec33e47ac1a0b;p=francis%2Fwinuae.git CPU tester updates --- diff --git a/cputest.cpp b/cputest.cpp index 1d9261f4..ee106476 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -132,6 +132,7 @@ static int test_exception_3_w; static int test_exception_3_fc; static int test_exception_3_size; static int test_exception_3_di; +static uae_u16 test_exception_3_sr; static int test_exception_opcode; static uae_u32 trace_store_pc; static uae_u16 trace_store_sr; @@ -225,8 +226,12 @@ static bool valid_address(uaecptr addr, int size, int rwp) if (addr < test_low_memory_start || test_low_memory_start == 0xffffffff) goto oob; // exception vectors needed during tests - if ((addr + size >= 0x08 && addr < 0x30 || (addr + size >= 0x80 && addr < 0xc0)) && currprefs.cpu_model == 68000) - goto oob; + if (currprefs.cpu_model == 68000) { + if ((addr + size >= 0x08 && addr < 0x30 || (addr + size >= 0x80 && addr < 0xc0))) + goto oob; + if (feature_interrupts && (addr + size >= 0x64 && addr < 0x7c)) + goto oob; + } if (addr + size >= test_low_memory_end) goto oob; if (w && lmem_rom) @@ -445,24 +450,32 @@ uae_u16 get_word_test_prefetch(int o) return get_iword_test(m68k_getpci() + o); } -static void previoussame(uaecptr addr, int size) +static void previoussame(uaecptr addr, int size, uae_u32 *old) { if (!ahcnt_current || ahcnt_current == ahcnt_written) return; // Move from SR does two writes to same address. // Loop mode can write different values to same address. // Mark old values as do not save. + // Also loop mode test can do multi writes and it needs original value. + bool gotold = false; for (int i = ahcnt_written; i < ahcnt_current; i++) { struct accesshistory *ah = &ahist[i]; if (ah->size == size && ah->addr == addr) { ah->donotsave = true; - } - if (size == sz_long) { - if (ah->size == sz_word && ah->addr == addr) { - ah->donotsave = true; + if (!gotold) { + *old = ah->oldval; + gotold = true; } - if (ah->size == sz_word && ah->addr == addr + 2) { - ah->donotsave = true; + } + if (cpu_lvl < 2) { + if (size == sz_long) { + if (ah->size == sz_word && ah->addr == addr) { + ah->donotsave = true; + } + if (ah->size == sz_word && ah->addr == addr + 2) { + ah->donotsave = true; + } } } } @@ -475,7 +488,8 @@ 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, 2); if (!out_of_test_space && !noaccesshistory && !hardware_bus_error_fake) { - previoussame(addr, sz_byte); + uae_u32 old = p[0]; + previoussame(addr, sz_byte, &old); if (ahcnt_current >= MAX_ACCESSHIST) { wprintf(_T(" ahist overflow!")); abort(); @@ -483,7 +497,7 @@ void put_byte_test(uaecptr addr, uae_u32 v) struct accesshistory *ah = &ahist[ahcnt_current++]; ah->addr = addr; ah->val = v & 0xff; - ah->oldval = *p; + ah->oldval = old & 0xff; ah->size = sz_byte; ah->donotsave = false; } @@ -503,7 +517,8 @@ void put_word_test(uaecptr addr, uae_u32 v) } else { uae_u8 *p = get_addr(addr, 2, 2); if (!out_of_test_space && !noaccesshistory && !hardware_bus_error_fake) { - previoussame(addr, sz_word); + uae_u32 old = (p[0] << 8) | p[1]; + previoussame(addr, sz_word, &old); if (ahcnt_current >= MAX_ACCESSHIST) { wprintf(_T(" ahist overflow!")); abort(); @@ -511,7 +526,7 @@ void put_word_test(uaecptr addr, uae_u32 v) struct accesshistory *ah = &ahist[ahcnt_current++]; ah->addr = addr; ah->val = v & 0xffff; - ah->oldval = (p[0] << 8) | p[1]; + ah->oldval = old & 0xffff; ah->size = sz_word; ah->donotsave = false; } @@ -536,7 +551,8 @@ void put_long_test(uaecptr addr, uae_u32 v) } else { uae_u8 *p = get_addr(addr, 4, 2); if (!out_of_test_space && !noaccesshistory && !hardware_bus_error_fake) { - previoussame(addr, sz_long); + uae_u32 old = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + previoussame(addr, sz_long, &old); if (ahcnt_current >= MAX_ACCESSHIST) { wprintf(_T(" ahist overflow!")); abort(); @@ -544,7 +560,7 @@ void put_long_test(uaecptr addr, uae_u32 v) struct accesshistory *ah = &ahist[ahcnt_current++]; ah->addr = addr; ah->val = v; - ah->oldval = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + ah->oldval = old; ah->size = sz_long; ah->donotsave = false; } @@ -935,7 +951,6 @@ void MakeFromSR_x(int t0trace) // Always trace if Tx bits were already set, even if this SR modification cleared them. activate_trace(); } - } void REGPARAM2 MakeFromSR_T0(void) @@ -1074,7 +1089,7 @@ static void doexcstack(void) MakeSR(); regs.sr |= 0x2000; - regs.sr &= ~0x8000; + regs.sr &= ~(0x8000 | 0x4000); MakeFromSR(); regs.pc = original_exception * 4; @@ -1100,6 +1115,9 @@ static void doexcstack(void) } else { flags |= 0x20000; } + if (cpu_lvl < 5) { + regs.m = 0; + } } // set I/N if original exception was group 1 exception. @@ -1142,10 +1160,11 @@ void REGPARAM2 op_unimpl(uae_u32 opcode) } uae_u32 REGPARAM2 op_unimpl_1(uae_u32 opcode) { - if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060) + if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060) { op_illg(opcode); - else + } else { op_unimpl(opcode); + } return 0; } uae_u32 REGPARAM2 op_illg(uae_u32 opcode) @@ -1206,7 +1225,7 @@ void exception2_read(uae_u32 opcode, uaecptr addr, int size, int fc) test_exception_addr = addr; test_exception_opcode = opcode; test_exception_3_fc = fc; - test_exception_3_size = size; + test_exception_3_size = size & 15; test_exception_3_di = 1; if (currprefs.cpu_model == 68000) { @@ -1229,12 +1248,16 @@ void exception2_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int f test_exception_addr = addr; test_exception_opcode = opcode; test_exception_3_fc = fc; - test_exception_3_size = size; - if (size == sz_byte) { - regs.write_buffer &= 0xff00; - regs.write_buffer |= val & 0xff; - } else { + test_exception_3_size = size & 15; + if (size & 0x100) { regs.write_buffer = val; + } else { + if (size == sz_byte) { + regs.write_buffer &= 0xff00; + regs.write_buffer |= val & 0xff; + } else { + regs.write_buffer = val; + } } test_exception_3_di = 1; @@ -1258,7 +1281,7 @@ void exception3_read(uae_u32 opcode, uae_u32 addr, int size, int fc) test_exception_addr = addr; test_exception_opcode = opcode; test_exception_3_fc = fc; - test_exception_3_size = size; + test_exception_3_size = size & 15; test_exception_3_di = 1; if (currprefs.cpu_model == 68000) { @@ -1284,7 +1307,7 @@ void exception3_write(uae_u32 opcode, uae_u32 addr, int size, uae_u32 val, int f test_exception_addr = addr; test_exception_opcode = opcode; test_exception_3_fc = fc; - test_exception_3_size = size; + test_exception_3_size = size & 15; regs.write_buffer = val; test_exception_3_di = 1; @@ -1342,6 +1365,28 @@ void exception3_read_prefetch(uae_u32 opcode, uae_u32 addr) doexcstack(); } +void exception3_read_prefetch_68040bug(uae_u32 opcode, uae_u32 addr, uae_u16 secondarysr) +{ + if (cpu_lvl == 1) { + get_word_test(addr & ~1); + } else { + add_memory_cycles(1); + } + exception3_pc_inc(); + + test_exception = 3; + test_exception_3_w = 0; + test_exception_addr = addr; + test_exception_opcode = opcode | 0x10000; + test_exception_3_fc = 2; + test_exception_3_size = sz_word; + test_exception_3_di = 0; + test_exception_3_sr = secondarysr; + + doexcstack(); +} + + void exception3_read_access2(uae_u32 opcode, uae_u32 addr, int size, int fc) { get_word_test(addr & ~1); @@ -1385,9 +1430,11 @@ void REGPARAM2 Exception_cpu(int n) test_exception_opcode = -1; bool t0 = currprefs.cpu_model >= 68020 && regs.t0 && !regs.t1; - // check T0 trace - if (t0) { - activate_trace(); + if (n != 14) { + // check T0 trace + if (t0) { + activate_trace(); + } } doexcstack(); } @@ -1629,6 +1676,8 @@ static bool regchange(int reg, uae_u32 *regs) if (generate_address_mode && reg >= 8) return false; + if (feature_loop_mode_register == reg) + return false; // don't unnecessarily modify static forced register for (int i = 0; i < regdatacnt; i++) { @@ -1703,6 +1752,9 @@ static bool regchange(int reg, uae_u32 *regs) } break; case 11: + if (feature_loop_mode && !feature_loop_mode_68010) { + return false; + } v ^= 0x8000; break; case 12: @@ -2007,7 +2059,7 @@ static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old, { if (!len) return dst; - if (len > 32) { + if (len > 256) { wprintf(_T(" too long byte count!\n")); abort(); } @@ -2048,7 +2100,12 @@ static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old, if (header) { *dst++ = CT_MEMWRITES | CT_PC_BYTES; } - *dst++ = (offset << 5) | (uae_u8)(len == 32 ? 0 : len); + if (len > 32) { + *dst++ = (offset << 5) | 31; + *dst++ = len; + } else { + *dst++ = (offset << 5) | (uae_u8)(len == 32 ? 0 : len); + } for (int i = 0; i < len; i++) { *dst++ = get_byte_test(start); start++; @@ -2145,7 +2202,7 @@ static void markfile(const TCHAR *dir) } } -static void save_data(uae_u8 *dst, const TCHAR *dir) +static void save_data(uae_u8 *dst, const TCHAR *dir, int size) { TCHAR path[1000]; @@ -2213,15 +2270,16 @@ static void save_data(uae_u8 *dst, const TCHAR *dir) fwrite(data, 1, 2, f); fclose(f); filecount++; - save_data(dst, dir); + save_data(dst, dir, size); } else { uae_u8 data[4]; pl(data, DATA_VERSION); fwrite(data, 1, 4, f); pl(data, (uae_u32)starttime); fwrite(data, 1, 4, f); - pl(data, 0); + pl(data, (size & 3)); fwrite(data, 1, 4, f); + pl(data, 0); fwrite(data, 1, 4, f); *dst++ = CT_END_FINISH; *dst++ = filecount; @@ -2762,7 +2820,6 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str } else { if (opcodecnt == 1) { // STOP #xxxx: test all combinations - // (also includes RTD) if (dp->mnemo == i_LPSTOP) { uae_u16 lp = 0x01c0; if (imm16_cnt & (0x40 | 0x80)) { @@ -2818,7 +2875,8 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str else *isconstant = -1; } else if (dp->mnemo == i_BSR || dp->mnemo == i_DBcc || dp->mnemo == i_Bcc || - dp->mnemo == i_ORSR || dp->mnemo == i_ANDSR || dp->mnemo == i_EORSR) { + dp->mnemo == i_ORSR || dp->mnemo == i_ANDSR || dp->mnemo == i_EORSR || + dp->mnemo == i_RTD) { // don't try to test all 65536 possibilies.. uae_u16 i16 = imm16_cnt; put_word_test(pc, imm16_cnt); @@ -3539,16 +3597,29 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i static const int interrupt_levels[] = { - 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 0 + 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6 }; +static bool check_interrupts(void) +{ + if (feature_interrupts) { + int ic = interrupt_count & 15; + int lvl = interrupt_levels[ic]; + if (lvl > 0 && lvl > feature_min_interrupt_mask) { + Exception(lvl + 24); + return true; + } + } + return false; +} + static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) { uae_u16 opc = regs.ir; uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0); uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0); - if (opc == 0xf202 - && opw1 == 0x5225 + if (opc == 0x4ed6 + //&& opw1 == 0x5225 //&& opw2 == 0x4afc ) printf(""); @@ -3584,7 +3655,12 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) cpu_cycles = 0; regs.loop_mode = 0; - int cnt = (feature_loop_mode + 1) * 2; + int cnt = 2; + if (feature_loop_mode_68010) { + cnt = (feature_loop_mode + 1) * 2; + } else if (feature_loop_mode) { + cnt = (feature_loop_mode + 1) * 20; + } if (multi_mode) cnt = 100; @@ -3605,15 +3681,9 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) do_trace(); } - if (feature_interrupts) { - int ic = interrupt_count; - interrupt_count++; - interrupt_count &= 15; - int lvl = interrupt_levels[ic]; - if (lvl > 0 && lvl > feature_min_interrupt_mask) { - Exception(lvl + 24); + if (cpu_lvl <= 1) { + if (check_interrupts()) break; - } } regs.instruction_pc = regs.pc; @@ -3659,10 +3729,15 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) break; } + if (cpu_lvl >= 2) { + if (check_interrupts()) + break; + } + if (regs.pc == endpc || regs.pc == targetpc) { // 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) { + if (SPCFLAG_DOTRACE && !test_exception && trace_store_pc == 0xffffffffff) { Exception(9); } break; @@ -3700,7 +3775,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) cnt--; - if (!feature_loop_mode && !multi_mode && opc != 0x4e71) { + if (!feature_loop_mode && !multi_mode && opc != NOP_OPCODE) { wprintf(_T(" Test instruction didn't finish in single step in non-loop mode!?\n")); abort(); } @@ -4105,6 +4180,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int count = 0; + if (feature_loop_mode && !feature_loop_mode_68010) { + registers[8 + 3] = 0; + } + registers[8 + 6] = opcode_memory_start - 0x100; registers[15] = user_stack_memory_use; @@ -4169,10 +4248,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi dst = storage_buffer; - if (low_memory) { + if (low_memory && low_memory_size != 0xffffffff) { memcpy(low_memory, low_memory_temp, low_memory_size); } - if (high_memory) { + if (high_memory && high_memory_size != 0xffffffff) { memcpy(high_memory, high_memory_temp, high_memory_size); } memcpy(test_memory, test_memory_temp, test_memory_size); @@ -4188,6 +4267,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi uae_u32 target_ea_bak[3], target_address_bak, target_opcode_address_bak; for (;;) { + int got_something = 0; target_ea_bak[0] = target_ea[0]; target_ea_bak[1] = target_ea[1]; @@ -4216,7 +4296,14 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (feature_loop_mode) { cur_regs.regs[feature_loop_mode_register] &= 0xffff0000; - cur_regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1; + if (feature_loop_mode_68010) { + cur_regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1; + } else { + // loop register is used as index in some addressing modes but + // we don't handle situation where multiple memory writes access same + // memory location using different access sizes. + cur_regs.regs[feature_loop_mode_register] |= feature_loop_mode * 64 - 1; + } } for (int i = 0; i < MAX_REGISTERS; i++) { @@ -4273,6 +4360,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi continue; } + got_something = 1; + target_ea[0] = target_ea_bak[0]; target_ea[1] = target_ea_bak[1]; target_ea[2] = target_ea_bak[2]; @@ -4344,7 +4433,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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_original = (ILLG_OPCODE << 16) | NOP_OPCODE; uae_u32 branch_target_data = branch_target_data_original; int srcregused = -1; @@ -4389,7 +4478,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi pc -= 2; int cnt = 0; while (pc - 2 != opcode_memory_address) { - put_word_test(pc, 0x4e71); + put_word_test(pc, NOP_OPCODE); pc += 2; cnt++; if (cnt >= 16) { @@ -4502,9 +4591,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi uae_u8 *bo = opcode_memory_ptr + 2; uae_u16 bopw1 = (bo[0] << 8) | (bo[1] << 0); uae_u16 bopw2 = (bo[2] << 8) | (bo[3] << 0); - if (opc == 0x4e96 - //&& bopw1 == 0x3dec - //&& bopw2 == 0x2770 + if (opc == 0x0ab3 + && bopw1 == 0x5aa9 + && bopw2 == 0xe5cc ) printf(""); @@ -4550,6 +4639,23 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // loop mode if (feature_loop_mode) { // dbf dn, opcode_memory_start + if (!feature_loop_mode_68010) { + for (int i = 0; i < 4; i++) { + // bcc, bne, bvc, bpl + put_word(pc, 0x6400 + (i * 0x0200) + 4); + pc += 2; + // adda.w #x,a3 + put_long(pc, 0xd6fc0000 | (1 << (i * 3))); + pc += 4; + } + // negx.b d0 ; add.w d0,d0 + put_long(pc, 0x4000d040); + pc += 4; + // sub.w #63,dn + put_long(pc, ((0x0440 | feature_loop_mode_register) << 16) | 63); + pc += 4; + } + // dbf dn,label put_long_test(pc, ((0x51c8 | feature_loop_mode_register) << 16) | ((opcode_memory_address - pc - 2) & 0xffff)); pc += 4; } @@ -4561,7 +4667,7 @@ 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. - uae_u32 originalendopcode = 0x4afc4e71; + uae_u32 originalendopcode = (ILLG_OPCODE << 16) | NOP_OPCODE; uae_u32 endopcode = originalendopcode; uae_u32 actualendpc = pc; @@ -4621,6 +4727,17 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (dstaddr != 0xffffffff && srcaddr != dstaddr) { outbytes(_T("D"), dstaddr); } + if (feature_loop_mode) { + wprintf(_T("\n")); + for (int i = 0; i < 20; i++) { + out_of_test_space = false; + if (get_word_test(nextpc) == ILLG_OPCODE) + break; + m68k_disasm_2(out, sizeof(out) / sizeof(TCHAR), nextpc, &nextpc, 1, NULL, NULL, 0xffffffff, 0); + my_trim(out); + wprintf(_T("%08u %s\n"), subtest_count, out); + } + } } // disassembler may set this @@ -4745,6 +4862,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi uae_u32 branchtarget_old_prev = branchtarget_old; uae_u32 srcaddr_old_prev = srcaddr_old; uae_u32 dstaddr_old_prev = dstaddr_old; + int interrupt_count_old_prev = interrupt_count; if (startpc != startpc_old) { dst = store_reg(dst, CT_PC, startpc_old, startpc, -1); @@ -4848,16 +4966,22 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi ahcnt_current = ahcnt_written; int ahcnt_start = ahcnt_current; + if (feature_interrupts) { + *dst++ = (uae_u8)interrupt_count; + interrupt_count++; + interrupt_count &= 15; + } + memset(®s, 0, sizeof(regs)); // swap end opcode illegal/nop noaccesshistory++; endopcode = (endopcode >> 16) | (endopcode << 16); - int extraopcodeendsize = ((endopcode >> 16) == 0x4e71) ? 2 : 0; + int extraopcodeendsize = ((endopcode >> 16) == NOP_OPCODE) ? 2 : 0; int endopcodesize = 0; if (!is_nowrite_address(pc - 4, 4)) { put_long_test(pc - 4, endopcode); - endopcodesize = (endopcode >> 16) == 0x4e71 ? 2 : 4; + endopcodesize = (endopcode >> 16) == NOP_OPCODE ? 2 : 4; } else if (!is_nowrite_address(pc - 4, 2)) { put_word_test(pc - 4, endopcode >> 16); endopcodesize = 2; @@ -4872,7 +4996,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (!(branch_target_swap_address & 1)) { branch_target_data = (branch_target_data >> 16) | (branch_target_data << 16); put_long_test(branch_target_swap_address, branch_target_data); - if ((branch_target_data >> 16) == 0x4e71) + if ((branch_target_data >> 16) == NOP_OPCODE) branch_target_pc = branch_target + 2; else branch_target_pc = branch_target; @@ -4894,7 +5018,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi regs.ir = get_word_test(regs.pc + 0); regs.irc = get_word_test(regs.pc + 2); - if (regs.ir == 0x4afc && dp->mnemo != i_ILLG) { + if (regs.ir == ILLG_OPCODE && dp->mnemo != i_ILLG) { wprintf(_T(" Illegal as starting opcode!?\n")); abort(); } @@ -5132,10 +5256,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // did we have trace also active? if (SPCFLAG_DOTRACE) { - if ((regs.t1 || regs.t0) && (test_exception == 5 || test_exception == 6 || test_exception == 7 || (test_exception >= 32 && test_exception <= 47) || (cpu_lvl == 1 && test_exception == 14))) { - test_exception_extra = 9; - } else { - test_exception_extra = 0; + test_exception_extra = 0; + if (regs.t1 || regs.t0) { + if ((cpu_lvl < 4 && (test_exception == 5 || test_exception == 6 || test_exception == 7 || (test_exception >= 32 && test_exception <= 47))) + || + (cpu_lvl == 1 && test_exception == 14)) { + test_exception_extra = 9; + } } } if (trace_store_pc != 0xffffffff) { @@ -5249,6 +5376,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi branchtarget_old = branchtarget_old_prev; instructionendpc_old = instructionendpc_old_prev; startpc_old = startpc_old_prev; + interrupt_count = interrupt_count_old_prev; } else { full_format_cnt++; data_saved = 1; @@ -5290,7 +5418,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // save to file and create new file if watermark reached if (dst - storage_buffer >= storage_buffer_watermark) { if (subtest_count > 0) { - save_data(dst, dir); + save_data(dst, dir, size); branchtarget_old = 0xffffffff; srcaddr_old = 0xffffffff; @@ -5331,7 +5459,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } if (data_saved) { - save_data(dst, dir); + save_data(dst, dir, size); data_saved = 0; } dst = storage_buffer; @@ -5392,7 +5520,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (nextround) { rounds--; if (rounds < 0) { - if (subtest_count >= feature_test_rounds_opcode) + if (subtest_count >= feature_test_rounds_opcode || !got_something) break; rounds = 1; } @@ -5799,7 +5927,7 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna if (currprefs.fpu_model < 0) { currprefs.fpu_model = currprefs.cpu_model; if (currprefs.fpu_model == 68020 || currprefs.fpu_model == 68030) { - currprefs.fpu_model == 68882; + currprefs.fpu_model = 68882; } } else if (currprefs.cpu_model >= 68040) { currprefs.fpu_model = currprefs.cpu_model; diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index 4c073f92..e8c649b3 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -1,5 +1,5 @@ -#define DATA_VERSION 18 +#define DATA_VERSION 20 #define CT_FPREG 0 #define CT_DREG 0 @@ -45,5 +45,10 @@ #define CT_OVERRIDE_REG (0x80 | 0x40 | 0x10) #define CT_BRANCHED 0x40 -#define OPCODE_AREA 32 +#define OPCODE_AREA 48 #define BRANCHTARGET_AREA 4 + +// MOVEA.L A0,A0 +// not NOP because on 68040 NOP generates T0 trace. +#define NOP_OPCODE 0x2048 +#define ILLG_OPCODE 0x4afc diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 73c6d553..f42b0232 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -43,9 +43,9 @@ high_rom=D:\amiga\roms\Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A200 ; main test memory start and size (real hardware must have RAM in this address space) test_memory_start=0x860000 ;test_memory_start=0x68800000 +;test_memory_start=0x43800000 ;test_memory_start=0x07800000 -;test_memory_start=0x340000 -test_memory_size=0x40000 +test_memory_size=0xa0000 ; address where test instructions are located ; if not defined: mid point of test memory @@ -61,7 +61,7 @@ min_opcode_test_rounds=0 ; test word or long odd data access address errors (68000/010 only) ; 0 = do not generate address errors ; 1 = include address errors -; 2 = only generate test instructions that generate address errors +; 2 = only generate test instructions that generate address errors (trace is allowed) feature_exception3_data=0 ; test branches to odd addresses @@ -149,10 +149,12 @@ feature_sr_mask=0x0000 ; generate loop test: label: dbf dn,label ; value: 0 = disabled, >0 = number of loops -feature_loop_mode=0 -feature_loop_mode_register=7 +; feature_loop_mode=0 +; feature_loop_mode_register=7 ; only generate 68010 loop mode compatible instructions -feature_loop_mode_68010=0 +: feature_loop_mode_68010=0 +; reload changed address register(s) (-(an) or (an)+) after each round +; feature_loop_mode_reload=1 ; 68020+ addressing modes (this makes test files much larger if other addressing modes are also enabled) ; currently does not generate any reserved mode bit combinations. @@ -204,8 +206,10 @@ mode=all [test=IRQ] enabled=0 cpu=68000-68010 -mode=nop,ext,swap +feature_sr_mask=0x8000 feature_interrupts=1 +mode=jsr,jmp,bsr,bcc,dbcc,nop,exg,swap,stop,mvsr2,mv2sr,andsr,eorsr,orsr +min_opcode_test_rounds=100 ; source EA address error [test=AE_SRC] @@ -255,6 +259,8 @@ feature_safe_memory_mode=P feature_target_opcode_offset=2,4,6,8,10,12,14,16 opcode_memory_start=0x87ffee test_memory_size=0xa0000 +test_memory_size=0x100000 +opcode_memory_start=0x87ffa0 mode=all ; source EA read bus error (requires extra hardware) @@ -266,7 +272,9 @@ feature_safe_memory_size=0x80000 feature_safe_memory_mode=R feature_target_src_ea=0x87fffc,0x87fffd,0x87fffe,0x87ffff,0x880000,0x880001,0x880002,0x880003,0x880004 feature_target_dst_ea= -test_memory_size=0xa0000 +test_memory_start=0x860000 +test_memory_size=0x100000 +opcode_memory_start=0x87ffa0 mode=all ; destination EA read bus error (requires extra hardware) @@ -278,7 +286,9 @@ feature_safe_memory_size=0x80000 feature_safe_memory_mode=R feature_target_src_ea= feature_target_dst_ea=0x87fffc,0x87fffd,0x87fffe,0x87ffff,0x880000,0x880001,0x880002,0x880003,0x880004 -test_memory_size=0xa0000 +test_memory_start=0x860000 +test_memory_size=0x100000 +opcode_memory_start=0x87ffa0 mode=all ; source EA (=RMW instructions like NOT have only source EA) write bus error (requires extra hardware) @@ -293,7 +303,8 @@ feature_target_dst_ea= opcode_memory_start=0x8fffa0 test_memory_start=0x880000 test_memory_size=0x100000 -mode=all +mode=moves +;mode=all ; destination EA write bus error (requires extra hardware) [test=BE_DSTW] @@ -309,11 +320,15 @@ test_memory_start=0x880000 test_memory_size=0x100000 mode=all + ; 68010 loop mode compatible instructions -[test=loopmode] +[test=LM] enabled=0 cpu=68010 feature_loop_mode_68010=1 +feature_loop_mode=3 +feature_loop_mode_register=7 +min_opcode_test_rounds=100 mode=all ; ************** @@ -325,9 +340,17 @@ mode=all [test=Basic] enabled=0 cpu=68020-68060 -feature_sr_mask=0xd000 +feature_sr_mask=0xf000 mode=all +; interrupt exception +[test=IRQ] +enabled=0 +cpu=68020-68060 +mode=jsr,jmp,bsr,bcc,dbcc,nop,exg,swap,stop,mvsr2,mv2sr,andsr,eorsr,orsr +min_opcode_test_rounds=100 +feature_interrupts=1 + ; 68020+ addressing mode tests [test=FFEXT_SRC] enabled=0 @@ -349,6 +372,7 @@ mode=add,move [test=AE] enabled=0 cpu=68020-68060 +feature_sr_mask=0xd000 feature_exception3_instruction=2 mode=all @@ -356,6 +380,7 @@ mode=all [test=ODD_STK] enabled=0 cpu=68020-68060 +feature_sr_mask=0xd000 feature_usp=2 mode=rts,rtd,rtr,jsr,bsr,link,unlk,pea @@ -363,6 +388,7 @@ mode=rts,rtd,rtr,jsr,bsr,link,unlk,pea [test=ODD_EXC] enabled=0 cpu=68020-68060 +feature_sr_mask=0xd000 feature_exception_vectors=0x000123 mode=mv2sr.w,mvsr2.w,mvusp2r,mvr2usp,illegal,chk,trap,trapv,orsr.w,eorsr.w,andsr.w,divu,divs,divul,divsl @@ -370,7 +396,8 @@ mode=mv2sr.w,mvsr2.w,mvusp2r,mvr2usp,illegal,chk,trap,trapv,orsr.w,eorsr.w,andsr [test=ODD_IRQ] enabled=0 cpu=68020-68060 -mode=nop,ext,swap +feature_sr_mask=0xd000 +mode=ext,swap feature_interrupts=1 feature_exception_vectors=0x000123 @@ -431,3 +458,18 @@ fpu=68882 exceptions=11,55,60,61 feature_flags_mode=2 mode=fillegal + +; ****************** +; JIT loop mode test +; ****************** + +[test=JITLM] +enabled=0 +cpu=68020-68060 +cpu_address_space=68020 +feature_loop_mode=10 +feature_loop_mode_reload=1 +feature_loop_mode_register=7 +mode=eor +feature_instruction_size=W +verbose=0 diff --git a/cputest/main.c b/cputest/main.c index 665be614..26c80632 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -133,6 +133,7 @@ static short quit; static uae_u8 ccr_mask; static uae_u32 addressing_mask = 0x00ffffff; static uae_u32 interrupt_mask; +static short instructionsize; static short disasm; static short basicexcept; static short excskipccr; @@ -161,6 +162,7 @@ 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; +static uae_u8 *opcode_memory_end; static char opcode[32], group[32], cpustr[10]; @@ -304,7 +306,7 @@ static void endinfo(void) break; uae_u16 v = (p[i] << 8) | (p[i + 1]); printf("%08x %04x\n", (uae_u32)&p[i], v); - if (v == 0x4afc && i > 0) + if (v == ILLG_OPCODE && i > 0) break; } printf("\n"); @@ -1057,11 +1059,17 @@ static void restoreahist(void) static uae_u8 *restore_bytes(uae_u8 *mem, uae_u8 *p) { uae_u8 *addr = mem; - uae_u8 v = *p++; + uae_u16 v = *p++; addr += v >> 5; v &= 31; - if (v == 0) + if (v == 31) { + v = *p++; + if (v == 0) { + v = 256; + } + } else if (v == 0) { v = 32; + } #ifndef _MSC_VER xmemcpy(addr, p, v); #endif @@ -1266,7 +1274,7 @@ static void out_disasm(uae_u8 *mem) uae_u8 *p = mem; int offset = 0; int lines = 0; - while (lines++ < 7) { + while (lines++ < 15) { int v = 0; if (!is_valid_word(p)) { sprintf(outbp, "%08x -- INACCESSIBLE --\n", (uae_u32)p); @@ -1286,14 +1294,14 @@ static void out_disasm(uae_u8 *mem) } sprintf(outbp, "%04x ", v); outbp += strlen(outbp); - if (v == 0x4e71) + if (v == NOP_OPCODE) lines--; } sprintf(outbp, " %s\n", tmpbuffer); outbp += strlen(outbp); if (!is_valid_word((uae_u8*)(code + offset))) break; - if (v <= 0 || code[offset] == 0x4afc) + if (v <= 0 || code[offset] == ILLG_OPCODE) break; while (v > 0) { offset++; @@ -1391,19 +1399,22 @@ static void out_regs(struct registers *r, struct registers *r1, struct registers } else if ((i % 8) != 0) { strcat(outbp, " "); } + uae_u32 v1 = r1->regs[i]; + uae_u32 v2 = r2->regs[i]; + uae_u32 sv = sreg->regs[i]; outbp += strlen(outbp); - sprintf(outbp, "%c%d:%c%08x", i < 8 ? 'D' : 'A', i & 7, r1->regs[i] != r2->regs[i] ? '*' : ' ', r->regs[i]); + sprintf(outbp, "%c%d:%c%08x", i < 8 ? 'D' : 'A', i & 7, v1 == v2 && v1 != sv ? '*' : (v1 != v2 ? '!' : ' '), r->regs[i]); outbp += strlen(outbp); } *outbp++ = '\n'; - sprintf(outbp, "SR:%c%04x PC: %08x ISP: %08x B: %d", r1->sr != r2->sr ? '*' : ' ', r->sr, r->pc, r->ssp, branched); + sprintf(outbp, "SR:%c%04x PC: %08x ISP: %08x", r1->sr == r2->sr && r1->sr != sreg->sr ? '*' : (r1->sr != r2->sr ? '!' : ' '), r->sr, r->pc, r->ssp); } else { // output only lines that have at least one modified register to save screen space for (int i = 0; i < 4; i++) { int diff = 0; for (int j = 0; j < 4; j++) { int idx = i * 4 + j; - if (r1->regs[idx] != r2->regs[idx]) { + if (r1->regs[idx] != sreg->regs[idx]) { diff = 1; } } @@ -1412,19 +1423,26 @@ static void out_regs(struct registers *r, struct registers *r1, struct registers int idx = i * 4 + j; if (j > 0) *outbp++ = ' '; - sprintf(outbp, "%c%d:%c%08x", idx < 8 ? 'D' : 'A', idx & 7, r->regs[idx] != r2->regs[idx] ? '*' : ' ', r->regs[idx]); + uae_u32 v1 = r1->regs[idx]; + uae_u32 v2 = r2->regs[idx]; + uae_u32 sv = sreg->regs[idx]; + sprintf(outbp, "%c%d:%c%08x", idx < 8 ? 'D' : 'A', idx & 7, v1 == v2 && v1 != sv ? '*' : ((v1 != v2) ? '!' : ' '), r->regs[idx]); outbp += strlen(outbp); } *outbp++ = '\n'; } } - sprintf(outbp, "SR:%c%04x/%04x PC: %08x ISP: %08x B: %d", r->sr != r2->sr ? '*' : ' ', r->sr, r->expsr, r->pc, r->ssp, branched); + sprintf(outbp, "SR:%c%04x/%04x PC: %08x ISP: %08x", r1->sr == r2->sr && r1->sr != sreg->sr ? '*' : (r1->sr != r2->sr ? '!' : ' '), r->sr, r->expsr, r->pc, r->ssp); } outbp += strlen(outbp); if (cpu_lvl >= 2 && cpu_lvl <= 4) { sprintf(outbp, " MSP: %08x", r->msp); outbp += strlen(outbp); } + if (branched) { + sprintf(outbp, " B: %d", branched); + outbp += strlen(outbp); + } *outbp++ = '\n'; *outbp = 0; @@ -1563,6 +1581,7 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu last_exception_extra = *p++; if (last_exception_extra & 0x40) { *group2with1 = *p++; + exceptioncount[0][*group2with1]++; last_exception_extra &= ~0x40; } if ((last_exception_extra & 0x3f) == 9) { @@ -1570,7 +1589,14 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu uae_u32 ret = (regs->tracedata[1] << 16) | regs->tracedata[2]; uae_u16 sr = regs->tracedata[0]; if (regs->tracecnt == 0) { - sprintf(outbp, "Expected trace exception but got none\n"); + uae_u32 pc; + if (!(last_exception_extra & 0x80)) { + pc = exceptiontableinuse + (excnum - 2) * 2; + } else { + pc = opcode_memory_addr; + p = restore_rel_ordered(p + 2, &pc); + } + sprintf(outbp, "Expected trace exception (PC=%08x) but got none.\n", pc); outbp += strlen(outbp); *experr = 1; } else if (!(last_exception_extra & 0x80)) { @@ -1804,6 +1830,12 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu } alts = 3; } + if (instructionsize == 0) { + // if byte wide bus error, ignore high byte of input and output buffer + // contents of high byte depends on used alu operation and instruction type and more.. + masked_exception[16] = 0; + masked_exception[20] = 0; + } p += 2; } break; @@ -1969,6 +2001,30 @@ static int get_cycles_amiga(void) int gotcycles = (endcycle - startcycle) * 2; return gotcycles; } + +static uae_u16 test_intena, test_intreq; + +static void set_interrupt(void) +{ + if (interrupt_count < 15) { + volatile uae_u16 *intena = (uae_u16 *)0xdff09a; + volatile uae_u16 *intreq = (uae_u16 *)0xdff09c; + uae_u16 mask = 1 << interrupt_count; + test_intena = mask | 0x8000 | 0x4000; + test_intreq = mask | 0x8000; + *intena = test_intena; + *intreq = test_intreq; + } +} + +static void clear_interrupt(void) +{ + volatile uae_u16 *intena = (uae_u16 *)0xdff09a; + volatile uae_u16 *intreq = (uae_u16 *)0xdff09c; + *intena = 0x7fff; + *intreq = 0x7fff; +} + #endif static int check_cycles(int exc, short extratrace, short extrag2w1, struct registers *lregs) @@ -2056,7 +2112,6 @@ static int check_cycles(int exc, short extratrace, short extrag2w1, struct regis // interrupt expectedcycles += 2 + 4 + 4; } - exceptioncount[0][extrag2w1]++; } if (0 || abs(gotcycles - expectedcycles) > cycles_range) { @@ -2411,14 +2466,14 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st errflag |= 1 << 16; } if ((tregs->expsr & 0xff) != (tregs->sr & 0xff)) { - sprintf(outbp, "Exception stacked CCR != CCR at start of exception handler!\n"); + sprintf(outbp, "Exception stacked CCR (%04x) != CCR (%04x) at start of exception handler!\n", tregs->sr, tregs->expsr); outbp += strlen(outbp); errflag |= 1 << 16; } lregs->sr = val; } else if (mode == CT_PC) { uae_u32 val = lregs->pc; - p = restore_rel(p, &val, 0); + p = restore_rel(p, &val, 1); pc_changed = 0; lregs->pc = val; } else if (mode == CT_CYCLES) { @@ -2635,6 +2690,12 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st strcat(outbp, "Registers after:\n"); outbp += strlen(outbp); out_regs(tregs, tregs, lregs, sregs, 0, branched2); +#ifdef AMIGA + if (interrupttest) { + sprintf(outbp, "INTREQ: %04x INTENA: %04x\n", test_intreq, test_intena); + outbp += strlen(outbp); + } +#endif if (exc > 1) { if (!experr) { sprintf(outbp, "OK: exception %d ", exc); @@ -2708,34 +2769,6 @@ static void store_addr(uae_u32 s, uae_u8 *d) } } -#ifdef AMIGA -static const int interrupt_levels[] = -{ - 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, -1 -}; - -static void set_interrupt(void) -{ - if (interrupt_count < 15) { - volatile uae_u16 *intena = (uae_u16*)0xdff09a; - volatile uae_u16 *intreq = (uae_u16*)0xdff09c; - uae_u16 mask = 1 << interrupt_count; - *intena = mask | 0x8000 | 0x4000; - *intreq = mask | 0x8000; - } - interrupt_count++; - interrupt_count &= 15; -} - -static void clear_interrupt(void) -{ - volatile uae_u16 *intena = (uae_u16*)0xdff09a; - volatile uae_u16 *intreq = (uae_u16*)0xdff09c; - *intena = 0x7fff; - *intreq = 0x7fff; -} -#endif - static uae_u32 xorshiftstate; static uae_u32 xorshift32(void) { @@ -2812,13 +2845,13 @@ static void process_test(uae_u8 *p) store_addr(cur_regs.branchtarget, branchtarget); startpc = cur_regs.pc; endpc = cur_regs.endpc; - uae_u8 *opcode_memory_end = (uae_u8*)endpc; + opcode_memory_end = (uae_u8*)endpc; int fpumode = fpu_model && (opcode_memory[0] & 0xf0) == 0xf0; copyregs(&last_regs, &cur_regs, fpumode); - uae_u32 originalopcodeend = 0x4afc4e71; + uae_u32 originalopcodeend = (ILLG_OPCODE << 16) | NOP_OPCODE; short opcodeendsizeextra = 0; uae_u32 opcodeend = originalopcodeend; int extraccr = 0; @@ -2849,7 +2882,6 @@ static void process_test(uae_u8 *p) testcntsub = 0; for (short ccr = 0; ccr < maxccr; ccr++, testcntsub++) { - copyregs(&test_regs, &cur_regs, fpumode); fpu_approx = 0; opcodeend = (opcodeend >> 16) | (opcodeend << 16); @@ -2868,16 +2900,19 @@ static void process_test(uae_u8 *p) pl((uae_u8*)cur_regs.branchtarget, bv); } else if (cur_regs.branchtarget_mode == 2) { uae_u16 bv = gw((uae_u8 *)cur_regs.branchtarget); - if (bv == 0x4e71) - bv = 0x4afc; + if (bv == NOP_OPCODE) + bv = ILLG_OPCODE; else - bv = 0x4e71; + bv = NOP_OPCODE; pw((uae_u8 *)cur_regs.branchtarget, bv); } } - test_regs.ssp = super_stack_memory - 0x80; - test_regs.msp = super_stack_memory; + cur_regs.ssp = super_stack_memory - 0x80; + cur_regs.msp = super_stack_memory; + + copyregs(&test_regs, &cur_regs, fpumode); + test_regs.pc = startpc; test_regs.fpiar = startpc; test_regs.cyclest = 0xffffffff; @@ -2911,6 +2946,12 @@ static void process_test(uae_u8 *p) } } +#ifdef AMIGA + if (interrupttest) { + interrupt_count = *p++; + } +#endif + while ((*p) == CT_OVERRIDE_REG) { p++; uae_u8 v = *p++; @@ -3179,7 +3220,7 @@ static int test_mnemo(const char *opcode) int headoffset = 0; v = read_u32(headerfile, &headoffset); if (v != DATA_VERSION) { - printf("Invalid test data file (header)\n"); + printf("Invalid test data file (header %08x<>%08x)\n", v, DATA_VERSION); exit(0); } @@ -3317,7 +3358,7 @@ static int test_mnemo(const char *opcode) break; } if (gl(test_data) != DATA_VERSION) { - printf("Invalid test data file (header)\n"); + printf("Invalid test data file (header, %08x<>%08x)\n", gl(test_data), DATA_VERSION); exit(0); } if (gl(test_data + 4) != starttimeid) { @@ -3329,6 +3370,8 @@ static int test_mnemo(const char *opcode) free(test_data); exit(0); } + uae_u32 flags = gl(test_data + 8); + instructionsize = flags & 3; // last file? int last = test_data[test_data_size - 1] == CT_END_FINISH; diff --git a/cputest/readme.txt b/cputest/readme.txt index 0de203a5..33d9391d 100644 --- a/cputest/readme.txt +++ b/cputest/readme.txt @@ -131,6 +131,13 @@ If mismatch is detected, opcode word(s), instruction disassembly, registers befo Change log: +31.05.2020 + +- 68010 bus error and byte size memory access: ignore bus error stack frame high byte of input and output buffers. Their contents depends on type of ALU operation, instruction type and probably more.. +- If trace exception was generated after some other exception ("+EXC 9" in stack frame info line), it was not counted in final exception totals (Exx=1234) +- Replaced NOP with MOVEA.L A0,A0 in test code because 68040 NOP is considered branching instruction and triggers T0 trace. +- Interrupt test improved. + 17.05.2020 - Rewritten disassembler to use indirect and validated opword reads, now it is safe to use when testing bus errors.