ssw |= test_exception_3_size == 0 ? 0x0200 : 0x0000; // BY
ssw |= test_exception_3_w ? 0x0000 : 0x0100; // RW
regs.mmu_fault_addr = test_exception_addr;
- Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, 3, 0x08);
+ Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, test_exception, 0x08);
SPCFLAG_DOTRACE = 0;
} else {
Exception_build_stack_frame_common(regs.instruction_pc, regs.pc, 0, test_exception);
uae_u16 ssw = (sv ? 4 : 0) | test_exception_3_fc;
ssw |= 0x20;
regs.mmu_fault_addr = test_exception_addr;
- Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, 3, 0x0b);
+ Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, test_exception, 0x0b);
} else {
Exception_build_stack_frame_common(regs.instruction_pc, regs.pc, 0, test_exception);
}
if (test_exception == 3) {
if (currprefs.cpu_model >= 68040)
test_exception_addr &= ~1;
- Exception_build_stack_frame(test_exception_addr, regs.pc, 0, 3, 0x02);
+ Exception_build_stack_frame(test_exception_addr, regs.pc, 0, test_exception, 0x02);
} else {
Exception_build_stack_frame_common(regs.instruction_pc, regs.pc, 0, test_exception);
}
static uae_u8 alternate_exception1[256];
static uae_u8 alternate_exception2[256];
static uae_u8 alternate_exception3[256];
+static uae_u8 masked_exception[256];
+static int mask_exception;
+static int exception_stored;
+
+static int compare_exception(uae_u8 *s1, uae_u8 *s2, int len, int domask, uae_u8 *mask)
+{
+ if (!domask) {
+ return memcmp(s1, s2, len);
+ } else {
+ for (int i = 0; i < len; i++) {
+ if (mask[i])
+ continue;
+ if (s1[i] != s2[i])
+ return 1;
+ }
+ return 0;
+ }
+}
static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int *gotexcnum, int *experr)
{
int excrwp = 0;
int alts = 0;
+ mask_exception = 0;
if (!excdatalen) {
return p;
}
exclen = 16;
break;
case 8: // 68010 bus/address error
- exc[8] = *p++;
- exc[9] = *p++;
- excrwp = ((exc[8] & 1) == 0) ? 1 : 0;
- if (exc[9] & 2)
- excrwp = 2;
- v = opcode_memory_addr;
- p = restore_rel_ordered(p, &v);
- pl(exc + 10, v);
- // data out
- exc[16] = *p++;
- exc[17] = *p++;
- // data in
- exc[20] = *p++;
- exc[21] = *p++;
- // inst
- exc[24] = *p++;
- exc[25] = *p++;
- exc[14] = exc[15] = 0;
- sp[14] = sp[15] = 0;
- exc[18] = exc[19] = 0;
- sp[18] = sp[19] = 0;
- exc[22] = exc[23] = 0;
- sp[22] = sp[23] = 0;
- // ignore undocumented data
- exclen = 26;
- // read input buffer may contain either actual data read from memory or previous read data
- // this depends on hardware, cpu does dummy read cycle and some hardware returns memory data, some ignore it.
- memcpy(alternate_exception1, exc, exclen);
- memcpy(alternate_exception2, exc, exclen);
- alternate_exception1[20] = p[0];
- alternate_exception1[21] = p[1];
- memcpy(alternate_exception3, alternate_exception1, exclen);
- // same with instruction input buffer if branch instruction generates address error
- alternate_exception2[24] = p[0];
- alternate_exception2[25] = p[1];
- alternate_exception3[24] = p[0];
- alternate_exception3[25] = p[1];
- p += 2;
- alts = 3;
+ {
+ exc[8] = *p++;
+ exc[9] = *p++;
+ excrwp = ((exc[8] & 1) == 0) ? 1 : 0;
+ if (exc[9] & 2)
+ excrwp = 2;
+ uae_u32 fault_addr = opcode_memory_addr;
+ p = restore_rel_ordered(p, &fault_addr);
+ pl(exc + 10, fault_addr);
+ // data out
+ exc[16] = *p++;
+ exc[17] = *p++;
+ // data in
+ exc[20] = *p++;
+ exc[21] = *p++;
+ // inst
+ exc[24] = *p++;
+ exc[25] = *p++;
+ exc[14] = exc[15] = 0;
+ sp[14] = sp[15] = 0;
+ exc[18] = exc[19] = 0;
+ sp[18] = sp[19] = 0;
+ exc[22] = exc[23] = 0;
+ sp[22] = sp[23] = 0;
+ if (basicexcept) {
+ exclen = 14;
+ } else {
+ // ignore undocumented data
+ exclen = 26;
+ // read input buffer may contain either actual data read from memory or previous read data
+ // this depends on hardware, cpu does dummy read cycle and some hardware returns memory data, some ignore it.
+ memcpy(alternate_exception1, exc, exclen);
+ memcpy(alternate_exception2, exc, exclen);
+ alternate_exception1[20] = p[0];
+ alternate_exception1[21] = p[1];
+ memcpy(alternate_exception3, alternate_exception1, exclen);
+ // same with instruction input buffer if branch instruction generates address error
+ alternate_exception2[24] = p[0];
+ alternate_exception2[25] = p[1];
+ alternate_exception3[24] = p[0];
+ alternate_exception3[25] = p[1];
+ if (excnum == 2 || !is_valid_test_addr_readwrite(fault_addr - 4) || !is_valid_test_addr_readwrite(fault_addr + 4)) {
+ // bus error read: cpu may still the data, depends on hardware.
+ // ignore input buffer contents
+ mask_exception = 1;
+ memset(masked_exception, 0, sizeof(masked_exception));
+ masked_exception[20] = 1;
+ masked_exception[21] = 1;
+ }
+ alts = 3;
+ }
+ p += 2;
+ }
break;
case 0x0a:
case 0x0b:
if (exclen == 0 || *gotexcnum != excnum)
return p;
int err = 0;
- if (memcmp(exc, sp, exclen)) {
+ if (compare_exception(exc, sp, exclen, mask_exception, masked_exception)) {
err = 1;
if (err && alts > 0) {
- if (alts >= 1 && !memcmp(alternate_exception1, sp, exclen))
+ if (alts >= 1 && !compare_exception(alternate_exception1, sp, exclen, mask_exception, masked_exception))
err = 0;
- if (alts >= 2 && !memcmp(alternate_exception2, sp, exclen))
+ if (alts >= 2 && !compare_exception(alternate_exception2, sp, exclen, mask_exception, masked_exception))
err = 0;
- if (alts >= 3 && !memcmp(alternate_exception3, sp, exclen))
+ if (alts >= 3 && !compare_exception(alternate_exception3, sp, exclen, mask_exception, masked_exception))
err = 0;
}
}
hexdump(sp, exclen);
*experr = 1;
}
+ exception_stored = exclen;
return p;
}
+
// regs: registers before execution of test code
// test_reg: registers used during execution of test code, also modified by test code.
// last_registers: registers after modifications from data files. Test ok if test_reg == last_registers.
int errflag = 0;
int errflag_orig = 0;
uae_u8 *outbp_old = outbp;
+ exception_stored = 0;
for (;;) {
uae_u8 v = *p;
out_regs(&test_regs, 0);
if (exc > 1) {
if (!experr) {
- sprintf(outbp, "OK: Generated exception %d\n", exc);
+ sprintf(outbp, "OK: exception %d ", exc);
outbp += strlen(outbp);
+ if (exception_stored) {
+ hexdump(last_exception, exception_stored);
+ }
}
if ((exc == 3 || exc == 2) && cpu_lvl == 0) {
sprintf(outbp, "RW=%d IN=%d FC=%d\n",
printf("\t\tregs.sr = sr;\n");
printf("\t\tMakeFromSR();\n");
}
+ } else if (cpu_level == 1) {
+ // -(an).l where first word causes bus error: An is not modified
+ // -(an).l where second word causes bus error: An is modified
+ if (g_instr->size != sz_long || (g_instr->size == sz_long && offset)) {
+ printf("\t\tm68k_areg(regs, %s) = %sa;\n", bus_error_reg, name);
+ }
} else {
printf("\t\tm68k_areg(regs, %s) = %sa;\n", bus_error_reg, name);
}
}
}
- if (cpu_level == 1 && g_instr->mnemo == i_MVSR2 && !write) {
- printf("\t\topcode |= 0x20000;\n"); // upper byte of SSW is zero -flag.
- }
+ if (cpu_level == 1) {
+ // 68010 bus/address error HB bit
+ if (extra) {
+ printf("\t\topcode |= 0x%x;\n", extra);
+ }
+ // upper byte of SSW is zero -flag.
+ if (g_instr->mnemo == i_MVSR2 && !write) {
+ printf("\t\topcode |= 0x20000;\n");
+ }
+ // read bus error, -(an).w/.l: pre-decrement is done first.
+ if (!write && g_instr->smode == Apdi && g_instr->size == sz_long) {
+
+ //printf("\t\tm68k_areg(regs, %s) = %sa;\n", bus_error_reg, name);
+ }
- // 68010 bus/address error HB bit
- if (extra && cpu_level == 1) {
- printf("\t\topcode |= 0x%x;\n", extra);
}
// write causing bus error and trace: set I/N
printf("\tif (%sa & 1) {\n", name);
if (cpu_level == 1) {
+ int bus_error_reg_add_old = bus_error_reg_add;
// 68010 does dummy access
if (getv != 2) {
if ((flags & GF_REVERSE) && size == sz_long) {
} else {
do_bus_error_fixes(name, 0, getv == 2);
}
- // x,-(an): an is modified
- if (mode == Apdi && g_instr->size == sz_word && g_instr->mnemo != i_CLR) {
+ // x,-(an): an is modified (MOVE to CCR counts as word sized)
+ if (mode == Apdi && (g_instr->size == sz_word || g_instr->size == i_MV2SR) && g_instr->mnemo != i_CLR) {
printf("\t\tm68k_areg(regs, %s) = %sa;\n", reg, name);
}
+ bus_error_reg_add = bus_error_reg_add_old;
}
if (g_instr->mnemo == i_ADDX || g_instr->mnemo == i_SUBX) {