From 2ed41c40ed70d2b9ce738623c719ba2469073ed8 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 17 Apr 2022 18:07:47 +0300 Subject: [PATCH] cputester IPL timing test support updates --- cputest.cpp | 82 +++++++++++++++++++++++++++++----------- cputest/cputestgen.ini | 4 +- cputest/main.c | 86 ++++++++++++++++++++++++------------------ 3 files changed, 111 insertions(+), 61 deletions(-) diff --git a/cputest.cpp b/cputest.cpp index ed113d58..547516bf 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -374,6 +374,7 @@ static void count_interrupt_cycles(int cycles) interrupt_cycle_cnt -= cycles; if (interrupt_cycle_cnt <= 0) { regs.ipl_pin = 1; + interrupt_level = 1; interrupt_cycle_cnt = 0; } } @@ -1474,6 +1475,9 @@ void REGPARAM2 Exception(int n) test_exception_addr = m68k_getpci(); test_exception_opcode = -1; doexcstack(); + if (n >= 24 && n < 24 + 8) { + cpu_stopped = 0; + } } void REGPARAM2 Exception_cpu_oldpc(int n, uaecptr oldpc) { @@ -3898,7 +3902,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool 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 == 0xf208 + if (opc == 0x4e72 && opw1 == 0xa000 //&& opw2 == 0x4afc ) @@ -3974,7 +3978,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool abort(); } - if (SPCFLAG_TRACE) { + if (SPCFLAG_TRACE && !cpu_stopped) { do_trace(); } @@ -3995,7 +3999,17 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool } } - (*cpufunctbl[opc])(opc); + if (cpu_stopped) { + if (!interrupt_cycle_cnt) { + test_exception = -1; + break; + } + do_cycles_test(2); + ipl_fetch(); + do_cycles_test(2); + } else { + (*cpufunctbl[opc])(opc); + } if (fpumode) { // skip result has too large or small exponent @@ -4023,9 +4037,12 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool } - // Test did one or more out of bounds memory accesses - // or CPU stopped or was reset: skip - if (out_of_test_space || cpu_stopped) { + // One or more out of bounds memory accesses: skip + if (out_of_test_space) { + break; + } + // CPU stopped or was reset: skip + if (cpu_stopped && feature_interrupts != 2) { break; } @@ -4060,18 +4077,21 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool } if (feature_interrupts == 2) { - if (regs.ipl > regs.intmask) { + if (!test_exception && regs.ipl > regs.intmask) { + if (cpu_stopped) { + do_cycles_test(4); + } Exception(24 + regs.ipl); break; } } else { - if (regs.ipl_pin > regs.intmask) { + if (!test_exception && regs.ipl_pin > regs.intmask) { Exception(24 + regs.ipl_pin); break; } } - if (regs.pc == endpc || regs.pc == targetpc) { + if ((regs.pc == endpc || regs.pc == targetpc) && !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) { @@ -4130,7 +4150,10 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool if (feature_interrupts == 2) { // IPL test must cause some exception - if (!test_exception) { + if (!test_exception || test_exception == 8) { + test_exception = -1; + } + if (cpu_stopped) { test_exception = -1; } // Interrupt start must be before test instruction, @@ -4801,18 +4824,30 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi startpc = opcode_memory_address; } - // interrupt timing test mode + // interrupt IPL timing test mode if (feature_interrupts == 2) { pc -= 2; - // moveq #x,d0 (4) - put_word_test(pc + 0, 0x7000 | interrupt_delay_cnt); - // move.b d0,0xdcfffc (RTCW) (8 + 4 + 4) - put_word_test(pc + 2, 0x13c0); - put_long_test(pc + 4, IPL_TRIGGER_ADDR); + // 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 + } + // moveq #x,d0 (4 cycles) + put_word_test(pc + 2, 0x7000 | interrupt_delay_cnt); + // move.b d0,0xdc0000 (RTCW) (8 + 4 + 4) + put_word_test(pc + 4, 0x13c0); + put_long_test(pc + 6, IPL_TRIGGER_ADDR); // ror.l d0,d0 (4 + 4 + d0 * 2 cycles) - put_word_test(pc + 8, 0xe0b8); - put_word_test(pc + 10, NOP_OPCODE); // (4 cycles) - pc += 12; + put_word_test(pc + 10, 0xe0b8); + // restore CCR + // move d7,ccr + put_word_test(pc + 12, 0x44c7); // 12 cycles + put_word_test(pc + 14, NOP_OPCODE); // 4 cycles + put_word_test(pc + 16, NOP_OPCODE); // 4 cycles + pc += 18; opcode_memory_address = pc; pc += 2; } @@ -5128,7 +5163,7 @@ 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_jit || feature_loop_mode_68010) { // || feature_interrupts == 2) { + if (feature_loop_mode_jit || feature_loop_mode_68010 || verbose >= 3) { wprintf(_T("\n")); nextpc = opcode_memory_start; for (int i = 0; i < 20; i++) { @@ -5550,7 +5585,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (regs.sr & 0x2000) prev_s_cnt++; - if (subtest_count == 20609) + if (subtest_count == 433) printf(""); // execute test instruction(s) @@ -5936,8 +5971,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } dst = storage_buffer; - if (opcodecnt == 1 && target_address == 0xffffffff && target_opcode_address == 0xffffffff && target_usp_address == 0xffffffff && subtest_count >= feature_test_rounds_opcode) + if (feature_interrupts != 2 && opcodecnt == 1 && target_address == 0xffffffff && + target_opcode_address == 0xffffffff && target_usp_address == 0xffffffff && subtest_count >= feature_test_rounds_opcode) break; + if (lookup->mnemo == i_ILLG || fpuopcode == FPUOPP_ILLEGAL) break; @@ -5977,6 +6014,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } else { nextround = true; rounds = 1; + quick = 0; } } diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 4d193156..9e3755d8 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -148,8 +148,8 @@ feature_min_interrupt_mask=0 ; Uses serial port to generate timing interrupt. Requires serial port TX connected to RX. ; Generates multiple extra tests. ; Used delay instruction: ROL.L D0,D0 (D0 = number of CPU clocks * 2) -; All test rounds that generate interrupt immediately after test instuction has been executed are stored. -; Amiga only +; All test rounds that generate interrupt immediately before or immediately after test instuction +; has been executed are stored. Amiga only. feature_interrupts=0 ; SR extra mask. diff --git a/cputest/main.c b/cputest/main.c index 28f0dd86..bc60e243 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -145,7 +145,8 @@ static short skipregchange; static short skipccrchange; static short askifmissing; static short nextall; -static int exitcnt, irqcnt; +static short exitmode; +static int exitcnt, exitcnt2, irqcnt; static short cycles, cycles_range, cycles_adjust; static short gotcycles; static short interrupttest; @@ -2125,10 +2126,10 @@ static int get_cycles_amiga(void) } // hpos 0-1: vertical count hasn't been increased yet - if (hstart <= 1) { + if (hstart <= 0) { vstart++; } - if (hend <= 1) { + if (hend <= 0) { vend++; } @@ -2502,12 +2503,15 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st if (dooutput) { if (cpuexc == 4 && lregs->pc + opcodeendsizeextra == tregs->pc) { sprintf(outbp, "Exception: expected %d but got no exception.\n", exc); + outbp += strlen(outbp); } else if (cpuexc == 4) { sprintf(outbp, "Exception: expected %d but got %d (or no exception)\n", exc, cpuexc); + outbp += strlen(outbp); } else { int excsize; uae_u8 *excp; sprintf(outbp, "Exception: expected %d but got %d\n", exc, cpuexc); + outbp += strlen(outbp); excp = get_exceptionframe(&test_regs, cpuexc, &excsize); if (excp && excsize) { hexdump(excp, excsize, 1); @@ -2515,7 +2519,6 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st } experr = 1; } - outbp += strlen(outbp); errflag |= 1 << 16; } break; @@ -2871,7 +2874,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st errflag = 0; } - if (exitcnt == 0 && !errflag) { + if (exitcnt == 0 && !exitmode && !errflag) { errflag = 1; } @@ -3222,6 +3225,9 @@ static void process_test(uae_u8 *p) if (exitcnt >= 0) { exitcnt--; + if (!exitcnt && exitmode) { + goto end; + } } if ((*p) == CT_END_SKIP) { @@ -3370,6 +3376,9 @@ end: printf("%s", outbuffer); } } + if (exitcnt == 0 && exitmode) { + printf("Exit count expired\n"); + } } static void freestuff(void) @@ -3533,6 +3542,7 @@ static int test_mnemo(const char *opcode) fpu_approxcnt = 0; memset(exceptioncount, 0, sizeof(exceptioncount)); supercnt = 0; + exitcnt = exitcnt2; uae_u8 *test_data_prealloc = NULL; @@ -3598,7 +3608,7 @@ static int test_mnemo(const char *opcode) } test_data = NULL; - if (errors || quit || last) { + if (errors || quit || last || (!exitcnt && exitmode)) { break; } @@ -3610,7 +3620,7 @@ static int test_mnemo(const char *opcode) out_endinfo(); printf("%s", outbuffer); } - if (exitcnt == 0) { + if (exitcnt == 0 && !exitmode) { printf("Exit count expired\n"); } if (!errors && !quit) { @@ -3707,6 +3717,7 @@ int main(int argc, char *argv[]) printf("-skipreg = do not validate registers.\n"); printf("-askifmissing = ask for new path if dat file is missing.\n"); printf("-exit n = exit after n tests.\n"); + printf("-exitok n = exit after n tests, continue normally.\n"); printf("-fpuadj 16-bit exponent range value. (16383 = 1.0)\n"); printf("-fpsrmask = ignore FPSR bits that are not set.\n"); printf("-cycles [range adjust] = check cycle counts.\n"); @@ -3724,7 +3735,8 @@ int main(int argc, char *argv[]) ccr_mask = 0xff; fpsr_ignore_mask = 0xffffffff; disasm = 1; - exitcnt = -1; + exitcnt2 = -1; + exitmode = 0; cyclecounter_addr = 0xffffffff; cycles_range = 2; fpu_adjust_exp = -1; @@ -3786,7 +3798,14 @@ int main(int argc, char *argv[]) nextall = 1; } else if (!_stricmp(s, "-exit")) { if (next) { - exitcnt = atoi(next); + exitcnt2 = atoi(next); + exitmode = 0; + i++; + } + } else if (!_stricmp(s, "-exitok")) { + if (next) { + exitcnt2 = atoi(next); + exitmode = 1; i++; } } else if (!_stricmp(s, "-irqcnt")) { @@ -3926,7 +3945,7 @@ int main(int argc, char *argv[]) } } - if (!_stricmp(opcode, "all")) { + if (!_stricmp(opcode, "all") || (opcode[0] && opcode[strlen(opcode) - 1] == '*')) { DIR *d = opendir(path); if (!d) { printf("Couldn't list directory '%s'\n", path); @@ -3940,6 +3959,7 @@ int main(int argc, char *argv[]) if (!dirs) return 0; + // get directory for (;;) { struct dirent *dr = readdir(d); if (!dr) @@ -3947,6 +3967,7 @@ int main(int argc, char *argv[]) int d = isdir(path, dr->d_name); if (d && dr->d_name[0] != '.') { strcpy(dirs + diroff, dr->d_name); + printf("%s\n", dr->d_name); dircnt++; diroff += MAX_FILE_LEN; if (dircnt >= MAX_FILES) { @@ -3957,6 +3978,7 @@ int main(int argc, char *argv[]) } closedir(d); + // sort directory for (int i = 0; i < diroff; i += MAX_FILE_LEN) { for (int j = i + MAX_FILE_LEN; j < diroff; j += MAX_FILE_LEN) { if (_stricmp(dirs + i, dirs + j) > 0) { @@ -3985,42 +4007,32 @@ int main(int argc, char *argv[]) if (nextall) { first += MAX_FILE_LEN; } + int err = 0; - for (int i = first; i < diroff; i += MAX_FILE_LEN) { - if (test_mnemo(dirs + i)) { - err = 1; - if (stop_on_error) - break; + if (!_stricmp(opcode, "all")) { + for (int i = first; i < diroff; i += MAX_FILE_LEN) { + if (test_mnemo(dirs + i)) { + err = 1; + if (stop_on_error) + break; + } } - } - - free(dirs); - - if (err && stop_on_error) - break; - - } else if (opcode[0] && opcode[strlen(opcode) - 1] == '*') { - DIR *d = opendir(path); - if (!d) { - printf("Couldn't list directory '%s'\n", path); - return 0; - } - for (;;) { - struct dirent *dr = readdir(d); - if (!dr) - break; - if (!strnicmp(dr->d_name, opcode, strlen(opcode) - 1)) { - int d = isdir(path, dr->d_name); - if (d) { - if (test_mnemo(dr->d_name)) { + } else { + for (int i = first; i < diroff; i += MAX_FILE_LEN) { + char *name = dirs + i; + if (!strnicmp(name, opcode, strlen(opcode) - 1)) { + if (test_mnemo(name)) { if (stop_on_error) break; } } } } - closedir(d); + free(dirs); + + if (err && stop_on_error) + break; } else { if (test_mnemo(opcode)) { -- 2.47.3