From: Toni Wilen Date: Sun, 12 Mar 2023 08:04:45 +0000 (+0200) Subject: CPUTester update (68000 IPL timing, wait states, etc) X-Git-Tag: 5.0.0~112 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=819595132da7181c3196cfe4efd1e88e5a87e0bd;p=francis%2Fwinuae.git CPUTester update (68000 IPL timing, wait states, etc) --- diff --git a/cputest.cpp b/cputest.cpp index c4b6cd99..ad80f70a 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -40,6 +40,7 @@ int hardware_bus_error, hardware_bus_error_fake; struct mmufixup mmufixup[2]; cpuop_func *cpufunctbl[65536]; +cpuop_func_noret *cpufunctbl_noret[65536]; struct cputbl_data { uae_s16 length; @@ -51,12 +52,15 @@ static struct cputbl_data cpudatatbl[65536]; struct regstruct regs; struct flag_struct regflags; int cpu_cycles; +static int cycle_count_disable; static int verbose = 1; static int feature_exception3_data = 0; static int feature_exception3_instruction = 0; static int feature_sr_mask = 0; static int feature_undefined_ccr = 0; +static int feature_initial_interrupt = 0; +static int feature_initial_interrupt_mask = 0; static int feature_min_interrupt_mask = 0; static int feature_loop_mode_cnt = 0; static int feature_loop_mode_register = -1; @@ -69,12 +73,14 @@ static int feature_flag_mode = 0; static int feature_usp = 0; static int feature_exception_vectors = 0; static int feature_interrupts = 0; +static int feature_waitstates = 0; static int feature_instruction_size = 0; static int fpu_min_exponent, fpu_max_exponent; static int max_file_size; static int rnd_seed, rnd_seed_prev; static TCHAR *feature_instruction_size_text = NULL; static uae_u32 feature_addressing_modes[2]; +static uae_u32 feature_condition_codes; static int feature_gzip = 0; static int ad8r[2], pc8r[2]; static int multi_mode; @@ -147,6 +153,8 @@ static int test_memory_access_mask; static uae_u32 opcode_memory_address; static uaecptr branch_target; static uaecptr branch_target_pc; +static uae_u16 test_opcode; +static int test_absw; static uae_u8 imm8_cnt; static uae_u16 imm16_cnt; @@ -173,8 +181,11 @@ static uae_u16 extra_or, extra_and; static struct regstruct cur_regs; static uae_u16 read_buffer_prev; static int interrupt_count; +static uaecptr interrupt_pc; static int interrupt_cycle_cnt, interrupt_delay_cnt; static int interrupt_level; +static int waitstate_cycle_cnt; +static int waitstate_delay_cnt; static uaecptr test_instruction_end_pc; static uaecptr lm_safe_address1, lm_safe_address2; static uae_u8 ccr_cnt; @@ -242,11 +253,15 @@ static bool valid_address(uaecptr addr, int size, int rwp) if (low_memory_size != 0xffffffff && addr + size < low_memory_size) { if (addr < test_low_memory_start || test_low_memory_start == 0xffffffff) goto oob; + // only accept low memory when testing short absolute addressing + if (!test_absw) { + goto oob; + } // exception vectors needed during tests 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)) + if (feature_interrupts && (addr + size >= 0x60 && addr < 0x80)) goto oob; } if (addr + size >= test_low_memory_end) @@ -263,6 +278,10 @@ static bool valid_address(uaecptr addr, int size, int rwp) goto oob; if (addr + size >= test_high_memory_end) goto oob; + // only accept high memory when testing short absolute addressing + if (!test_absw) { + goto oob; + } if (w && hmem_rom) goto oob; if (testing_active) { @@ -371,15 +390,33 @@ oob: return dummy_memory; } -static void count_interrupt_cycles(int cycles) +static void count_cycles(int cycles) { - if (!interrupt_cycle_cnt) + if (cycle_count_disable) { return; - interrupt_cycle_cnt -= cycles; - if (interrupt_cycle_cnt <= 0) { - regs.ipl_pin = IPL_TEST_IPL_LEVEL; - interrupt_level = regs.ipl_pin; - interrupt_cycle_cnt = 0; + } + while (cycles > 0) { + cycles--; + cpu_cycles++; + if (interrupt_cycle_cnt != 0) { + interrupt_cycle_cnt--; + if (interrupt_cycle_cnt == 0) { + if (regs.ipl_pin < IPL_TEST_IPL_LEVEL) { + regs.ipl_pin = IPL_TEST_IPL_LEVEL; + regs.ipl_pin_change_evt = cpu_cycles; + } + if (cpu_cycles == regs.ipl_evt_pre + cpuipldelay2) { + if (regs.ipl_evt_pre_mode) { + ipl_fetch_next(); + } else { + ipl_fetch_now(); + } + } + interrupt_pc = regs.pc; + interrupt_level = regs.ipl_pin; + interrupt_cycle_cnt = 0; + } + } } } @@ -387,19 +424,65 @@ void do_cycles_test(int cycles) { if (!testing_active) return; - cpu_cycles += cycles; - count_interrupt_cycles(cycles); + count_cycles(cycles); } -static void add_memory_cycles(int c) +static void add_memory_cycles(uaecptr addr, int c) { - if (!testing_active) + if (cycle_count_disable) { return; - if (trace_store_pc != 0xffffffff) + } + if (!testing_active) { + return; + } + if (trace_store_pc != 0xffffffff) { return; - c *= 4; - cpu_cycles += c; - count_interrupt_cycles(c); + } + if (waitstate_cycle_cnt && (addr & addressing_mask) < 0x200000 && c > 0) { + c *= 2; + while (c > 0) { + int now = cpu_cycles; + int ipl = regs.ipl_pin; + count_cycles(2); + c--; + // wait for free bus cycle + for (;;) { + int cb = (cpu_cycles - waitstate_cycle_cnt) / 2; + // remove init cycles + cb -= 3; + if (cb < 0) { + break; + } + if (feature_waitstates == 1) { + cb %= 3; + // AB-AB-AB-.. + if (cb == 2) { + break; + } + } else { + // -BC--BCD-BCD.. + // 012301230123 + if (cb == 0 || cb == 3) { + break; + } + cb %= 4; + if (cb == 0) { + break; + } + } + ipl = regs.ipl_pin; + count_cycles(2); + } + count_cycles(2); + c--; + if (now == regs.ipl_evt) { + regs.ipl[0] = ipl; + } + } + } else { + c *= 4; + count_cycles(c); + } } static void check_bus_error(uaecptr addr, int write, int fc) @@ -439,7 +522,7 @@ static uae_u8 get_ibyte_test(uaecptr addr) { check_bus_error(addr, 0, regs.s ? 5 : 1); uae_u8 *p = get_addr(addr, 1, 4); - add_memory_cycles(1); + add_memory_cycles(addr, 1); return *p; } @@ -450,7 +533,7 @@ static uae_u16 get_iword_test(uaecptr addr) return (get_ibyte_test(addr + 0) << 8) | (get_ibyte_test(addr + 1) << 0); } else { uae_u8 *p = get_addr(addr, 2, 4); - add_memory_cycles(1); + add_memory_cycles(addr, 1); return (p[0] << 8) | (p[1]); } } @@ -471,7 +554,7 @@ uae_u32 get_ilong_test(uaecptr addr) } else { uae_u8 *p = get_addr(addr, 4, 4); v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); - add_memory_cycles(2); + add_memory_cycles(addr, 2); } return v; } @@ -482,11 +565,13 @@ uae_u16 get_word_test_prefetch(int o) if (cpu_lvl < 2) { o -= 2; } - add_memory_cycles(-1); + cycle_count_disable = 1; regs.irc = get_iword_test(m68k_getpci() + o + 2); + cycle_count_disable = 0; read_buffer_prev = regs.read_buffer; regs.read_buffer = regs.irc; - return get_iword_test(m68k_getpci() + o); + uae_u16 v = get_iword_test(m68k_getpci() + o); + return v; } static void previoussame(uaecptr addr, int size, uae_u32 *old) @@ -524,12 +609,14 @@ void put_byte_test(uaecptr addr, uae_u32 v) { if (!testing_active && is_nowrite_address(addr, 1)) return; - if (feature_interrupts >= 2 && addr == IPL_TRIGGER_ADDR) { - add_memory_cycles(1); + if (feature_interrupts >= 2) { + if (addr == IPL_TRIGGER_ADDR) { + add_memory_cycles(addr, 1); #if IPL_TRIGGER_ADDR_SIZE == 1 - interrupt_cycle_cnt = INTERRUPT_CYCLES; + interrupt_cycle_cnt = INTERRUPT_CYCLES; #endif - return; + return; + } } check_bus_error(addr, 1, regs.s ? 5 : 1); uae_u8 *p = get_addr(addr, 1, 2); @@ -550,18 +637,25 @@ void put_byte_test(uaecptr addr, uae_u32 v) regs.write_buffer &= 0xff00; regs.write_buffer |= v & 0xff; *p = v; - add_memory_cycles(1); + add_memory_cycles(addr, 1); } void put_word_test(uaecptr addr, uae_u32 v) { if (!testing_active && is_nowrite_address(addr, 1)) return; - if (feature_interrupts >= 2 && addr == IPL_TRIGGER_ADDR) { - add_memory_cycles(1); + if (feature_interrupts >= 2) { + if (addr == IPL_BLTSIZE) { + add_memory_cycles(addr, 1); + waitstate_cycle_cnt = cpu_cycles; + return; + } + if (addr == IPL_TRIGGER_ADDR) { + add_memory_cycles(addr, 1); #if IPL_TRIGGER_ADDR_SIZE == 2 - interrupt_cycle_cnt = INTERRUPT_CYCLES; + interrupt_cycle_cnt = INTERRUPT_CYCLES; #endif - return; + return; + } } check_bus_error(addr, 1, regs.s ? 5 : 1); if (addr & 1) { @@ -587,7 +681,7 @@ void put_word_test(uaecptr addr, uae_u32 v) p[1] = v & 0xff; } regs.write_buffer = v; - add_memory_cycles(1); + add_memory_cycles(addr, 1); } void put_long_test(uaecptr addr, uae_u32 v) { @@ -621,7 +715,7 @@ void put_long_test(uaecptr addr, uae_u32 v) p[1] = v >> 16; p[2] = v >> 8; p[3] = v >> 0; - add_memory_cycles(2); + add_memory_cycles(addr, 2); } regs.write_buffer = v; } @@ -660,7 +754,7 @@ uae_u32 get_byte_test(uaecptr addr) read_buffer_prev = regs.read_buffer; regs.read_buffer &= 0xff00; regs.read_buffer |= *p; - add_memory_cycles(1); + add_memory_cycles(addr, 1); return *p; } uae_u32 get_word_test(uaecptr addr) @@ -675,7 +769,7 @@ uae_u32 get_word_test(uaecptr addr) } read_buffer_prev = regs.read_buffer; regs.read_buffer = v; - add_memory_cycles(1); + add_memory_cycles(addr, 1); return v; } uae_u32 get_long_test(uaecptr addr) @@ -694,7 +788,7 @@ uae_u32 get_long_test(uaecptr addr) } else { uae_u8 *p = get_addr(addr, 4, 1); v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); - add_memory_cycles(2); + add_memory_cycles(addr, 2); } read_buffer_prev = regs.read_buffer; regs.read_buffer = v; @@ -831,7 +925,7 @@ uae_u32 next_ilong_test(void) bool mmu_op30(uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa) { m68k_setpc(pc); - op_illg(opcode); + op_illg_noret(opcode); return true; } @@ -840,18 +934,36 @@ bool is_cycle_ce(uaecptr addr) return 0; } +void ipl_fetch_next_pre(void) +{ + ipl_fetch_next(); + regs.ipl_evt_pre = cpu_cycles; + regs.ipl_evt_pre_mode = 1; +} + +void ipl_fetch_now_pre(void) +{ + ipl_fetch_now(); + regs.ipl_evt_pre = cpu_cycles; + regs.ipl_evt_pre_mode = 0; +} + // ipl check was early enough, interrupt possible after current instruction void ipl_fetch_now(void) { - if (regs.ipl[0] != regs.ipl_pin) { - regs.ipl[0] = regs.ipl_pin; - regs.ipl[1] = 0; - } + int c = cpu_cycles; + regs.ipl_evt = c; + regs.ipl[0] = regs.ipl_pin; + regs.ipl[1] = 0; } // ipl check was too late, interrupt possible after following instruction void ipl_fetch_next(void) { - if (regs.ipl[1] != regs.ipl_pin) { + int c = cpu_cycles; + if (c - regs.ipl_pin_change_evt >= cpuipldelay4) { + regs.ipl[0] = regs.ipl_pin; + regs.ipl[1] = 0; + } else { regs.ipl[1] = regs.ipl_pin; } } @@ -933,8 +1045,7 @@ static void activate_trace(void) static void do_trace(void) { if (cpu_stopped) { - m68k_incpci(4); - cpu_stopped = 0; + return; } regs.trace_pc = regs.pc; if (regs.t0 && !regs.t1 && currprefs.cpu_model >= 68020) { @@ -967,11 +1078,26 @@ void MakeFromSR_x(int t0trace) SET_VFLG((regs.sr >> 1) & 1); SET_CFLG(regs.sr & 1); + if (regs.t1 == ((regs.sr >> 15) & 1) && + regs.t0 == ((regs.sr >> 14) & 1) && + regs.s == ((regs.sr >> 13) & 1) && + regs.m == ((regs.sr >> 12) & 1) && + regs.intmask == ((regs.sr >> 8) & 7)) + return; + regs.t1 = (regs.sr >> 15) & 1; regs.t0 = (regs.sr >> 14) & 1; - regs.s = (regs.sr >> 13) & 1; - regs.m = (regs.sr >> 12) & 1; - regs.intmask = (regs.sr >> 8) & 7; + regs.s = (regs.sr >> 13) & 1; + regs.m = (regs.sr >> 12) & 1; + + if (regs.intmask != ((regs.sr >> 8) & 7)) { + int newimask = (regs.sr >> 8) & 7; + // STOP intmask change enabling already active interrupt: delay it by 1 STOP round + if (t0trace < 0 && regs.ipl[0] <= regs.intmask && regs.ipl[0] > newimask && regs.ipl[0] < 7) { + regs.ipl[0] = 0; + } + regs.intmask = newimask; + } if (currprefs.cpu_model >= 68020) { /* 68060 does not have MSP but does have M-bit.. */ @@ -1021,7 +1147,7 @@ void MakeFromSR_x(int t0trace) } // STOP SR-modification does not generate T0 // If this SR modification set Tx bit, no trace until next instruction. - if ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1) { + if (!cpu_stopped && ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1)) { // Always trace if Tx bits were already set, even if this SR modification cleared them. activate_trace(); } @@ -1220,7 +1346,7 @@ static void doexcstack(void) exception3_read(regs.ir | flags, test_exception_addr, 1, 2); } -uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode) +void REGPARAM2 op_illg_1_noret(uae_u32 opcode) { if ((opcode & 0xf000) == 0xf000) { if (currprefs.cpu_model == 68030) { @@ -1229,7 +1355,7 @@ uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode) // we can't test any MMU opcodes without parsing following word. TODO. if ((opcode & 0xfe00) == 0xf000) { test_exception = -1; - return 0; + return; } } test_exception = 11; @@ -1242,25 +1368,39 @@ uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode) test_exception = 4; } doexcstack(); - return 0; } void REGPARAM2 op_unimpl(uae_u32 opcode) { test_exception = 61; doexcstack(); } -uae_u32 REGPARAM2 op_unimpl_1(uae_u32 opcode) +void REGPARAM2 op_unimpl_1_noret(uae_u32 opcode) { if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060) { - op_illg(opcode); + op_illg_noret(opcode); } else { op_unimpl(opcode); } +} +uae_u32 REGPARAM2 op_unimpl_1(uae_u32 opcode) +{ + op_unimpl_1_noret(opcode); + return 0; +} + +void REGPARAM2 op_illg_noret(uae_u32 opcode) +{ + op_illg_1_noret(opcode); +} +uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode) +{ + op_illg_1_noret(opcode); return 0; } uae_u32 REGPARAM2 op_illg(uae_u32 opcode) { - return op_illg_1(opcode); + op_illg_1_noret(opcode); + return 0; } static void exception3_pc_inc(void) @@ -1423,7 +1563,7 @@ void exception3_read_prefetch_only(uae_u32 opcode, uae_u32 addr) regs.irc = regs.read_buffer; regs.read_buffer = prev; } else { - add_memory_cycles(1); + add_memory_cycles(addr, 1); } test_exception = 3; test_exception_3_w = 0; @@ -1441,7 +1581,7 @@ void exception3_read_prefetch(uae_u32 opcode, uae_u32 addr) if (cpu_lvl == 1) { get_word_test(addr & ~1); } else { - add_memory_cycles(1); + add_memory_cycles(addr, 1); } exception3_pc_inc(); @@ -1461,7 +1601,7 @@ void exception3_read_prefetch_68040bug(uae_u32 opcode, uae_u32 addr, uae_u16 sec if (cpu_lvl == 1) { get_word_test(addr & ~1); } else { - add_memory_cycles(1); + add_memory_cycles(addr, 1); } exception3_pc_inc(); @@ -1490,20 +1630,20 @@ void exception3_read_access(uae_u32 opcode, uae_u32 addr, int size, int fc) if (cpu_lvl == 1) { get_word_test(addr & ~1); } else { - add_memory_cycles(1); + add_memory_cycles(addr, 1); } exception3_read(opcode, addr, size, fc); } void exception3_write_access(uae_u32 opcode, uae_u32 addr, int size, uae_u32 val, int fc) { - add_memory_cycles(1); + add_memory_cycles(addr, 1); exception3_write(opcode, addr, size, val, fc); } uae_u16 exception3_word_read(uaecptr addr) { - add_memory_cycles(1); + add_memory_cycles(addr, 1); return 0; } @@ -1974,10 +2114,11 @@ static void compressfiles(const TCHAR *dir) static void mergefiles(const TCHAR *dir) { int tsize = 0; + int mergecount = 0; FILE *of = NULL; int oi = -1; unsigned char zero[4] = { 0, 0, 0, 0 }; - unsigned char head[4] = { 0xff, 0xff, 0xff, 0xff }; + unsigned char head[4] = { 0xaf, 'M', 'R', 'G'}; TCHAR opath[1000]; for (int i = 0; i < filecount; i++) { TCHAR path[1000]; @@ -2018,6 +2159,7 @@ static void mergefiles(const TCHAR *dir) wprintf(_T("Couldn't open '%s'\n"), opath); abort(); } + mergecount++; } if (oi != i) { _tunlink(path); @@ -2040,6 +2182,7 @@ static void mergefiles(const TCHAR *dir) fwrite(zero, 1, 4, of); fclose(of); } + wprintf(_T("Number of files after merge: %d -> %d\n"), filecount, mergecount); } static void save_memory(const TCHAR *path, const TCHAR *name, uae_u8 *p, int size) @@ -2069,7 +2212,6 @@ static void deletefile(const TCHAR *path, const TCHAR *name) _tunlink(path2); } - static uae_u8 *modify_reg(uae_u8 *dst, struct regstruct *regs, uae_u8 type, uae_u32 *valp) { int mode = type & CT_DATA_MASK; @@ -2283,7 +2425,7 @@ static uae_u8 *store_reg(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d, int siz return dst; } -static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old, bool header) +static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old) { if (!len) return dst; @@ -2310,11 +2452,6 @@ static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old, } // end offset = start - oldstart; - if (offset > 7) { - start -= (offset - 7); - old -= (offset - 7); - offset = 7; - } len -= offset; if (old) { for (int i = len - 1; i >= 0; i--) { @@ -2326,18 +2463,16 @@ static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old, } if (!len) return dst; - if (header) { - *dst++ = CT_MEMWRITES | CT_PC_BYTES; - } - if (len > 32) { - *dst++ = (offset << 5) | 31; + *dst++ = CT_MEMWRITES | CT_PC_BYTES; + if ((len > 32 || offset > 7) || (len == 31 && offset == 7)) { + *dst++ = 0xff; + *dst++ = offset; *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++; } return dst; } @@ -2470,6 +2605,12 @@ static void save_data(uae_u8 *dst, const TCHAR *dir, int size) (feature_min_interrupt_mask << 20) | (safe_memory_mode << 23) | (feature_interrupts << 26) | ((feature_loop_mode_jit ? 1 : 0) << 28) | ((feature_loop_mode_68010 ? 1 : 0) << 29)); fwrite(data, 1, 4, f); + pl(data, (feature_initial_interrupt_mask & 7)); + fwrite(data, 1, 4, f); + pl(data, 0); + fwrite(data, 1, 4, f); + pl(data, 0); + fwrite(data, 1, 4, f); pl(data, currprefs.fpu_model); fwrite(data, 1, 4, f); pl(data, test_low_memory_start); @@ -2832,7 +2973,10 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str if (currprefs.cpu_model >= 68020) v &= ~0x100; ereg = v >> 12; - if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 7 || ((1 << ereg) & ignore_register_mask))) { + if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 7)) { + continue; + } + if ((1 << ereg) & ignore_register_mask) { continue; } break; @@ -2916,6 +3060,7 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str uae_u32 v; if (!high_memory && !low_memory) return -1; + test_absw = 1; for (;;) { v = rand16(); if (immabsw_cnt & 1) @@ -3162,11 +3307,15 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str else *isconstant = -1; } else { - put_word_test(pc, imm16_cnt); + if (dp->mnemo == i_STOP) { + put_word_test(pc, imm16_cnt | 0x2000); + } else { + put_word_test(pc, imm16_cnt); + } if (dp->mnemo == i_STOP && feature_interrupts > 0) { // STOP hack to keep STOP test size smaller. - if (feature_interrupts > 1) { - imm16_cnt += 0x0100; + if (feature_interrupts > 0) { + imm16_cnt += 0x0080; } else { imm16_cnt += 0x0001; } @@ -3342,9 +3491,10 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru } case absw: { - if (target >= test_low_memory_start && target < test_low_memory_end) { + if ((target >= test_low_memory_start && target < test_low_memory_end) || (target >= test_high_memory_start && target < test_high_memory_end)) { put_word_test(pc, target); *eap = target; + test_absw = 1; return 2; } return -2; @@ -4012,17 +4162,16 @@ static const int interrupt_levels[] = 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6 }; -static bool check_interrupts(void) +static void check_interrupts(void) { if (feature_interrupts == 1) { int ic = interrupt_count & 15; int lvl = interrupt_levels[ic]; if (lvl > 0 && lvl > feature_min_interrupt_mask) { - Exception(24 + lvl); - return true; + regs.ipl_pin = lvl; + return; } } - return false; } static int get_ipl(void) @@ -4035,7 +4184,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool uae_u16 opc = regs.ir; int off = opcode_memory_address - opcode_memory_start + 2; uae_u16 opw1 = (opcode_memory[off + 0] << 8) | (opcode_memory[off + 1] << 0); - uae_u16 opw2 = (opcode_memory[off + 2] << 8) | (opcode_memory[off + 2] << 0); + uae_u16 opw2 = (opcode_memory[off + 2] << 8) | (opcode_memory[off + 3] << 0); if (opc == 0x4e72 && opw1 == 0xa000 //&& opw2 == 0x4afc @@ -4072,16 +4221,37 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool exception_extra_frame_type = 0; cpu_cycles = 0; regs.loop_mode = 0; - regs.ipl_pin = 0; + regs.ipl_pin = feature_initial_interrupt; + interrupt_level = regs.ipl_pin; regs.ipl[0] = regs.ipl[1] = 0; + regs.ipl_evt_pre = 0; + regs.ipl_evt = 0; interrupt_level = 0; interrupt_cycle_cnt = 0; test_exception_orig = 0; + waitstate_cycle_cnt = 0; + cpuipldelay2 = 2; + cpuipldelay4 = 4; int cnt = 2; uaecptr first_pc = regs.pc; uae_u32 loop_mode_reg = 0; int stop_count = 0; + bool starts = regs.s; + int startimask = regs.intmask; + bool imaskintprevented = false; + + if (regs.ipl_pin > regs.intmask) { + wprintf(_T("Interrupt immediately active! IPL=%d IMASK=%d\n"), regs.ipl_pin, regs.intmask); + abort(); + } + if (feature_interrupts == 1) { + check_interrupts(); + if (regs.ipl_pin > regs.intmask) { + Exception(24 + regs.ipl_pin); + goto end; + } + } if (feature_loop_mode_68010) { // 68010 loop mode @@ -4093,9 +4263,6 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool if (multi_mode) { cnt = 100; } - if (feature_interrupts >= 2) { - interrupt_cycle_cnt = INTERRUPT_CYCLES; - } for (;;) { @@ -4119,9 +4286,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool do_trace(); } - if (check_interrupts()) { - break; - } + check_interrupts(); regs.instruction_pc = regs.pc; regs.fp_ea_set = false; @@ -4143,10 +4308,11 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool } } - (*cpufunctbl[opc])(opc); + test_opcode = opc; + (*cpufunctbl_noret[opc])(opc); if (fpumode) { - // skip result has too large or small exponent + // skip result if it has too large or small exponent for (int i = 0; i < 8; i++) { if (regs.fp[i].fpx.high != cur_regs.fp[i].fpx.high || regs.fp[i].fpx.low != cur_regs.fp[i].fpx.low) { int exp = regs.fp[i].fpx.high & 0x7fff; @@ -4176,11 +4342,6 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool break; } - // CPU stopped or was reset: skip - if (cpu_stopped && feature_interrupts < 2) { - break; - } - // Supervisor mode and A7 was modified and not RTE+stack mode: skip this test round. if (s && regs.s && regs.regs[15] != a7 && (dp->mnemo != i_RTE || feature_usp < 3)) { // but not if RTE @@ -4206,23 +4367,51 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool break; } - if (get_ipl() > regs.intmask) { - Exception(24 + get_ipl()); - break; - } - regs.ipl[0] = regs.ipl[1]; - regs.ipl[1] = 0; - - if ((regs.pc == endpc || regs.pc == targetpc) && !cpu_stopped && feature_interrupts < 2) { + if (((regs.pc == endpc && feature_interrupts < 2) || (regs.pc == targetpc && feature_interrupts < 2)) && !cpu_stopped) { // 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 && trace_store_pc == 0xffffffffff) { Exception(9); + break; } + } - break; + if (feature_interrupts >= 1) { + if (SPCFLAG_DOTRACE) { + if (trace_store_pc != 0xffffffff) { + wprintf(_T(" Full trace in interrupt mode!?\n")); + abort(); + } + MakeSR(); + if (cpu_stopped) { + cpu_stopped = 0; + m68k_incpci(4); + regs.ir = get_iword_test(regs.pc + 0); + regs.irc = get_iword_test(regs.pc + 2); + } + trace_store_pc = regs.pc; + trace_store_sr = regs.sr; + SPCFLAG_DOTRACE = 0; + // pending interrupt always triggers during trace processing + regs.ipl[0] = regs.ipl_pin; + } + } + + int ipl = get_ipl(); + if (ipl > 0) { + if (ipl > regs.intmask) { + Exception(24 + ipl); + break; + } + if (ipl > startimask && ipl <= regs.intmask && !imaskintprevented) { + printf("*"); + imaskintprevented = true; + } } + regs.ipl[0] = regs.ipl[1]; + regs.ipl[1] = 0; + if (test_exception) { break; } @@ -4233,6 +4422,10 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool if (!feature_loop_mode_jit && !feature_loop_mode_68010) { // trace after NOP if (SPCFLAG_DOTRACE) { + if (feature_interrupts == 3) { + Exception(9); + break; + } MakeSR(); // store only first if (trace_store_pc == 0xffffffff) { @@ -4266,6 +4459,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool opc = regs.ir; } +end: test_exception_orig = test_exception; // if still stopped: skip test @@ -4274,8 +4468,12 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool } if (feature_interrupts >= 2) { - // Skip test if end exception - if (regs.pc == endpc || regs.pc == targetpc) { + // Skip test if end exception and no prevented interrupt + if ((regs.pc == endpc || regs.pc == targetpc) && !imaskintprevented) { + test_exception = -1; + } + // skip if check or privilege violation + if (test_exception == 6 || test_exception == 8) { test_exception = -1; } // Skip test if no exception @@ -4288,11 +4486,18 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool if (test_exception >= 24 && test_exception <= 24 + 8) { if (test_exception_addr != opcode_memory_address && test_exception_addr != opcode_memory_address - 2 && + test_exception_addr != test_instruction_end_pc - 4 && + test_exception_addr != test_instruction_end_pc - 2 && test_exception_addr != test_instruction_end_pc && - test_exception_addr != branch_target) { + test_exception_addr != branch_target && + test_exception_addr != branch_target + 2) { test_exception = -1; } } + if (starts && (test_exception >= 24 && test_exception <= 24 + 8)) { + printf(""); + } + } testing_active = 0; @@ -4630,7 +4835,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int quick = 0; int rounds = feature_test_rounds; int data_saved = 0; - int first_cycles = 1; + int first_save = 1; int count = 0; @@ -4641,6 +4846,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } ignore_register_mask = 0; + ignore_register_mask |= 1 << 15; // SP if (feature_loop_mode_register >= 0) { ignore_register_mask |= 1 << feature_loop_mode_register; } @@ -4727,8 +4933,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi full_format_cnt = 0; last_exception_len = -1; interrupt_count = 0; - interrupt_delay_cnt = 0; + interrupt_pc = 0; + waitstate_delay_cnt = 0; int sr_override = 0; @@ -4791,7 +4998,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } dst = store_reg(dst, CT_FPIAR, 0, cur_regs.fpiar, -1); } - cur_regs.sr = feature_min_interrupt_mask << 8; + cur_regs.sr = feature_initial_interrupt_mask << 8; uae_u32 srcaddr_old = 0xffffffff; uae_u32 dstaddr_old = 0xffffffff; @@ -4832,6 +5039,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // skip all unsupported instructions if not specifically testing i_ILLG if (dp->clev > cpu_lvl) continue; + if (dp->ccuse && !(feature_condition_codes & (1 << dp->cc))) + continue; } if (feature_loop_mode_68010) { @@ -4897,6 +5106,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi constant_loops = 1; } } + if (feature_interrupts) { + constant_loops = 1; + } while (constant_loops-- > 0) { uae_u8 oldcodebytes[OPCODE_AREA]; @@ -4938,6 +5150,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi test_exception_extra = 0; lm_safe_address1 = 0xffffffff; lm_safe_address2 = 0xffffffff; + test_absw = 0; target_ea[0] = target_ea_bak[0]; target_ea[1] = target_ea_bak[1]; @@ -4982,15 +5195,17 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // interrupt IPL timing test mode if (feature_interrupts >= 2) { pc -= 2; - // save CCR - if (cpu_lvl == 0) { - // move sr,d7 - put_word_test(pc + 0, 0x40c7); // 4 cycles - } else { - // move ccr,d7 - put_word_test(pc + 0, 0x42c7); // 4 cycles + if (!feature_waitstates) { + // save CCR + if (cpu_lvl == 0) { + // move sr,d7 + put_word_test(pc + 0, 0x40c7); // 4 cycles + } else { + // move ccr,d7 + put_word_test(pc + 0, 0x42c7); // 4 cycles + } + pc += 2; } - pc += 2; #if IPL_TRIGGER_ADDR_SIZE == 1 // move.b #x,xxx.L (4 * 4 + 4) put_long_test(pc, (0x13fc << 16) | IPL_TRIGGER_DATA); @@ -5026,20 +5241,30 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // ror.l d0,d0 (4 + 4 + d0 * 2 cycles) put_word_test(pc, 0xe0b8); pc += 2; - // restore CCR - // move d7,ccr - put_word_test(pc, 0x44c7); // 12 cycles - pc += 2; - put_word_test(pc, NOP_OPCODE); // 4 cycles - pc += 2; - put_word_test(pc, NOP_OPCODE); // 4 cycles + if (feature_waitstates) { + // move.w #x,0xdff058 + put_long_test(pc, (0x33fc << 16) | (2 * 64 + 63)); + pc += 4; + put_long_test(pc, IPL_BLTSIZE); + pc += 4; + // lsl.b #1+,d0 + put_word_test(pc, 0xe308 + waitstate_delay_cnt * 0x200); // 4+n*2 cycles + pc += 2; + } + if (!feature_waitstates) { + // restore CCR + // move d7, ccr + put_word_test(pc, 0x44c7); // 12 cycles + pc += 2; + } + put_word_test(pc, REAL_NOP_OPCODE); // 4 cycles pc += 2; if (feature_interrupts >= 3) { // or #$8000,sr put_long_test(pc, 0x007c8000); pc += 4; } else { - put_word_test(pc, NOP_OPCODE); // 4 cycles + put_word_test(pc, IPL_TEST_NOP1); // 4 cycles pc += 2; } opcode_memory_address = pc; @@ -5185,6 +5410,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } + if (feature_interrupts >= 2) { + put_long_test(pc, (IPL_TEST_NOP2 << 16) | REAL_NOP_OPCODE); // 8 cycles + pc += 4; + } + // if bus error stack checking and RTE: copy USP to ISP before RTE if (dp->mnemo == i_RTE && feature_usp == 3) { put_word_test(opcode_memory_address, 0x4e6f); // MOVE USP,A7 @@ -5348,9 +5578,6 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi srcaddr = 0xffffffff; dstaddr = 0xffffffff; - if (opc == 0x4efb && get_word_debug(opcode_memory_address + 2) == 0x06d4) - printf(""); - uae_u32 dflags = m68k_disasm_2(out, sizeof(out) / sizeof(TCHAR), opcode_memory_address, NULL, 0, &nextpc, 1, &srcaddr, &dstaddr, 0xffffffff, 0); if (verbose) { my_trim(out); @@ -5375,10 +5602,6 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } - - if (srcaddr == 0x006b022e) - printf(""); - // disassembler may set this out_of_test_space = false; @@ -5523,11 +5746,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } - if (subtest_count == 262144) + if (subtest_count > 0) printf(""); // save opcode memory - dst = store_mem_bytes(dst, opcode_memory_start, instruction_end_pc - opcode_memory_start, oldcodebytes, true); + dst = store_mem_bytes(dst, opcode_memory_start, instruction_end_pc - opcode_memory_start, oldcodebytes); // store branch target and stack modifications (these needs to be rolled back after the test) dst = store_mem_writes(dst, 1); @@ -5565,6 +5788,12 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi dst = store_reg(dst, CT_AREG + 7, 0, target_usp_address, sz_long); } + if (feature_interrupts >= 2) { + *dst++ = CT_EDATA; + *dst++ = CT_EDATA_IRQ_CYCLES; + *dst++ = interrupt_delay_cnt; + } + // pre-test data end *dst++ = CT_END_INIT; @@ -5761,7 +5990,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } else { regs.sr = ((ccr & 1) ? 31 : 0) | sr_mask; } - regs.sr |= feature_min_interrupt_mask << 8; + if (feature_initial_interrupt_mask > ((regs.sr >> 8) & 7)) { + regs.sr &= ~(7 << 8); + regs.sr |= feature_initial_interrupt_mask << 8; + } // override special register values for (int i = 0; i < regdatacnt; i++) { @@ -5787,7 +6019,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (regs.sr & 0x2000) prev_s_cnt++; - if (subtest_count == 77171) + if (subtest_count == 9) printf(""); // execute test instruction(s) @@ -5901,10 +6133,12 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } else if (test_exception) { // generated exception exception_array[test_exception]++; - if (test_exception == 8 && !(sr_mask & 0x2000) && !(feature_sr_mask & 0x2000)) { - // Privilege violation exception and S mask not set? Switch to super mode in next round. - sr_mask_request |= 0x2000; - sr_allowed_mask |= 0x2000; + if (test_exception == 8) { + if (!(sr_mask & 0x2000) && !(feature_sr_mask & 0x2000)) { + // Privilege violation exception and S mask not set? Switch to super mode in next round. + sr_mask_request |= 0x2000; + sr_allowed_mask |= 0x2000; + } } // got exception 3 but didn't want them? if (test_exception == 3) { @@ -5988,21 +6222,21 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi for (int i = 0; i < MAX_REGISTERS; i++) { uae_u32 s = last_regs.regs[i]; uae_u32 d = regs.regs[i]; - if (s != d) { + if (s != d || first_save) { if (storeregs) { - dst = store_reg(dst, CT_DREG + i, s, d, -1); + dst = store_reg(dst, CT_DREG + i, s, d, first_save ? sz_long : -1); } last_regs.regs[i] = d; } } // SR/CCR uae_u32 ccrignoremask = get_ccr_ignore(dp, extraword, false) << 16; - if ((regs.sr | ccrignoremask) != last_regs.sr) { - dst = store_reg(dst, CT_SR, last_regs.sr, regs.sr | ccrignoremask, -1); + if ((regs.sr | ccrignoremask) != last_regs.sr || first_save) { + dst = store_reg(dst, CT_SR, last_regs.sr, regs.sr | ccrignoremask, first_save ? sz_word : -1); last_regs.sr = regs.sr | ccrignoremask; } // PC - if (regs.pc - extraopcodeendsize != last_regs.pc) { + if (regs.pc - extraopcodeendsize != last_regs.pc || first_save) { dst = store_rel(dst, CT_PC, last_regs.pc, regs.pc - extraopcodeendsize, 0); last_regs.pc = regs.pc - extraopcodeendsize; } @@ -6011,29 +6245,31 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi for (int i = 0; i < 8; i++) { floatx80 s = last_regs.fp[i].fpx; floatx80 d = regs.fp[i].fpx; - if (s.high != d.high || s.low != d.low) { + if (s.high != d.high || s.low != d.low || first_save) { dst = store_fpureg(dst, CT_FPREG + i, &s, d, 0); last_regs.fp[i].fpx = d; } } - if (regs.fpiar != last_regs.fpiar) { - dst = store_reg(dst, CT_FPIAR, last_regs.fpiar, regs.fpiar, -1); + if (regs.fpiar != last_regs.fpiar || first_save) { + dst = store_reg(dst, CT_FPIAR, last_regs.fpiar, regs.fpiar, first_save ? sz_long : -1); last_regs.fpiar = regs.fpiar; } - if (regs.fpsr != last_regs.fpsr) { - dst = store_reg(dst, CT_FPSR, last_regs.fpsr, regs.fpsr, -1); + if (regs.fpsr != last_regs.fpsr || first_save) { + dst = store_reg(dst, CT_FPSR, last_regs.fpsr, regs.fpsr, first_save ? sz_long : -1); last_regs.fpsr = regs.fpsr; } - if (regs.fpcr != last_regs.fpcr) { - dst = store_reg(dst, CT_FPCR, last_regs.fpcr, regs.fpcr, -1); + if (regs.fpcr != last_regs.fpcr || first_save) { + dst = store_reg(dst, CT_FPCR, last_regs.fpcr, regs.fpcr, first_save ? sz_long : -1); last_regs.fpcr = regs.fpcr; } } - if (cpu_lvl <= 1 && (last_cpu_cycles != cpu_cycles || first_cycles)) { - dst = store_reg(dst, CT_CYCLES, last_cpu_cycles, cpu_cycles, first_cycles ? sz_word : -1); + if (cpu_lvl <= 1 && (last_cpu_cycles != cpu_cycles || first_save)) { + dst = store_reg(dst, CT_CYCLES, last_cpu_cycles, cpu_cycles, first_save ? sz_word : -1); last_cpu_cycles = cpu_cycles; - first_cycles = 0; } + + first_save = 0; + // store test instruction generated changes dst = store_mem_writes(dst, 0); uae_u8 bcflag = regs.pc == branch_target_pc ? CT_BRANCHED : 0; @@ -6115,10 +6351,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } if (verbose) { - wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d STP=%d I=%d/%d EX=%d %08x %08x"), ok, exception_array[0], + wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d S=%d I=%d/%d EX=%d %08x %08x %08x"), ok, exception_array[0], prev_s_cnt, s_cnt, t_cnt, cnt_stopped, interrupt_delay_cnt, interrupt_cycle_cnt, test_exception_orig, - test_exception_addr, regs.pc); + test_exception_addr, regs.pc, interrupt_pc); if (!ccr_done) wprintf(_T(" X")); for (int i = 2; i < 128; i++) { @@ -6212,7 +6448,15 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // interrupt delay test if (feature_interrupts >= 2) { - interrupt_delay_cnt++; + if (feature_waitstates) { + waitstate_delay_cnt++; + if (waitstate_delay_cnt >= 3) { + waitstate_delay_cnt = 0; + interrupt_delay_cnt++; + } + } else { + interrupt_delay_cnt++; + } if (interrupt_delay_cnt > 2 * 63) { break; } else { @@ -6447,6 +6691,12 @@ static const TCHAR *addrmodes[] = _T("absw"), _T("absl"), _T("PC16"), _T("PC8r"), _T("imm"), _T("Ad8rf"), _T("PC8rf"), NULL }; +static const TCHAR *ccnames[] = +{ + _T("T"), _T("F"), _T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"), + _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE") +}; + #define INISECTION _T("cputest") @@ -6717,6 +6967,7 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna feature_addressing_modes[1] = 0xffffffff; ad8r[0] = ad8r[1] = 1; pc8r[0] = pc8r[1] = 1; + feature_condition_codes = 0xffffffff; feature_exception3_data = 0; ini_getvalx(ini, sections, _T("feature_exception3_data"), &feature_exception3_data); @@ -6869,6 +7120,12 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna feature_undefined_ccr = 0; ini_getvalx(ini, sections, _T("feature_undefined_ccr"), &feature_undefined_ccr); + feature_initial_interrupt = 0; + ini_getvalx(ini, sections, _T("feature_initial_interrupt"), &feature_initial_interrupt); + + feature_initial_interrupt_mask = 0; + ini_getvalx(ini, sections, _T("feature_initial_interrupt_mask"), &feature_initial_interrupt_mask); + feature_min_interrupt_mask = 0; ini_getvalx(ini, sections, _T("feature_min_interrupt_mask"), &feature_min_interrupt_mask); @@ -6900,6 +7157,8 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna ini_getvalx(ini, sections, _T("feature_exception_vectors"), &feature_exception_vectors); feature_interrupts = 0; ini_getvalx(ini, sections, _T("feature_interrupts"), &feature_interrupts); + feature_waitstates = 0; + ini_getvalx(ini, sections, _T("feature_waitstates"), &feature_waitstates); feature_full_extension_format = 0; if (currprefs.cpu_model >= 68020) { @@ -6953,6 +7212,29 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna } } + TCHAR *cc = NULL; + if (ini_getstringx(ini, sections, _T("feature_condition_codes"), &cc)) { + feature_condition_codes = 0; + TCHAR *p = cc; + while (p && *p) { + TCHAR *pp = _tcschr(p, ','); + if (pp) { + *pp++ = 0; + } + TCHAR cctext[256]; + _tcscpy(cctext, p); + my_trim(cctext); + for (int i = 0; ccnames[i]; i++) { + if (!_tcsicmp(ccnames[i], cctext)) { + feature_condition_codes |= 1 << i; + break; + } + } + p = pp; + } + xfree(cc); + } + TCHAR *mode = NULL; ini_getstringx(ini, sections, _T("mode"), &mode); @@ -7198,11 +7480,12 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna for (int opcode = 0; opcode < 65536; opcode++) { cpufunctbl[opcode] = op_illg_1; + cpufunctbl_noret[opcode] = op_illg_1_noret; } - - for (int i = 0; tbl[i].handler_ff != NULL; i++) { + for (int i = 0; tbl[i].handler_ff != NULL || tbl[i].handler_ff_noret != NULL; i++) { int opcode = tbl[i].opcode; cpufunctbl[opcode] = tbl[i].handler_ff; + cpufunctbl_noret[opcode] = tbl[i].handler_ff_noret; cpudatatbl[opcode].length = tbl[i].length; cpudatatbl[opcode].disp020[0] = tbl[i].disp020[0]; cpudatatbl[opcode].disp020[1] = tbl[i].disp020[1]; @@ -7210,7 +7493,6 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna } for (int opcode = 0; opcode < 65536; opcode++) { - cpuop_func *f; instr *table = &table68k[opcode]; if (table->mnemo == i_ILLG) @@ -7224,6 +7506,7 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna // generates unimplemented instruction exception. if (currprefs.int_no_unimplemented && table->unimpclev == 5) { cpufunctbl[opcode] = op_unimpl_1; + cpufunctbl_noret[opcode] = op_unimpl_1_noret; continue; } // remove unimplemented instruction that were removed in previous models, @@ -7232,10 +7515,11 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna // clev=4: implemented in 68040 or later. unimpclev=5: not in 68060 if (table->unimpclev < 5 || (table->clev == 4 && table->unimpclev == 5)) { cpufunctbl[opcode] = op_illg_1; + cpufunctbl_noret[opcode] = op_illg_1_noret; continue; } } else { - cpufunctbl[opcode] = op_illg_1; + cpufunctbl_noret[opcode] = op_illg_1_noret; continue; } } @@ -7252,10 +7536,10 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna if (table->handler != -1) { int idx = table->handler; - f = cpufunctbl[idx]; - if (f == op_illg_1) + if (cpufunctbl[idx] == op_illg_1 || cpufunctbl_noret[idx] == op_illg_1_noret) abort(); - cpufunctbl[opcode] = f; + cpufunctbl[opcode] = cpufunctbl[idx]; + cpufunctbl_noret[opcode] = cpufunctbl_noret[idx]; memcpy(&cpudatatbl[opcode], &cpudatatbl[idx], sizeof(struct cputbl_data)); } diff --git a/cputest/amiga.S b/cputest/amiga.S index 2470430a..6fe792c6 100644 --- a/cputest/amiga.S +++ b/cputest/amiga.S @@ -6,6 +6,8 @@ .globl _allocate_absolute .globl _free_absolute + .globl _allocate_blttemp + .globl _free_blttemp .globl _touser .globl _tosuper .globl _testexit @@ -44,12 +46,29 @@ uaefuncname: .asciz "uaelib_demux" sync: + move.l a1,d0 + lea 0xdff040,a1 + move.w #0x0400+0x200+0x0100,(a1)+ | BCD + move.w #0x0000,(a1)+ + addq.l #4,a1 + move.l d0,(a1)+ | A + move.l d0,(a1)+ | B + move.l d0,(a1)+ | C + move.l d0,(a1)+ | D move.b 0xdff006,d0 beq.s sync - cmp.b #0xff,d0 - beq.s sync - cmp.b #0x38,d0 - beq.s sync + cmp.b #0xfc,d0 + bcc.s sync + cmp.b #0x34,d0 + bcs.s sync2 + cmp.b #0x39,d0 + bcs.s sync +sync2: + move.b 0xdff007,d0 + cmp.b #110,d0 + bcs.s sync2 + cmp.b #130,d0 + bcc.s sync2 | above prevent wraparound between | dff004.w and dff006.w reads move.l 0xdff004,d0 @@ -70,9 +89,11 @@ _tosuper: move.l 4.w,a6 jsr -0x78(a6) | Disable jsr -0x96(a6) | SuperState + move.w 0xdff002,dmacon tst.l 8+1*4(sp) beq.s .keepdisplay - move.w #0x0200,0xdff096 + move.w #0x7fff,0xdff096 + move.w #0x8000+0x0400+0x0200+0x0040,0xdff096 .keepdisplay: move.w #0x2700,sr move.l (sp)+,a6 @@ -84,7 +105,10 @@ _touser: move.l 4.w,a6 move.l 8(sp),d0 jsr -0x9c(a6) | UserState - move.w #0x8200,0xdff096 + move.w #0x7fff,0xdff096 + move.w dmacon,d0 + or.w #0x8000,d0 + move.w d0,0xdff096 jsr -0x7e(a6) | Enable move.l (sp)+,a6 rts @@ -109,6 +133,24 @@ _allocate_absolute: move.l (sp)+,a6 rts +_allocate_blttemp: + move.l a6,-(sp) + move.l 8(sp),d0 + move.l #65536+2,d1 + move.l 4.w,a6 + jsr -0xc6(a6) | AllocMem + move.l (sp)+,a6 + rts +_free_blttemp: + move.l a6,-(sp) + move.l 8(sp),a1 + move.l 12(sp),d0 + move.l 4.w,a6 + jsr -0xd2(a6) | FreeMem + move.l (sp)+,a6 + rts + + | return CPU model (68000=0, 68010=1, 68020=2, 68030=3, 68040=4, 68060=5) _get_cpu_model: move.l 4.w,a0 @@ -151,4 +193,7 @@ illg: move.l a1,sp rte +dmacon: + dc.l 0 + .include "asm.S" diff --git a/cputest/asm.S b/cputest/asm.S index 0d2616e5..79ef69c5 100644 --- a/cputest/asm.S +++ b/cputest/asm.S @@ -43,7 +43,8 @@ S_TRACESTACK = S_TRACECNT+4 S_CYCLES = S_TRACESTACK+12 S_CYCLES2 = S_CYCLES+4 S_CYCLEST = S_CYCLES2+4 -S_FPU = S_CYCLEST+4 +S_BLTTEMP = S_CYCLEST+4 +S_FPU = S_BLTTEMP+4 S_FPIAR = S_FPU+8*12 S_FPCR = S_FPIAR+4 S_FPSR = S_FPCR+4 @@ -202,6 +203,7 @@ _execute_test000: move.w S_SR+2(a0),-(sp) move.l S_AREG+7*4(a0),a1 move.l a1,USP + move.l S_BLTTEMP(a0),a1 bsr sync move.l d0,S_CYCLES2(a0) movem.l (a0),d0-d7/a0-a6 @@ -292,6 +294,7 @@ exception_trace000: move.w sr,-(sp) _cyclereg_address3: move.w CYCLEREG,cycles+4 + | pop SR and bsr.s exception_trace000 addq.l #2+4,sp move.l a0,-(sp) move.l datapointer(pc),a0 @@ -364,16 +367,23 @@ _cyclereg_address4: bcs.s .okpc cmp.l #asm_end,2+4+2(sp) bhi.s .okpc - | interrupt? - cmp.l #_exceptiontable000+24*2,2(sp) - bcs.s .okpc - cmp.l #_exceptiontable000+(24+8)*2,2(sp) - bcc.s .okpc - | possibly IPL tester spurious interrupt - | ignore it. Mark cycle count as invalid. -#ifdef AMIGA - move.w #0x0800,0xdff09c -#endif + move.w #0x7fff,0xdff09c + | Interrupt exception interrupted trace? + cmp.l #_exceptiontable000+(9-2)*2,2+4+2(sp) + bne.s .notokpc + | Store trace, copy trace PC/SR to interrupt PC/SR + move.l a0,-(sp) + move.l datapointer(pc),a0 + move.l 4+2+6+4+0(sp),S_TRACESTACK(a0) + move.l 4+2+6+4+4(sp),S_TRACESTACK+4(a0) + | set exception PC and SR same as Trace + move.w 4+2+6+4+0(sp),4+2+4+0(sp) + move.l 4+2+6+4+2(sp),4+2+4+2(sp) + addq.l #1,S_TRACECNT(a0) + move.l (sp)+,a0 + bra.s .okpc +.notokpc: + | Mark cycle count as invalid. move.l #0xffffffff,cycles addq.l #2+4,sp rte @@ -404,7 +414,7 @@ _cyclereg_address4: cmp.w #24+8,d0 bcc.s .nointerrupt #ifdef AMIGA - move.w #0x0800,0xdff09c + move.w #0x7fff,0xdff09c #endif .nointerrupt: diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index 8c79a2e5..c4a9af13 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -1,5 +1,5 @@ -#define DATA_VERSION 23 +#define DATA_VERSION 24 #define CT_FPREG 0 #define CT_DREG 0 @@ -55,13 +55,18 @@ // MOVEA.L A0,A0 // not NOP because on 68040 NOP generates T0 trace. #define NOP_OPCODE 0x2048 +#define REAL_NOP_OPCODE 0x4e71 #define ILLG_OPCODE 0x4afc #define LM_OPCODE 0x42db +#define IPL_TEST_NOP1 0x4e71 +#define IPL_TEST_NOP2 0x4e71 + #define IPL_TRIGGER_ADDR 0xdff030 #define IPL_TRIGGER_ADDR_SIZE 2 -#define IPL_TRIGGER_DATA 0x100 +#define IPL_TRIGGER_DATA (0x100 | 0xCA) #define IPL_TRIGGER_SERPER 10 -#define INTERRUPT_CYCLES ((((IPL_TRIGGER_SERPER + 1) * 9) + (((IPL_TRIGGER_SERPER + 1) - 1) / 2) + 1 + 3 + 9) * 2) +#define INTERRUPT_CYCLES ((((IPL_TRIGGER_SERPER + 1) * 9) + (((IPL_TRIGGER_SERPER + 1) - 1) / 2) + 1 + 3 + 9 + 0) * 2) #define IPL_TRIGGER_INTMASK 0x0800 #define IPL_TEST_IPL_LEVEL 5 +#define IPL_BLTSIZE 0xdff058 diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 69e139ae..3af7dcda 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -139,12 +139,18 @@ exceptions= ; 2 = always all zeros and all ones only feature_flags_mode=1 +; SR initial interrupt mask +feature_initial_interrupt_mask=0 + ; SR min interrupt mask ; Amiga: can be zero. ; Atari ST: should be 4 or larger. ; Skips all tests that would set lower interrupt mask. feature_min_interrupt_mask=0 +; Initial active interrupt level, 0 to 6. (Amiga only) +feature_initial_interrupt=0 + ; Interrupt test ; 1 = interrupt request is set before test. ; Tests all INTREQ bits one by one. Compatible with cycle count mode. @@ -202,6 +208,11 @@ feature_full_extension_format=0 feature_addressing_modes_src= feature_addressing_modes_dst= +; empty = all condition codes +; T, F, HI, LS, CC etc.. select condition codes to generate. All others will be skipped. +; Xcc instructions only. +feature_condition_codes= + ; Limit test instruction size ; B = byte, W = word, L = long, empty = no size limit ; FPU only: S = single, D = double, X = extended, P = packed @@ -234,10 +245,27 @@ feature_sr_mask=0x8000 [test=BASIC] cpu=68000-68010 enabled=0 +verbose=0 feature_sr_mask=0x8000 feature_undefined_ccr=1 mode=all +; interrupt timing test with waitstates +[test=WIPL] +cpu=68000-68010 +enabled=1 +verbose=0 +feature_undefined_ccr=1 +feature_interrupts=2 +feature_waitstates=2 +#feature_addressing_modes_src=dreg +feature_condition_codes= +# wait state mode requires use of chip ram +test_memory_start=0xd0000 +test_memory_size=0x20000 +rnd_seed=10 +mode=btst.b + ; interrupt timing test [test=IPL] cpu=68000-68010 @@ -245,17 +273,33 @@ enabled=1 verbose=0 feature_undefined_ccr=1 feature_interrupts=2 -;feature_sr_mask=0x2100 -mode=all +feature_sr_mask=0x2000 +#feature_addressing_modes_dst=apdi +feature_condition_codes=pl +rnd_seed=10 +mode=btst.b + +; STOP/SR modification timing special test +[test=SR] +cpu=68000-68010 +enabled=0 +verbose=0 +feature_undefined_ccr=1 +feature_interrupts=1 +feature_initial_interrupt_mask=4 +feature_sr_mask=0x8000 +#mode=stop,eorsr.w,andsr.w,mvsr2.w,mv2sr.w +mode=stop ; interrupt exception [test=IRQ] enabled=0 +verbose=0 cpu=68000-68010 feature_sr_mask=0x8000 feature_interrupts=1 feature_undefined_ccr=1 -mode=jsr,jmp,bsr,bcc,dbcc,nop,exg,swap,stop,mvsr2,mv2sr,andsr,eorsr,orsr +mode=jsr,jmp,bsr,bcc,dbcc,nop,exg,swap,stop,mvsr2.w,mv2sr.w,andsr.w,eorsr.w,orsr.w min_opcode_test_rounds=100 ; source EA address error diff --git a/cputest/main.c b/cputest/main.c index dfab4727..76c60cbc 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -49,6 +49,7 @@ struct registers uae_u32 tracecnt; uae_u16 tracedata[6]; uae_u32 cycles, cycles2, cyclest; + uae_u32 blttemp; struct fpureg fpuregs[8]; uae_u32 fpiar, fpcr, fpsr; @@ -77,6 +78,8 @@ static uae_u8 *test_memory; static uae_u32 test_memory_addr, test_memory_end; static uae_u32 test_memory_size; static uae_u8 *test_data; +#define BLT_TEMP_SIZE 8000 +static uae_u32 blt_data; static uae_u8 *safe_memory_start, *safe_memory_end; static short safe_memory_mode; static uae_u32 user_stack_memory, super_stack_memory; @@ -136,6 +139,8 @@ static uae_u8 ccr_mask; static uae_u32 fpsr_ignore_mask; static uae_u32 addressing_mask = 0x00ffffff; static uae_u32 interrupt_mask; +static short initial_interrupt_mask; +static short initial_interrupt; static short loop_mode_jit, loop_mode_68010, loop_mode_cnt; static short instructionsize; static short disasm; @@ -163,6 +168,8 @@ static uae_u16 main_intena; static int prealloc_test_data_size = 1001000; static int prealloc_gzip_size = 500000; static int prealloc; +static uae_u8 *debug_item_data; +static short debug_item_count; #define SIZE_STORED_ADDRESS_OFFSET 6 #define SIZE_STORED_ADDRESS 20 @@ -190,6 +197,13 @@ static uae_u8 *allocate_absolute(uae_u32 addr, uae_u32 size) static void free_absolute(uae_u32 addr, uae_u32 size) { } +static uae_u8 *allocate_blttemp(uae_u32 size) +{ + return calloc(1, size); +} +static void free_blttemp(uae_u32 addr, uae_u32 size) +{ +} static void execute_test000(struct registers *regs) { } @@ -245,6 +259,8 @@ static void xmemcpy(void *d, void *s, int size) extern uae_u8 *allocate_absolute(uae_u32, uae_u32); extern void free_absolute(uae_u32, uae_u32); +extern uae_u32 allocate_blttemp(uae_u32); +extern void free_blttemp(uae_u32, uae_u32); extern void execute_test000(struct registers*); extern void execute_test010(struct registers *); extern void execute_test020(struct registers *); @@ -454,7 +470,7 @@ static void start_test(void) error_vectors[i - 2] = p[i]; } } - if (interrupttest) { + if (interrupttest || initial_interrupt_mask || initial_interrupt) { for (int i = 24; i < 24 + 8; i++) { p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2); if (exception_vectors) { @@ -618,7 +634,7 @@ static int load_file_offset(FILE *f, int *foffsetp) unsigned char buf[4] = { 0 }; fseek(f, *foffsetp, SEEK_SET); fread(buf, 1, sizeof(buf), f); - if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff && buf[3] == 0xff) { + if (buf[0] == 0xaf && buf[1] == 'M' && buf[2] == 'R' && buf[3] == 'G') { fread(buf, 1, sizeof(buf), f); size = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0); if (size == 0) { @@ -653,7 +669,7 @@ static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *siz } FILE *f = fopen(fname, "rb"); if (f) { - int gsize; + int gsize = 0; if (foffsetp) { gsize = load_file_offset(f, foffsetp); if (gsize == 0) { @@ -663,7 +679,7 @@ static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *siz *sizep = gsize; } } - if (*sizep <= 0) { + if (*sizep <= 0 || foffsetp == NULL) { fseek(f, 0, SEEK_END); gsize = ftell(f); fseek(f, 0, SEEK_SET); @@ -719,11 +735,17 @@ static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *siz printf("Decompressing '%s' (%d -> %d)\n", fname, gsize, size); callinflate(p, gzdata, inflatestack); *sizep = size; + if (!prealloc_gzip) { + free(gzbuf); + } return p; } else if (candirect) { printf("Decompressing '%s' (%d -> %d)\n", fname, gsize, size); callinflate(p, gzdata, inflatestack); *sizep = size; + if (!prealloc_gzip) { + free(gzbuf); + } return p; } else { unpack = calloc(1, size); @@ -870,6 +892,11 @@ end: return p; } +static void endinfo_debug(uae_u8 *p) +{ + printf("PTR %08x, %08x, count %d\n", debug_item_data, p, debug_item_count); +} + static void pl(uae_u8 *p, uae_u32 v) { p[0] = v >> 24; @@ -899,6 +926,7 @@ static uae_u8 *restore_fpvalue(uae_u8 *p, struct fpureg *fp) if ((v & CT_SIZE_MASK) != CT_SIZE_FPU) { end_test(); printf("Expected CT_SIZE_FPU, got %02x\n", v); + endinfo_debug(p); endinfo(); exit(0); } @@ -967,7 +995,8 @@ static uae_u8 *restore_value(uae_u8 *p, uae_u32 *vp, int *sizep) break; case CT_SIZE_FPU: end_test(); - printf("Unexpected CT_SIZE_FPU\n"); + printf("Unexpected CT_SIZE_FPU (%02x)\n", v); + endinfo_debug(p); endinfo(); exit(0); break; @@ -1020,6 +1049,7 @@ static uae_u8 *restore_rel(uae_u8 *p, uae_u32 *vp, int nocheck) } else if ((val & addressing_mask) < test_memory_addr || (val & addressing_mask) >= test_memory_addr + test_memory_size) { end_test(); printf("restore_rel CT_ABSOLUTE_LONG outside of test memory! %08x\n", v); + endinfo_debug(p); endinfo(); exit(0); } @@ -1039,11 +1069,13 @@ static uae_u8 *restore_rel_ordered(uae_u8 *p, uae_u32 *vp) } -static void validate_mode(uae_u8 mode, uae_u8 v) +static void validate_mode(uae_u8 *p, uae_u8 v) { + uae_u8 mode = p[0]; if ((mode & CT_DATA_MASK) != v) { end_test(); printf("CT_MEMWRITE expected but got %02X\n", mode); + endinfo_debug(p); endinfo(); exit(0); } @@ -1066,7 +1098,7 @@ static uae_u8 *get_memory_addr(uae_u8 *p, uae_u8 **addrp) } else { addr = low_memory + offset; } - validate_mode(p[0], CT_MEMWRITE); + validate_mode(p, CT_MEMWRITE); *addrp = addr; return p; } @@ -1083,7 +1115,7 @@ static uae_u8 *get_memory_addr(uae_u8 *p, uae_u8 **addrp) #else uae_u8 *addr = (uae_u8*)val; #endif - validate_mode(p[0], CT_MEMWRITE); + validate_mode(p, CT_MEMWRITE); *addrp = addr; return p; } else if (val >= test_memory_addr && val < test_memory_addr + test_memory_size) { @@ -1092,12 +1124,13 @@ static uae_u8 *get_memory_addr(uae_u8 *p, uae_u8 **addrp) #else uae_u8 *addr = (uae_u8*)val; #endif - validate_mode(p[0], CT_MEMWRITE); + validate_mode(p, CT_MEMWRITE); *addrp = addr; return p; } else { end_test(); printf("get_memory_addr CT_ABSOLUTE_LONG outside of test memory! %08x\n", val); + endinfo_debug(p); endinfo(); exit(0); } @@ -1109,7 +1142,7 @@ static uae_u8 *get_memory_addr(uae_u8 *p, uae_u8 **addrp) val |= *p++; uae_s16 offset = (uae_s16)val; uae_u8 *addr = opcode_memory + offset; - validate_mode(p[0], CT_MEMWRITE); + validate_mode(p, CT_MEMWRITE); *addrp = addr; return p; } @@ -1118,6 +1151,7 @@ static uae_u8 *get_memory_addr(uae_u8 *p, uae_u8 **addrp) default: end_test(); printf("get_memory_addr unknown size %02x\n", v); + endinfo_debug(p); endinfo(); exit(0); } @@ -1171,21 +1205,27 @@ static void restoreahist(void) static uae_u8 *restore_bytes(uae_u8 *mem, uae_u8 *p) { uae_u8 *addr = mem; - uae_u16 v = *p++; - addr += v >> 5; - v &= 31; - if (v == 31) { - v = *p++; - if (v == 0) { - v = 256; + uae_u16 len, offset; + if (*p == 0xff) { + p++; + offset = *p++; + len = *p++; + if (len == 0) { + len = 256; + } + } else { + uae_u8 v = *p++; + offset = v >> 5; + len = v & 31; + if (len == 0) { + len = 32; } - } else if (v == 0) { - v = 32; } + addr += offset; #ifndef _MSC_VER - xmemcpy(addr, p, v); + xmemcpy(addr, p, len); #endif - p += v; + p += len; return p; } @@ -1230,6 +1270,7 @@ static uae_u8 *restore_memory(uae_u8 *p, int storedata) default: end_test(); printf("Unknown restore_memory type!?\n"); + endinfo_debug(p); endinfo(); exit(0); break; @@ -1251,6 +1292,7 @@ static uae_u8 *restore_memory(uae_u8 *p, int storedata) default: end_test(); printf("Unknown restore_memory type!?\n"); + endinfo_debug(p); endinfo(); exit(0); break; @@ -1271,6 +1313,7 @@ static uae_u8 *restore_edata(uae_u8 *p) default: end_test(); printf("Unexpected CT_EDATA 0x%02x\n", *p); + endinfo_debug(p); endinfo(); exit(0); } @@ -1283,6 +1326,7 @@ static uae_u8 *restore_data(uae_u8 *p, struct registers *r) if (v & CT_END) { end_test(); printf("Unexpected end bit!? 0x%02x offset %d\n", v, p - test_data); + endinfo_debug(p); endinfo(); exit(0); } @@ -1510,18 +1554,20 @@ struct srbit { char *name; int bit; + int size; }; static const struct srbit srbits[] = { - { "T1", 15 }, - { "T0", 14 }, - { "S", 13 }, - { "M", 12 }, - { "X", 4 }, - { "N", 3 }, - { "Z", 2 }, - { "V", 1 }, - { "C", 0 }, - { NULL, 0 } + { "T1", 15, 1 }, + { "T0", 14, 1 }, + { "S", 13, 1 }, + { "M", 12, 1 }, + { "IM", 8, 3 }, + { "X", 4, 1 }, + { "N", 3, 1 }, + { "Z", 2, 1 }, + { "V", 1, 1 }, + { "C", 0, 1 }, + { NULL, 0, 0 } }; // r = registers to output @@ -1593,9 +1639,13 @@ static void out_regs(struct registers *r, struct registers *r1, struct registers for (int i = 0; srbits[i].name; i++) { if (i > 0) *outbp++ = ' '; - uae_u16 mask = 1 << srbits[i].bit; + uae_u16 mask = 0; + for (int j = 0; j < srbits[i].size; j++) { + mask <<= 1; + mask |= 1 << srbits[i].bit; + } sprintf(outbp, "%s%c%d", srbits[i].name, - (s2 & mask) != (s3 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) != 0); + (s2 & mask) != (s3 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) >> srbits[i].bit); outbp += strlen(outbp); } *outbp++ = '\n'; @@ -1782,19 +1832,19 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu } sprintf(outbp, "Expected trace exception (PC=%08x) but got none.\n", pc); outbp += strlen(outbp); - *experr = 1; + *experr |= 2; } else if (!(last_exception_extra & 0x80)) { // Trace stacked with group 2 exception if (!(sr & 0x2000) || (sr | 0x2000 | 0xc000) != (regs->sr | 0x2000 | 0xc000)) { sprintf(outbp, "Trace (%d stacked) SR mismatch: %04x != %04x\n", excnum, sr, regs->sr); outbp += strlen(outbp); - *experr = 1; + *experr |= 2; } uae_u32 retv = exceptiontableinuse + (excnum - 2) * 2; if (ret != retv) { sprintf(outbp, "Trace (%d stacked) PC mismatch: %08x != %08x\n", excnum, ret, retv); outbp += strlen(outbp); - *experr = 1; + *experr |= 2; } *extratrace = 1; } else { @@ -1806,13 +1856,14 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu if ((vsr & test_ccrignoremask) != (sr & test_ccrignoremask)) { sprintf(outbp, "Trace (non-stacked) SR mismatch: %04x != %04x (PC=%08x)\n", sr, vsr, v); outbp += strlen(outbp); - *experr = 1; + *experr |= 2; } if (v != ret) { sprintf(outbp, "Trace (non-stacked) PC mismatch: %08x != %08x (SR=%04x)\n", ret, v, vsr); outbp += strlen(outbp); - *experr = 1; + *experr |= 2; } + *extratrace = -1; } } else if (!last_exception_extra && excnum != 9) { if (regs->tracecnt > 0) { @@ -1824,7 +1875,7 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu sprintf(outbp, "Exception %d also pending.\n", excnum); outbp += strlen(outbp); } - *experr = 1; + *experr |= 2; } } else if (last_exception_extra) { end_test(); @@ -2081,7 +2132,7 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnu strcpy(outbp, "Got : "); outbp += strlen(outbp); hexdump(sp, exclen, 1); - *experr = 1; + *experr |= 1; } exception_stored = exclen; return p; @@ -2200,6 +2251,18 @@ static int get_cycles_amiga(void) static uae_u16 test_intena, test_intreq; +static const uae_u16 itable[] = +{ + 0, + 1 << 2, + 1 << 3, + 1 << 4, + 1 << 7, + 1 << 11, + 1 << 13, + 0 +}; + static void set_interrupt(void) { if (interrupttest == 1) { @@ -2221,6 +2284,13 @@ static void set_interrupt(void) *intena = 0x8000 | 0x4000 | IPL_TRIGGER_INTMASK; *intreq = IPL_TRIGGER_INTMASK; } + if (initial_interrupt) { + uae_u16 mask = itable[initial_interrupt]; + volatile uae_u16 *intena = (uae_u16*)0xdff09a; + volatile uae_u16 *intreq = (uae_u16*)0xdff09c; + *intena = 0x8000 | 0x4000 | mask; + *intreq = 0x8000 | mask; + } } static void clear_interrupt(void) @@ -2305,7 +2375,7 @@ static int check_cycles(int exc, short extratrace, short extrag2w1, struct regis } gotcycles += cycles_adjust; - if (extratrace) { + if (extratrace > 0) { expectedcycles += getexceptioncycles(9); } // address error during group 2 exception stacking (=odd exception vector) @@ -2328,10 +2398,9 @@ static int check_cycles(int exc, short extratrace, short extrag2w1, struct regis } if (0 || abs(gotcycles - expectedcycles) > cycles_range) { - addinfo(); - sprintf(outbp, "Got %d cycles (%d + %d) but expected %d (%d + %d)\n", + sprintf(outbp, "Got %d cycles (%d + %d) but expected %d (%d + %d) %08x\n", gotcycles, gotcycles - exceptioncycles, exceptioncycles, - expectedcycles, expectedcycles - exceptioncycles, exceptioncycles); + expectedcycles, expectedcycles - exceptioncycles, exceptioncycles, test_regs.cycles); outbp += strlen(outbp); return 0; } @@ -2521,7 +2590,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st if (cpu_lvl > 0 && exc >= 2 && cpuexc010 != cpuexc) { if (dooutput) { sprintf(outbp, "Exception: vector number does not match vector offset! (%d <> %d) %d\n", exc, cpuexc010, cpuexc); - experr = 1; + experr |= 1; outbp += strlen(outbp); errflag |= 1 << 16; } @@ -2589,7 +2658,11 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st hexdump(excp, excsize, 1); } } - experr = 1; + if ((experr & 2) && !(experr & 1) && extratrace) { + sprintf(outbp, "Valid trace exception found\n"); + outbp += strlen(outbp); + } + experr |= 2; } errflag |= 1 << 16; } @@ -2967,7 +3040,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st } #endif if (exc > 1) { - if (!experr) { + if (!(experr & 1)) { sprintf(outbp, "OK: exception %d ", exc); outbp += strlen(outbp); if (exception_stored) { @@ -3002,7 +3075,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st static void out_endinfo(void) { - sprintf(outbp, "%u (%u/%u) ", testcnt, testcntsub, testcntsubmax); + sprintf(outbp, "%u (%u/%u/%u) ", testcnt, testcntsub, testcntsubmax, interrupt_delay_cnt); outbp += strlen(outbp); sprintf(outbp, "S=%d", supercnt); outbp += strlen(outbp); @@ -3104,7 +3177,7 @@ static void process_test(uae_u8 *p) short doopcodeswap = 1; - if (interrupttest >= 1) { + if (interrupttest >= 2) { doopcodeswap = 0; } @@ -3113,12 +3186,16 @@ static void process_test(uae_u8 *p) cur_regs.endpc = endpc; cur_regs.pc = startpc; + debug_item_data = p; + debug_item_count = 0; for (;;) { uae_u8 v = *p; if (v == CT_END_INIT || v == CT_END_FINISH) break; p = restore_data(p, &cur_regs); + debug_item_count++; } + debug_item_count = -1; if (*p == CT_END_FINISH) break; p++; @@ -3213,6 +3290,7 @@ static void process_test(uae_u8 *p) test_regs.pc = startpc; test_regs.cyclest = 0xffffffff; test_regs.fpeaset = 0; + test_regs.blttemp = blt_data; #ifdef M68K if (stackcopysize > 0) @@ -3223,7 +3301,7 @@ static void process_test(uae_u8 *p) } else { test_regs.sr = (ccr & 1) ? 31 : 0; } - test_regs.sr |= sr_mask | (interrupt_mask << 8); + test_regs.sr |= sr_mask | (initial_interrupt_mask << 8); if (fpumode) { test_regs.fpcr = 0; test_regs.fpsr = 0; @@ -3347,7 +3425,7 @@ static void process_test(uae_u8 *p) #ifdef AMIGA - if (interrupttest) { + if (interrupttest || initial_interrupt_mask || initial_interrupt) { set_interrupt(); } #endif @@ -3365,7 +3443,7 @@ static void process_test(uae_u8 *p) } #ifdef AMIGA - if (interrupttest) { + if (interrupttest || initial_interrupt_mask || initial_interrupt) { clear_interrupt(); } #endif @@ -3494,8 +3572,12 @@ end: static void freestuff(void) { - if (test_memory && test_memory_addr) + if (test_memory && test_memory_addr) { free_absolute(test_memory_addr, test_memory_size); + } + if (blt_data) { + free_blttemp(blt_data, BLT_TEMP_SIZE); + } #ifdef WAITEXIT getchar(); #endif @@ -3546,15 +3628,20 @@ static int test_mnemo(const char *opcode) test_memory_end = test_memory_addr + test_memory_size; opcode_memory_addr = read_u32(headerfile, &headoffset); opcode_memory = (uae_u8*)opcode_memory_addr; - uae_u32 lvl_mask = read_u32(headerfile, &headoffset); - lvl = (lvl_mask >> 16) & 15; - interrupt_mask = (lvl_mask >> 20) & 7; - addressing_mask = (lvl_mask & 0x80000000) ? 0xffffffff : 0x00ffffff; - interrupttest = (lvl_mask >> 26) & 3; - sr_undefined_mask = lvl_mask & 0xffff; - safe_memory_mode = (lvl_mask >> 23) & 7; - loop_mode_jit = (lvl_mask >> 28) & 1; - loop_mode_68010 = (lvl_mask >> 29) & 1; + v = read_u32(headerfile, &headoffset); + lvl = (v >> 16) & 15; + interrupt_mask = (v >> 20) & 7; + addressing_mask = (v & 0x80000000) ? 0xffffffff : 0x00ffffff; + interrupttest = (v >> 26) & 3; + sr_undefined_mask = v & 0xffff; + safe_memory_mode = (v >> 23) & 7; + loop_mode_jit = (v >> 28) & 1; + loop_mode_68010 = (v >> 29) & 1; + v = read_u32(headerfile, &headoffset); + initial_interrupt_mask = v & 7; + initial_interrupt = (v >> 3) & 7; + v = read_u32(headerfile, &headoffset); + v = read_u32(headerfile, &headoffset); fpu_model = read_u32(headerfile, &headoffset); test_low_memory_start = read_u32(headerfile, &headoffset); test_low_memory_end = read_u32(headerfile, &headoffset); @@ -3666,6 +3753,12 @@ static int test_mnemo(const char *opcode) } } + blt_data = allocate_blttemp(BLT_TEMP_SIZE); + if (!blt_data) { + printf("blt_temp failed to allocated.\n"); + exit(0); + } + int otestcnt = -1; for (;;) { if (otestcnt != testcnt) { @@ -3739,6 +3832,11 @@ static int test_mnemo(const char *opcode) } } + if (blt_data) { + free_blttemp(blt_data, BLT_TEMP_SIZE); + blt_data = 0; + } + if (errorcnt == 0) { outbp = outbuffer; out_endinfo(); diff --git a/cputest_support.cpp b/cputest_support.cpp index a1d998e9..71c5a6d9 100644 --- a/cputest_support.cpp +++ b/cputest_support.cpp @@ -10,13 +10,14 @@ #include "cpummu030.h" cpuop_func *loop_mode_table[65536]; +int cpuipldelay2, cpuipldelay4; void my_trim(TCHAR *s) { int len; while (s[0] != '\0' && _tcscspn(s, _T("\t \r\n")) == 0) - memmove(s, s + 1, (_tcslen(s + 1) + 1) * sizeof(TCHAR)); - len = _tcslen(s); + memmove(s, s + 1, (uaetcslen(s + 1) + 1) * sizeof(TCHAR)); + len = uaetcslen(s); while (len > 0 && _tcscspn(s + len - 1, _T("\t \r\n")) == 0) s[--len] = '\0'; } @@ -40,8 +41,8 @@ TCHAR *buf_out(TCHAR *buffer, int *bufsize, const TCHAR *format, ...) return 0; count = _vsntprintf(buffer, (*bufsize) - 1, format, parms); va_end(parms); - *bufsize -= _tcslen(buffer); - return buffer + _tcslen(buffer); + *bufsize -= uaetcslen(buffer); + return buffer + uaetcslen(buffer); } void fpux_restore(int *v) @@ -52,10 +53,11 @@ void fp_init_native(void) wprintf(_T("fp_init_native called!")); exit(0); } -void fp_init_native_80(void) +bool fp_init_native_80(void) { wprintf(_T("fp_init_native_80 called!")); exit(0); + return false; } void init_fpucw_x87(void) {