interrupt_cycle_cnt -= cycles;
if (interrupt_cycle_cnt <= 0) {
regs.ipl_pin = 1;
+ interrupt_level = 1;
interrupt_cycle_cnt = 0;
}
}
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)
{
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
)
abort();
}
- if (SPCFLAG_TRACE) {
+ if (SPCFLAG_TRACE && !cpu_stopped) {
do_trace();
}
}
}
- (*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
}
- // 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;
}
}
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) {
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,
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;
}
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++) {
if (regs.sr & 0x2000)
prev_s_cnt++;
- if (subtest_count == 20609)
+ if (subtest_count == 433)
printf("");
// execute test instruction(s)
}
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;
} else {
nextround = true;
rounds = 1;
+ quick = 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.
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;
}
// hpos 0-1: vertical count hasn't been increased yet
- if (hstart <= 1) {
+ if (hstart <= 0) {
vstart++;
}
- if (hend <= 1) {
+ if (hend <= 0) {
vend++;
}
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);
}
experr = 1;
}
- outbp += strlen(outbp);
errflag |= 1 << 16;
}
break;
errflag = 0;
}
- if (exitcnt == 0 && !errflag) {
+ if (exitcnt == 0 && !exitmode && !errflag) {
errflag = 1;
}
if (exitcnt >= 0) {
exitcnt--;
+ if (!exitcnt && exitmode) {
+ goto end;
+ }
}
if ((*p) == CT_END_SKIP) {
printf("%s", outbuffer);
}
}
+ if (exitcnt == 0 && exitmode) {
+ printf("Exit count expired\n");
+ }
}
static void freestuff(void)
fpu_approxcnt = 0;
memset(exceptioncount, 0, sizeof(exceptioncount));
supercnt = 0;
+ exitcnt = exitcnt2;
uae_u8 *test_data_prealloc = NULL;
}
test_data = NULL;
- if (errors || quit || last) {
+ if (errors || quit || last || (!exitcnt && exitmode)) {
break;
}
out_endinfo();
printf("%s", outbuffer);
}
- if (exitcnt == 0) {
+ if (exitcnt == 0 && !exitmode) {
printf("Exit count expired\n");
}
if (!errors && !quit) {
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 <exp> 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");
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;
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")) {
}
}
- 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);
if (!dirs)
return 0;
+ // get directory
for (;;) {
struct dirent *dr = readdir(d);
if (!dr)
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) {
}
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) {
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)) {