]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
CPUI tester exception stack frame extra field(s) verification. Moved stack frame...
authorToni Wilen <twilen@winuae.net>
Fri, 9 Aug 2019 09:35:57 +0000 (12:35 +0300)
committerToni Wilen <twilen@winuae.net>
Fri, 9 Aug 2019 09:35:57 +0000 (12:35 +0300)
cputest.cpp
cputest/main.c
include/newcpu.h
newcpu.cpp
newcpu_common.cpp

index d5fc3a2dbe82f53412050634e066fb9b8ccf0f0e..397c6f12d68c2d91bcec7142015160db616742af 100644 (file)
@@ -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"));
index 81be8d0a4f690510b3ee78512e36404bc8107294..61a1cd1d5a38c03976775e89a9855d8b46ef4fe1 100644 (file)
@@ -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) {
index b7dcfb7421495bd92b5198ac7d5f20694133d6b8..ab3f61c1a9b16fad784b2170dc3582047a01906f 100644 (file)
@@ -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);
index 8b89290c409357396f46f47f05a6221f8184a67e..76a8cfee2bccc3d6a7c025c176120de5c2564d1b 100644 (file)
@@ -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;
                }
index c25e307a6f17e7e8738fbe99ac159caf48d32a6d..70446c9d601e30e943101b677cdc37ec65f7f1cb 100644 (file)
@@ -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);
+}