From adfb5305c6a73702dfa264917acb1db3bebcd766 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Fri, 9 Aug 2019 12:35:57 +0300 Subject: [PATCH] CPUI tester exception stack frame extra field(s) verification. Moved stack frame creation to common code. --- cputest.cpp | 111 +++++++++++++++++++-- cputest/main.c | 152 +++++++++++++++++++--------- include/newcpu.h | 4 + newcpu.cpp | 239 +------------------------------------------- newcpu_common.cpp | 246 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 461 insertions(+), 291 deletions(-) diff --git a/cputest.cpp b/cputest.cpp index d5fc3a2d..397c6f12 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -68,6 +68,8 @@ static int ad8r[2], pc8r[2]; // 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; @@ -88,10 +90,12 @@ static int max_storage_buffer = 1000000; 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; @@ -148,6 +152,10 @@ static bool valid_address(uaecptr addr, int size, int w) 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) { @@ -177,7 +185,7 @@ static uae_u8 *get_addr(uaecptr addr, int size, int 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: @@ -659,23 +667,55 @@ void cpureset(void) 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) { @@ -688,18 +728,23 @@ 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) @@ -998,7 +1043,6 @@ static uae_u8 *store_mem(uae_u8 *dst, int storealways) return dst; } - static void pl(uae_u8 *p, uae_u32 v) { p[0] = v >> 24; @@ -1006,6 +1050,10 @@ static void pl(uae_u8 *p, uae_u32 v) 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) { @@ -1452,6 +1500,7 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc) if (SPCFLAG_TRACE) do_trace(); + regs.instruction_pc = regs.pc; (*cpufunctbl[opc])(opc); if (!test_exception) { @@ -1560,10 +1609,59 @@ static int isunsupported(struct instr *dp) } +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; } @@ -1679,6 +1777,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, in memcpy(test_memory, test_memory_temp, test_memory_size); full_format_cnt = 0; + last_exception_len = -1; int sr_override = 0; @@ -2405,7 +2504,7 @@ int __cdecl main(int argc, char *argv[]) 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")); diff --git a/cputest/main.c b/cputest/main.c index 81be8d0a..61a1cd1d 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -361,7 +361,7 @@ static uae_u8 *restore_value(uae_u8 *p, uae_u32 *vp, int *sizep) 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) @@ -397,15 +397,17 @@ static uae_u8 *restore_rel(uae_u8 *p, uae_u32 *vp) 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; } @@ -414,6 +416,14 @@ static uae_u8 *restore_rel(uae_u8 *p, uae_u32 *vp) 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) { @@ -753,51 +763,103 @@ static void hexdump(uae_u8 *p, int len) *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) @@ -869,11 +931,7 @@ 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(); @@ -920,7 +978,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) 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) { @@ -953,7 +1011,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) 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) { diff --git a/include/newcpu.h b/include/newcpu.h index b7dcfb74..ab3f61c1 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -685,6 +685,10 @@ extern void protect_roms (bool); 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); diff --git a/newcpu.cpp b/newcpu.cpp index 8b89290c..76a8cfee 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -2583,236 +2583,6 @@ kludge_me_do: } #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) { @@ -3204,15 +2974,8 @@ static void Exception_normal (int nr) 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; } diff --git a/newcpu_common.cpp b/newcpu_common.cpp index c25e307a..70446c9d 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -1153,3 +1153,249 @@ bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) } #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); +} -- 2.47.3