// large enough for RTD
#define STACK_SIZE (0x8000 + 8)
#define RESERVED_SUPERSTACK 1024
+// space for extra exception, not part of test region
+#define EXTRA_RESERVED_SPACE 1024
static uae_u32 test_low_memory_start;
static uae_u32 test_low_memory_end;
static bool out_of_test_space;
static uaecptr out_of_test_space_addr;
-static int test_exception;
static int forced_immediate_mode;
+static int test_exception;
+static int exception_stack_frame_size;
static uaecptr test_exception_addr;
static int test_exception_3_inst;
+static int test_exception_3_w;
static uae_u8 imm8_cnt;
static uae_u16 imm16_cnt;
static uae_u32 imm32_cnt;
goto oob;
return 1;
}
+ if (addr >= test_memory_end && addr + size < test_memory_end + EXTRA_RESERVED_SPACE) {
+ if (testing_active < 0)
+ return 1;
+ }
if (addr >= test_memory_start && addr + size < test_memory_end - RESERVED_SUPERSTACK) {
// make sure we don't modify our test instruction
if (testing_active && w) {
return low_memory + addr;
} else if (addr >= HIGH_MEMORY_START && addr < HIGH_MEMORY_START + 0x8000) {
return high_memory + (addr - HIGH_MEMORY_START);
- } else if (addr >= test_memory_start && addr + size < test_memory_end - RESERVED_SUPERSTACK) {
+ } else if (addr >= test_memory_start && addr + size < test_memory_end + EXTRA_RESERVED_SPACE) {
return test_memory + (addr - test_memory_start);
}
oob:
test_exception = 1;
}
+static void doexcstack(void)
+{
+ // generate exception but don't store it with test results
+
+ int noac = noaccesshistory;
+ int ta = testing_active;
+ noaccesshistory = 1;
+ testing_active = -1;
+
+ int sv = regs.s;
+ uaecptr tmp = m68k_areg(regs, 7);
+ m68k_areg(regs, 7) = test_memory_end + EXTRA_RESERVED_SPACE;
+ if (cpu_lvl == 0) {
+ if (test_exception == 3) {
+ uae_u16 opcode = (opcode_memory[0] << 8) | (opcode_memory[1]);
+ uae_u16 mode = (sv ? 4 : 0) | (test_exception_3_inst ? 2 : 1);
+ mode |= test_exception_3_w ? 0 : 16;
+ Exception_build_68000_address_error_stack_frame(mode, opcode, test_exception_addr, regs.pc);
+ }
+ } else if (cpu_lvl > 0) {
+ Exception_build_stack_frame_common(regs.instruction_pc, regs.pc, 0, test_exception);
+ }
+ exception_stack_frame_size = test_memory_end + EXTRA_RESERVED_SPACE - m68k_areg(regs, 7);
+
+ m68k_areg(regs, 7) = tmp;
+ testing_active = ta;
+ noaccesshistory = noac;
+}
+
void exception3_read(uae_u32 opcode, uae_u32 addr)
{
test_exception = 3;
test_exception_3_inst = 0;
test_exception_addr = addr;
+ doexcstack();
}
void exception3_write(uae_u32 opcode, uae_u32 addr)
{
test_exception = 3;
test_exception_3_inst = 0;
test_exception_addr = addr;
+ doexcstack();
}
void REGPARAM2 Exception(int n)
{
test_exception = n;
test_exception_3_inst = 0;
test_exception_addr = m68k_getpci();
+ doexcstack();
}
void REGPARAM2 Exception_cpu(int n)
{
if (t0) {
activate_trace();
}
+ doexcstack();
}
void exception3i(uae_u32 opcode, uaecptr addr)
{
test_exception = 3;
test_exception_3_inst = 1;
+ test_exception_3_w = 0;
test_exception_addr = addr;
+ doexcstack();
}
void exception3b(uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
{
test_exception = 3;
test_exception_3_inst = i;
+ test_exception_3_w = w;
test_exception_addr = addr;
+ doexcstack();
}
int cctrue(int cc)
return dst;
}
-
static void pl(uae_u8 *p, uae_u32 v)
{
p[0] = v >> 24;
p[2] = v >> 8;
p[3] = v >> 0;
}
+static uae_u32 gl(uae_u8 *p)
+{
+ return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+}
static bool load_file(const TCHAR *path, const TCHAR *file, uae_u8 *p, int size, int offset)
{
if (SPCFLAG_TRACE)
do_trace();
+ regs.instruction_pc = regs.pc;
(*cpufunctbl[opc])(opc);
if (!test_exception) {
}
+static uae_u8 last_exception[256];
+static int last_exception_len;
+
static uae_u8 *save_exception(uae_u8 *p)
{
- uae_u8 size = 0;
- *p++ = size;
+ uae_u8 *op = p;
+ int framelen;
+ p++;
+ uae_u8 *sf = test_memory + test_memory_size + EXTRA_RESERVED_SPACE - exception_stack_frame_size;
+ // parse exception and store fields that are unique
+ // SR and PC was already saved with non-exception data
+ if (cpu_lvl == 0) {
+ if (test_exception == 3) {
+ *p++ = sf[1];
+ // access address
+ p = store_rel(p, 0, opcode_memory_start, gl(sf + 2), 1);
+ }
+ } else if (cpu_lvl > 0) {
+ uae_u16 frame = (sf[6] << 8) | sf[7];
+ // frame + vector offset
+ *p++ = sf[6];
+ *p++ = sf[7];
+ switch (frame >> 12)
+ {
+ case 2:
+ // instruction address
+ p = store_rel(p, 0, opcode_memory_start, gl(sf + 8), 1);
+ break;
+ case 3:
+ // effective address
+ p = store_rel(p, 0, opcode_memory_start, gl(sf + 8), 1);
+ break;
+ case 8:
+ // fault/effective address
+ p = store_rel(p, 0, opcode_memory_start, gl(sf + 8), 1);
+ // FSLW or PC of faulted instruction
+ p = store_rel(p, 0, opcode_memory_start, gl(sf + 12), 1);
+ break;
+ default:
+ wprintf(_T("Unknown frame %04x!\n"), frame);
+ abort();
+ }
+ }
+ if (last_exception_len == exception_stack_frame_size && !memcmp(sf, last_exception, exception_stack_frame_size)) {
+ // stack frame was identical to previous
+ p = op;
+ *p++ = 0xff;
+ } else {
+ int datalen = (p - op) - 1;
+ last_exception_len = exception_stack_frame_size;
+ *op = (uae_u8)datalen;
+ memcpy(last_exception, sf, exception_stack_frame_size);
+ }
return p;
}
memcpy(test_memory, test_memory_temp, test_memory_size);
full_format_cnt = 0;
+ last_exception_len = -1;
int sr_override = 0;
if (ini_getval(ini, INISECTION, _T("test_high_memory_end"), &v))
test_high_memory_end = v;
- test_memory = (uae_u8 *)calloc(1, test_memory_size);
+ test_memory = (uae_u8 *)calloc(1, test_memory_size + EXTRA_RESERVED_SPACE);
test_memory_temp = (uae_u8 *)calloc(1, test_memory_size);
if (!test_memory || !test_memory_temp) {
wprintf(_T("Couldn't allocate test memory\n"));
return p;
}
-static uae_u8 *restore_rel(uae_u8 *p, uae_u32 *vp)
+static uae_u8 *restore_rel(uae_u8 *p, uae_u32 *vp, int nocheck)
{
uae_u32 v = *vp;
switch ((*p++) & CT_SIZE_MASK)
val |= (*p++) << 8;
val |= *p++;
v = val;
- if ((val & addressing_mask) < 0x8000) {
- ; // low memory
- } else if ((val & ~addressing_mask) == ~addressing_mask && val >= 0xfff80000) {
- ; // high memory
- } 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();
- exit(0);
+ if (!nocheck) {
+ if ((val & addressing_mask) < 0x8000) {
+ ; // low memory
+ } else if ((val & ~addressing_mask) == ~addressing_mask && val >= 0xfff80000) {
+ ; // high memory
+ } 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();
+ exit(0);
+ }
}
break;
}
return p;
}
+static uae_u8 *restore_rel_ordered(uae_u8 *p, uae_u32 *vp)
+{
+ if (*p == CT_EMPTY)
+ return p + 1;
+ return restore_rel(p, vp, 1);
+}
+
+
static void validate_mode(uae_u8 mode, uae_u8 v)
{
if ((mode & CT_DATA_MASK) != v) {
*outbp++ = '\n';
}
-static void validate_exception(struct registers *regs, uae_u8 *p)
+static uae_u8 last_exception[256];
+static int last_exception_len;
+
+static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum)
{
int exclen = 0;
- uae_u8 excmatch[32];
+ uae_u8 *exc;
+ uae_u8 *op = p;
uae_u8 *sp = (uae_u8*)regs->excframe;
uae_u32 v;
uae_u8 excdatalen = *p++;
if (!excdatalen)
- return;
-
- if (cpu_lvl == 0) {
- if (regs->exc == 3) {
- // status (with undocumented opcode part)
- excmatch[0] = opcode_memory[0];
- excmatch[1] = (opcode_memory[1] & 0xf0) | (*p++);
- // access address
- v = opcode_memory_addr;
- p = restore_rel(p, &v);
- pl(excmatch + 2, v);
- p += 4;
- // opcode
- excmatch[6] = opcode_memory[0];
- excmatch[7] = opcode_memory[1];
+ return p;
+ exc = last_exception;
+ if (excdatalen != 0xff) {
+ if (cpu_lvl == 0) {
+ if (excnum == 3) {
+ // status (with undocumented opcode part)
+ exc[0] = opcode_memory[0];
+ exc[1] = (opcode_memory[1] & 0xf0) | (*p++);
+ // access address
+ v = opcode_memory_addr;
+ p = restore_rel_ordered(p, &v);
+ pl(exc + 2, v);
+ // opcode
+ exc[6] = opcode_memory[0];
+ exc[7] = opcode_memory[1];
+ // sr
+ exc[8] = regs->sr >> 8;
+ exc[9] = regs->sr;
+ // pc
+ pl(exc + 10, regs->pc);
+ exclen = 14;
+ }
+ } else if (cpu_lvl > 0) {
// sr
- excmatch[8] = regs->sr >> 8;
- excmatch[9] = regs->sr;
- // pc
- pl(excmatch + 10, regs->pc);
- exclen = 14;
+ exc[0] = regs->sr >> 8;
+ exc[1] = regs->sr;
+ pl(exc + 2, regs->pc);
+ // frame type
+ uae_u16 frame = ((*p++) << 8) | (*p++);
+ exc[6] = frame >> 8;
+ exc[7] = frame >> 0;
+
+ switch (frame >> 12)
+ {
+ case 0:
+ exclen = 8;
+ break;
+ case 2:
+ v = opcode_memory_addr;
+ p = restore_rel_ordered(p, &v);
+ pl(exc + 8, v);
+ exclen = 12;
+ break;
+ case 3:
+ v = opcode_memory_addr;
+ p = restore_rel_ordered(p, &v);
+ pl(exc + 8, v);
+ exclen = 12;
+ break;
+ case 8:
+ v = opcode_memory_addr;
+ p = restore_rel_ordered(p, &v);
+ pl(exc + 8, v);
+ v = opcode_memory_addr;
+ p = restore_rel_ordered(p, &v);
+ pl(exc + 12, v);
+ exclen = 16;
+ break;
+ default:
+ end_test();
+ printf("Unknown frame %04x\n", frame);
+ exit(0);
+ break;
+ }
+ }
+ last_exception_len = exclen;
+ if (p != op + excdatalen + 1) {
+ end_test();
+ printf("Exception length mismatch %d != %d\n", excdatalen, p - op - 1);
+ exit(0);
}
} else {
- // sr
- excmatch[0] = regs->sr >> 8;
- excmatch[1] = regs->sr;
- pl(excmatch + 2, regs->pc);
+ exclen = last_exception_len;
}
if (exclen == 0)
- return;
- if (memcmp(excmatch, sp, exclen)) {
- strcpy(outbp, "Exception stack frame mismatch");
+ return p;
+ if (memcmp(exc, sp, exclen)) {
+ strcpy(outbp, "Exception stack frame mismatch:\n");
outbp += strlen(outbp);
hexdump(sp, exclen);
- hexdump(excmatch, exclen);
+ hexdump(exc, exclen);
+ errors = 1;
}
+ return p;
}
static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr)
break;
}
if (exc) {
- uae_u8 excdatalen = *p++;
- if (exc == cpuexc && excdatalen) {
- validate_exception(&test_regs, p);
- }
- p += excdatalen;
+ p = validate_exception(&test_regs, p, exc);
}
if (exc != cpuexc) {
addinfo();
last_registers.sr = val;
} else if (mode == CT_PC) {
uae_u32 val = last_registers.pc;
- p = restore_rel(p, &val);
+ p = restore_rel(p, &val, 0);
pc_changed = 0;
last_registers.pc = val;
} else if (mode == CT_FPCR) {
last_registers.fpsr = val;
} else if (mode == CT_FPIAR) {
uae_u32 val = last_registers.fpiar;
- p = restore_rel(p, &val);
+ p = restore_rel(p, &val, 0);
if (val != test_regs.fpiar && !ignore_errors) {
addinfo();
if (dooutput) {
extern void unprotect_maprom (void);
extern bool is_hardreset(void);
extern bool is_keyboardreset(void);
+extern void Exception_build_stack_frame_common(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr);
+extern void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format);
+extern void Exception_build_68000_address_error_stack_frame(uae_u16 mode, uae_u16 opcode, uaecptr fault_addr, uaecptr pc);
+extern uae_u32 exception_pc(int nr);
extern void mmu_op (uae_u32, uae_u32);
extern bool mmu_op30 (uaecptr, uae_u32, uae_u16, uaecptr);
}
#endif
-static uae_u32 exception_pc (int nr)
-{
- // bus error, address error, illegal instruction, privilege violation, a-line, f-line
- if (nr == 2 || nr == 3 || nr == 4 || nr == 8 || nr == 10 || nr == 11)
- return regs.instruction_pc;
- return m68k_getpc ();
-}
-
-static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format)
-{
- int i;
-
-#if 0
- if (nr < 24 || nr > 31) { // do not print debugging for interrupts
- write_log(_T("Building exception stack frame (format %X)\n"), format);
- }
-#endif
-
- switch (format) {
- case 0x0: // four word stack frame
- case 0x1: // throwaway four word stack frame
- break;
- case 0x2: // six word stack frame
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), oldpc);
- break;
- case 0x3: // floating point post-instruction stack frame (68040)
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.fp_ea);
- break;
- case 0x7: // access error stack frame (68040)
-
- for (i = 3; i >= 0; i--) {
- // WB1D/PD0,PD1,PD2,PD3
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), mmu040_move16[i]);
- }
-
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), 0); // WB1A
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), 0); // WB2D
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.wb2_address); // WB2A
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.wb3_data); // WB3D
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // WB3A
-
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // FA
-
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), 0);
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), regs.wb2_status);
- regs.wb2_status = 0;
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), regs.wb3_status);
- regs.wb3_status = 0;
-
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), ssw);
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.mmu_effective_addr);
- break;
- case 0x9: // coprocessor mid-instruction stack frame (68020, 68030)
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.fp_ea);
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.fp_opword);
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), oldpc);
- break;
- case 0x8: // bus and address error stack frame (68010)
- write_log(_T("Exception stack frame format %X not implemented\n"), format);
- return;
- case 0x4: // floating point unimplemented stack frame (68LC040, 68EC040)
- // or 68060 bus access fault stack frame
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), ssw);
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), oldpc);
- break;
- case 0xB: // long bus cycle fault stack frame (68020, 68030)
- // Store state information to internal register space
-#if MMU030_DEBUG
- if (mmu030_idx >= MAX_MMU030_ACCESS) {
- write_log(_T("mmu030_idx out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS);
- }
-#endif
- if (!(ssw & MMU030_SSW_RW)) {
- mmu030_ad[mmu030_idx].val = regs.wb3_data;
- }
- for (i = 0; i < mmu030_idx + 1; i++) {
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), mmu030_ad[i].val);
- }
- while (i < MAX_MMU030_ACCESS) {
- uae_u32 v = 0;
- m68k_areg (regs, 7) -= 4;
- // mmu030_idx is always small enough if instruction is FMOVEM.
- if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
-#if MMU030_DEBUG
- if (mmu030_idx >= MAX_MMU030_ACCESS - 2) {
- write_log(_T("mmu030_idx (FMOVEM) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS - 2);
- }
-#endif
- if (i == MAX_MMU030_ACCESS - 2)
- v = mmu030_fmovem_store[0];
- else if (i == MAX_MMU030_ACCESS - 1)
- v = mmu030_fmovem_store[1];
- }
- x_put_long (m68k_areg (regs, 7), v);
- i++;
- }
- // version & internal information (We store index here)
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), mmu030_idx);
- // 3* internal registers
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), mmu030_state[2]);
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg(regs, 7), regs.wb2_address); // = mmu030_state[1]
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), mmu030_state[0]);
- // data input buffer = fault address
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
- // 2xinternal
- {
- uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
- ps |= ((regs.pipeline_r8[0] & 7) << 8);
- ps |= ((regs.pipeline_r8[1] & 7) << 11);
- ps |= ((regs.pipeline_pos & 15) << 16);
- ps |= ((regs.pipeline_stop & 15) << 20);
- if (mmu030_opcode == -1)
- ps |= 1 << 31;
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), ps);
- }
- // stage b address
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), mm030_stageb_address);
- // 2xinternal
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), mmu030_disp_store[1]);
- /* fall through */
- case 0xA:
- // short bus cycle fault stack frame (68020, 68030)
- // used when instruction's last write causes bus fault
- m68k_areg (regs, 7) -= 4;
- if (format == 0xb) {
- x_put_long(m68k_areg(regs, 7), mmu030_disp_store[0]);
- } else {
- uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
- ps |= ((regs.pipeline_r8[0] & 7) << 8);
- ps |= ((regs.pipeline_r8[1] & 7) << 11);
- ps |= ((regs.pipeline_pos & 15) << 16);
- ps |= ((regs.pipeline_stop & 15) << 20);
- x_put_long(m68k_areg(regs, 7), ps);
- }
- m68k_areg (regs, 7) -= 4;
- // Data output buffer = value that was going to be written
- x_put_long (m68k_areg (regs, 7), regs.wb3_data);
- m68k_areg (regs, 7) -= 4;
- if (format == 0xb) {
- x_put_long(m68k_areg(regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
- } else {
- x_put_long(m68k_areg(regs, 7), regs.irc | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
- }
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), regs.prefetch020[2]); // Instr. pipe stage B
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), regs.prefetch020[1]); // Instr. pipe stage C
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), ssw);
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), regs.wb2_address); // = mmu030_state[1]);
- break;
- default:
- write_log(_T("Unknown exception stack frame format: %X\n"), format);
- return;
- }
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), (format << 12) | (nr * 4));
- m68k_areg (regs, 7) -= 4;
- x_put_long (m68k_areg (regs, 7), currpc);
- m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), regs.sr);
-}
-
-static void Exception_build_stack_frame_common (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr)
-{
- if (nr == 5 || nr == 6 || nr == 7 || nr == 9) {
- if (currprefs.cpu_model <= 68010)
- Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
- else
- Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x2);
- } else if (nr == 60 || nr == 61) {
- Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0);
- } else if (nr >= 48 && nr <= 55) {
- if (regs.fpu_exp_pre) {
- if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
- Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2);
- } else {
- Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
- }
- } else { /* post-instruction */
- if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
- Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2);
- } else {
- Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3);
- }
- }
- } else if (nr == 11 && regs.fp_unimp_ins) {
- regs.fp_unimp_ins = false;
- if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ||
- (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
- Exception_build_stack_frame(regs.fp_ea, currpc, regs.instruction_pc, nr, 0x4);
- } else {
- Exception_build_stack_frame(regs.fp_ea, currpc, regs.mmu_ssw, nr, 0x2);
- }
- } else {
- Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
- }
-}
-
// 68030 MMU
static void Exception_mmu030 (int nr, uaecptr oldpc)
{
uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
mode |= last_writeaccess_for_exception_3 ? 0 : 16;
mode |= last_notinstruction_for_exception_3 ? 8 : 0;
- // undocumented bits seem to contain opcode
- mode |= last_op_for_exception_3 & ~31;
- m68k_areg (regs, 7) -= 14;
exception_in_exception = -1;
- x_put_word (m68k_areg (regs, 7) + 0, mode);
- x_put_long (m68k_areg (regs, 7) + 2, last_fault_for_exception_3);
- x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3);
- x_put_word (m68k_areg (regs, 7) + 8, regs.sr);
- x_put_long (m68k_areg (regs, 7) + 10, last_addr_for_exception_3);
+ Exception_build_68000_address_error_stack_frame(mode, last_op_for_exception_3, last_fault_for_exception_3, last_addr_for_exception_3);
write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, last_fault_for_exception_3, currpc, get_long_debug (regs.vbr + 4 * vector_nr));
goto kludge_me_do;
}
}
#endif
+
+uae_u32 exception_pc(int nr)
+{
+ // bus error, address error, illegal instruction, privilege violation, a-line, f-line
+ if (nr == 2 || nr == 3 || nr == 4 || nr == 8 || nr == 10 || nr == 11)
+ return regs.instruction_pc;
+ return m68k_getpc();
+}
+
+void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format)
+{
+ int i;
+
+#if 0
+ if (nr < 24 || nr > 31) { // do not print debugging for interrupts
+ write_log(_T("Building exception stack frame (format %X)\n"), format);
+ }
+#endif
+
+ switch (format) {
+ case 0x0: // four word stack frame
+ case 0x1: // throwaway four word stack frame
+ break;
+ case 0x2: // six word stack frame
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), oldpc);
+ break;
+ case 0x3: // floating point post-instruction stack frame (68040)
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.fp_ea);
+ break;
+#ifndef CPU_TESTER
+ case 0x7: // access error stack frame (68040)
+
+ for (i = 3; i >= 0; i--) {
+ // WB1D/PD0,PD1,PD2,PD3
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), mmu040_move16[i]);
+ }
+
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), 0); // WB1A
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), 0); // WB2D
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.wb2_address); // WB2A
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.wb3_data); // WB3D
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.mmu_fault_addr); // WB3A
+
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.mmu_fault_addr); // FA
+
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), 0);
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), regs.wb2_status);
+ regs.wb2_status = 0;
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), regs.wb3_status);
+ regs.wb3_status = 0;
+
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), ssw);
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.mmu_effective_addr);
+ break;
+#endif
+ case 0x9: // coprocessor mid-instruction stack frame (68020, 68030)
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.fp_ea);
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.fp_opword);
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), oldpc);
+ break;
+ case 0x8: // bus and address error stack frame (68010)
+ write_log(_T("Exception stack frame format %X not implemented\n"), format);
+ return;
+ case 0x4: // floating point unimplemented stack frame (68LC040, 68EC040)
+ // or 68060 bus access fault stack frame
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), ssw);
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), oldpc);
+ break;
+#ifndef CPU_TESTER
+ case 0xB: // long bus cycle fault stack frame (68020, 68030)
+ // Store state information to internal register space
+#if MMU030_DEBUG
+ if (mmu030_idx >= MAX_MMU030_ACCESS) {
+ write_log(_T("mmu030_idx out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS);
+ }
+#endif
+ if (!(ssw & MMU030_SSW_RW)) {
+ mmu030_ad[mmu030_idx].val = regs.wb3_data;
+ }
+ for (i = 0; i < mmu030_idx + 1; i++) {
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), mmu030_ad[i].val);
+ }
+ while (i < MAX_MMU030_ACCESS) {
+ uae_u32 v = 0;
+ m68k_areg(regs, 7) -= 4;
+ // mmu030_idx is always small enough if instruction is FMOVEM.
+ if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
+#if MMU030_DEBUG
+ if (mmu030_idx >= MAX_MMU030_ACCESS - 2) {
+ write_log(_T("mmu030_idx (FMOVEM) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS - 2);
+ }
+#endif
+ if (i == MAX_MMU030_ACCESS - 2)
+ v = mmu030_fmovem_store[0];
+ else if (i == MAX_MMU030_ACCESS - 1)
+ v = mmu030_fmovem_store[1];
+ }
+ x_put_long(m68k_areg(regs, 7), v);
+ i++;
+ }
+ // version & internal information (We store index here)
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), mmu030_idx);
+ // 3* internal registers
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), mmu030_state[2]);
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), regs.wb2_address); // = mmu030_state[1]
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), mmu030_state[0]);
+ // data input buffer = fault address
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.mmu_fault_addr);
+ // 2xinternal
+ {
+ uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
+ ps |= ((regs.pipeline_r8[0] & 7) << 8);
+ ps |= ((regs.pipeline_r8[1] & 7) << 11);
+ ps |= ((regs.pipeline_pos & 15) << 16);
+ ps |= ((regs.pipeline_stop & 15) << 20);
+ if (mmu030_opcode == -1)
+ ps |= 1 << 31;
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), ps);
+ }
+ // stage b address
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), mm030_stageb_address);
+ // 2xinternal
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), mmu030_disp_store[1]);
+ /* fall through */
+ case 0xA:
+ // short bus cycle fault stack frame (68020, 68030)
+ // used when instruction's last write causes bus fault
+ m68k_areg(regs, 7) -= 4;
+ if (format == 0xb) {
+ x_put_long(m68k_areg(regs, 7), mmu030_disp_store[0]);
+ } else {
+ uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
+ ps |= ((regs.pipeline_r8[0] & 7) << 8);
+ ps |= ((regs.pipeline_r8[1] & 7) << 11);
+ ps |= ((regs.pipeline_pos & 15) << 16);
+ ps |= ((regs.pipeline_stop & 15) << 20);
+ x_put_long(m68k_areg(regs, 7), ps);
+ }
+ m68k_areg(regs, 7) -= 4;
+ // Data output buffer = value that was going to be written
+ x_put_long(m68k_areg(regs, 7), regs.wb3_data);
+ m68k_areg(regs, 7) -= 4;
+ if (format == 0xb) {
+ x_put_long(m68k_areg(regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
+ } else {
+ x_put_long(m68k_areg(regs, 7), regs.irc | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
+ }
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), regs.mmu_fault_addr); // data cycle fault address
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), regs.prefetch020[2]); // Instr. pipe stage B
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), regs.prefetch020[1]); // Instr. pipe stage C
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), ssw);
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), regs.wb2_address); // = mmu030_state[1]);
+ break;
+#endif
+ default:
+ write_log(_T("Unknown exception stack frame format: %X\n"), format);
+ return;
+ }
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), (format << 12) | (nr * 4));
+ m68k_areg(regs, 7) -= 4;
+ x_put_long(m68k_areg(regs, 7), currpc);
+ m68k_areg(regs, 7) -= 2;
+ x_put_word(m68k_areg(regs, 7), regs.sr);
+}
+
+void Exception_build_stack_frame_common(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr)
+{
+ if (nr == 5 || nr == 6 || nr == 7 || nr == 9) {
+ if (currprefs.cpu_model <= 68010)
+ Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
+ else
+ Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x2);
+ } else if (nr == 60 || nr == 61) {
+ Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0);
+ } else if (nr >= 48 && nr <= 55) {
+ if (regs.fpu_exp_pre) {
+ if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
+ Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2);
+ } else {
+ Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
+ }
+ } else { /* post-instruction */
+ if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
+ Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2);
+ } else {
+ Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3);
+ }
+ }
+ } else if (nr == 11 && regs.fp_unimp_ins) {
+ regs.fp_unimp_ins = false;
+ if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ||
+ (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
+ Exception_build_stack_frame(regs.fp_ea, currpc, regs.instruction_pc, nr, 0x4);
+ } else {
+ Exception_build_stack_frame(regs.fp_ea, currpc, regs.mmu_ssw, nr, 0x2);
+ }
+ } else {
+ Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
+ }
+}
+
+void Exception_build_68000_address_error_stack_frame(uae_u16 mode, uae_u16 opcode, uaecptr fault_addr, uaecptr pc)
+{
+ // undocumented bits seem to contain opcode
+ mode |= opcode & ~31;
+ m68k_areg(regs, 7) -= 14;
+ x_put_word(m68k_areg(regs, 7) + 0, mode);
+ x_put_long(m68k_areg(regs, 7) + 2, fault_addr);
+ x_put_word(m68k_areg(regs, 7) + 6, opcode);
+ x_put_word(m68k_areg(regs, 7) + 8, regs.sr);
+ x_put_long(m68k_areg(regs, 7) + 10, pc);
+}