]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
CPU model specific edge case updates.
authorToni Wilen <twilen@winuae.net>
Sun, 31 May 2020 16:44:35 +0000 (19:44 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 31 May 2020 16:44:35 +0000 (19:44 +0300)
gencpu.cpp
include/newcpu.h
newcpu.cpp
newcpu_common.cpp

index 62befa24800ab98e229e534445e204eda15926f4..1e7a0890768a92382aba2309db18fb9fbaf1b5b5 100644 (file)
@@ -5360,10 +5360,18 @@ static void gen_opcode (unsigned int opcode)
                }
                addcycles000(8);
                out("regs.sr %c= src;\n", curi->mnemo == i_ORSR ? '|' : curi->mnemo == i_ANDSR ? '&' : '^');
-               makefromsr_t0();
+               if (cpu_level < 5 && curi->size == sz_word) {
+                       makefromsr_t0();
+               } else {
+                       makefromsr();
+               }
                sync_m68k_pc();
-               fill_prefetch_full_ntx(3);
-               next_level_000();
+               if (cpu_level < 2 || curi->size == sz_word) {
+                       fill_prefetch_full_ntx(3);
+               } else {
+                       fill_prefetch_next();
+               }
+               next_cpu_level = cpu_level - 1;
                break;
        case i_SUB:
        {
@@ -6445,22 +6453,28 @@ static void gen_opcode (unsigned int opcode)
                break;
        case i_MV2SR: // MOVE TO SR
                genamode(curi, curi->smode, "srcreg", sz_word, "src", 1, 0, 0);
-               if (cpu_level == 0)
+               if (cpu_level == 0) {
                        out("int t1 = regs.t1;\n");
+               }
                if (curi->size == sz_byte) {
                        // MOVE TO CCR
                        addcycles000(4);
                        out("MakeSR();\nregs.sr &= 0xFF00;\nregs.sr |= src & 0xFF;\n");
+                       makefromsr();
                } else {
                        // MOVE TO SR
                        check_trace();
                        addcycles000(4);
                        out("regs.sr = src;\n");
+                       makefromsr_t0();
+               }
+               if (cpu_level >= 2 && curi->size == sz_byte) {
+                       fill_prefetch_next();
+               } else {
+                       // does full prefetch because S-bit change may change memory mapping under the CPU
+                       sync_m68k_pc();
+                       fill_prefetch_full_ntx(3);
                }
-               makefromsr_t0();
-               // does full prefetch because S-bit change may change memory mapping under the CPU
-               sync_m68k_pc();
-               fill_prefetch_full_ntx(3);
                next_level_000();
                break;
        case i_SWAP:
@@ -6710,7 +6724,8 @@ static void gen_opcode (unsigned int opcode)
                        }
                } else {
                        out("uaecptr oldpc = %s;\n", getpc);
-                       out("uae_u16 newsr; uae_u32 newpc;\n");
+                       out("uae_u16 oldsr = regs.sr, newsr;\n");
+                       out("uae_u32 newpc;\n");
                        out("for (;;) {\n");
                        out("uaecptr a = m68k_areg(regs, 7);\n");
                        out("uae_u16 sr = %s(a);\n", srcw);
@@ -6775,28 +6790,47 @@ static void gen_opcode (unsigned int opcode)
                                    out("else if (frame == 0xb) {\nm68k_areg(regs, 7) += offset + 84; break; }\n");
                                }
                        }
+                       out("else {\n");
                        if (cpu_level == 1) {
-                               out("else {\n");
                                out("SET_NFLG(((uae_s16)format) < 0); \n");
                                out("SET_ZFLG(format == 0);\n");
                                out("SET_VFLG(0);\n");
                                out("Exception_cpu(14);\n");
                                write_return_cycles(0);
-                               out("}\n");
+                       } else if (cpu_level == 0) {
+                               out("Exception_cpu(14);\n");
+                               write_return_cycles(0);
+                       } else if (cpu_level == 3) {
+                               // 68030: trace bits are cleared
+                               out("regs.t1 = regs.t0 = 0;\n");
+                               out("Exception_cpu(14);\n");
+                               write_return_cycles(0);
                        } else {
-                               out("else {\n");
                                out("Exception_cpu(14);\n");
                                write_return_cycles(0);
-                               out("}\n");
                        }
-                   out("regs.sr = newsr;\n");
+                       out("}\n");
+                       out("regs.sr = newsr;\n");
+                       out("oldsr = newsr;\n");
                        makefromsr_t0();
                        out("}\n");
+                       out("MakeFromSR_intmask(regs.sr, newsr);\n");
                    out("regs.sr = newsr;\n");
                        addcycles_ce020 (4);
                        makefromsr_t0();
                    out("if (newpc & 1) {\n");
-                   out("exception3_read_prefetch(opcode, newpc);\n");
+                       if (cpu_level == 5) {
+                               out("regs.sr = oldsr & 0xff00;\n");
+                               makefromsr();
+                               out("SET_ZFLG(newsr == 0);\n");
+                               out("SET_NFLG(newsr & 0x8000);\n");
+                               out("exception3_read_prefetch(opcode, newpc);\n");
+                       } else if (cpu_level == 4) {
+                               makefromsr();
+                               out("exception3_read_prefetch_68040bug(opcode, newpc, oldsr);\n");
+                       } else {
+                               out("exception3_read_prefetch(opcode, newpc);\n");
+                       }
                        write_return_cycles(0);
                        out("}\n");
                    setpc ("newpc");
@@ -7043,7 +7077,19 @@ static void gen_opcode (unsigned int opcode)
                if (cpu_level >= 4) {
                        out("if (pc & 1) {\n");
                        out("m68k_areg(regs, 7) -= 6;\n");
-                       out("exception3_read_prefetch(opcode, pc);\n");
+                       if (cpu_level == 5) {
+                               out("regs.sr &= 0xFF00; sr &= 0xFF;\n");
+                               out("regs.sr |= sr;\n");
+                               makefromsr();
+                               out("exception3_read_prefetch(opcode, pc);\n");
+                       } else {
+                               // stacked SR is original SR. Real SR has CCR part zeroed.
+                               out("uae_u16 oldsr = regs.sr;\n");
+                               out("regs.sr &= 0xFF00; sr &= 0xFF;\n");
+                               out("regs.sr |= sr;\n");
+                               makefromsr();
+                               out("exception3_read_prefetch_68040bug(opcode, pc, oldsr);\n");
+                       }
                        write_return_cycles(0);
                        out("}\n");
                }
@@ -7067,7 +7113,7 @@ static void gen_opcode (unsigned int opcode)
                }
                branch_inst = 1;
                tail_ce020_done = true;
-               next_level_040_to_030();
+               next_cpu_level = cpu_level - 1;
                break;
        case i_JSR:
                {
@@ -7281,7 +7327,7 @@ static void gen_opcode (unsigned int opcode)
                        out("if (s & 1) {\n");
                        if (cpu_level < 4)
                                out("m68k_areg(regs, 7) -= 4;\n");
-                       out("exception3_read_prefetch(opcode, s);\n");
+                       out("exception3_read_prefetch(opcode, oldpc + s);\n");
                        write_return_cycles(0);
                        out("}\n");
                }
@@ -8342,7 +8388,6 @@ bccl_not68020:
                write_return_cycles(0);
                out("}\n");
                addcycles000(4);
-               trace_t0_68040_only();
                break;
        case i_MOVE2C:
                if (cpu_level == 1) {
@@ -8722,7 +8767,6 @@ bccl_not68020:
                                next_cpu_level = 2 - 1;
                        genastore_tas("src", curi->smode, "srcreg", curi->size, "src");
                        fill_prefetch_next();
-                       trace_t0_68040_only();
                }
                next_level_000();
                break;
index ef9428bb64f7bfcd06559d3de7192d59e1f5d7fb..061fdda1107429dfaa41e2e3872b48d591a57cc2 100644 (file)
@@ -669,6 +669,7 @@ extern void flush_cpu_caches_040(uae_u16 opcode);
 extern void REGPARAM3 MakeSR (void) REGPARAM;
 extern void REGPARAM3 MakeFromSR(void) REGPARAM;
 extern void REGPARAM3 MakeFromSR_T0(void) REGPARAM;
+extern void REGPARAM3 MakeFromSR_intmask(uae_u16 oldsr, uae_u16 newsr) REGPARAM;
 extern void REGPARAM3 Exception (int) REGPARAM;
 extern void REGPARAM3 Exception_cpu(int) REGPARAM;
 extern void REGPARAM3 ExceptionL (int, uaecptr) REGPARAM;
@@ -737,6 +738,7 @@ extern void exception3_read_access(uae_u32 opcode, uaecptr addr, int size, int f
 extern void exception3_read_access2(uae_u32 opcode, uaecptr addr, int size, int fc);
 extern void exception3_write_access(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc);
 extern void exception3_read_prefetch(uae_u32 opcode, uaecptr addr);
+extern void exception3_read_prefetch_68040bug(uae_u32 opcode, uaecptr addr, uae_u16 secondarysr);
 extern void exception3_read_prefetch_only(uae_u32 opcode, uaecptr addr);
 extern void exception3_notinstruction(uae_u32 opcode, uaecptr addr);
 extern void hardware_exception2(uaecptr addr, uae_u32 v, bool read, bool ins, int size);
index e312b4465956382cd6394476a4ba87fbf2404e98..9214dbfda1c3b8665626d2e1a944230fdac1ef1c 100644 (file)
@@ -80,6 +80,8 @@ static int last_di_for_exception_3;
 static bool last_notinstruction_for_exception_3;
 /* set when writing exception stack frame */
 static int exception_in_exception;
+/* secondary SR for handling 68040 bug */
+static uae_u16 last_sr_for_exception3;
 
 static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc);
 
@@ -2375,19 +2377,41 @@ void REGPARAM2 MakeFromSR(void)
        MakeFromSR_x(0);
 }
 
+void REGPARAM2 MakeFromSR_intmask(uae_u16 oldsr, uae_u16 newsr)
+{
+#if 0
+       int oldlvl = (oldsr >> 8) & 7;
+       int newlvl = (newsr >> 8) & 7;
+       int ilvl = intlev();
+
+       // interrupt mask lowered and allows new interrupt to start?
+       if (newlvl < oldlvl && ilvl > 0 && ilvl > newlvl && ilvl <= oldlvl) {
+               if (currprefs.cpu_model >= 68020) {
+                       unset_special(SPCFLAG_INT);
+               }
+       }
+#endif
+}
+
+static bool internalexception(int nr)
+{
+       return nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47);
+}
+
 static void exception_check_trace (int nr)
 {
        unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
        if (regs.t1) {
                /* trace stays pending if exception is div by zero, chk,
-               * trapv or trap #x
+               * trapv or trap #x. Except if 68040 or 68060.
                */
-               if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47))
-                       set_special (SPCFLAG_DOTRACE);
+               if (currprefs.cpu_model < 68040 && internalexception(nr)) {
+                       set_special(SPCFLAG_DOTRACE);
+               }
                // 68010 and RTE format error: trace is not cleared
-               if (nr == 14 && currprefs.cpu_model == 68010)
+               if (nr == 14 && currprefs.cpu_model == 68010) {
                        set_special(SPCFLAG_DOTRACE);
-
+               }
        }
        regs.t1 = regs.t0 = 0;
 }
@@ -2553,8 +2577,6 @@ Interrupt:
 
 */
 
-static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc);
-
 static int iack_cycle(int nr)
 {
        int vector;
@@ -2725,6 +2747,7 @@ kludge_me_do:
                        regs.irc = regs.read_buffer;
                        exception3_read_access(regs.opcode, newpc, sz_word, 2);
                } else {
+                       exception_check_trace(nr);
                        exception3_notinstruction(regs.ir, newpc);
                }
                return;
@@ -3169,6 +3192,12 @@ static void Exception_normal (int nr)
        if (currprefs.cpu_model == 68060 && interrupt) {
                regs.m = 0;
        }
+       if (currprefs.cpu_model == 68040 && nr == 3 && (last_op_for_exception_3 & 0x10000)) {
+               // Weird 68040 bug with RTR and RTE. New SR when exception starts. Stacked SR is different!
+               // Just replace it in stack, it is safe enough because we are in address error exception
+               // any other exception would halt the CPU.
+               x_put_word(m68k_areg(regs, 7), last_sr_for_exception3);
+       }
 kludge_me_do:
        if ((regs.vbr & 1) && currprefs.cpu_model <= 68010) {
                cpu_halt(CPU_HALT_DOUBLE_FAULT);
@@ -3203,6 +3232,7 @@ kludge_me_do:
                        regs.irc = regs.read_buffer;
                        exception3_read_access(regs.ir, newpc, sz_word, 2);
                } else {
+                       exception_check_trace(nr);
                        exception3_notinstruction(regs.ir, newpc);
                }
                return;
@@ -3277,6 +3307,9 @@ void REGPARAM2 Exception_cpu(int nr)
        // Check T0 trace
        // RTE format error ignores T0 trace
        if (nr != 14) {
+               if (currprefs.cpu_model >= 68040 && internalexception(nr)) {
+                       t0 = false;
+               }
                if (t0) {
                        activate_trace();
                }
@@ -4002,7 +4035,7 @@ void mmu_op (uae_u32 opcode, uae_u32 extra)
 static void do_trace (void)
 {
        // need to store PC because of branch instructions
-       regs.trace_pc = regs.pc;
+       regs.trace_pc = m68k_getpc();
        if (regs.t0 && !regs.t1 && currprefs.cpu_model >= 68020) {
                // this is obsolete
                return;
@@ -7175,7 +7208,7 @@ uae_u8 *restore_mmu (uae_u8 *src)
 
 #endif /* SAVESTATE */
 
-static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc)
+static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc, uae_u16 secondarysr)
 {
        if (currprefs.cpu_model >= 68040)
                addr &= ~1;
@@ -7185,7 +7218,7 @@ static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool in
                else
                        last_addr_for_exception_3 = pc;
        } else if (pc == 0xffffffff) {
-               last_addr_for_exception_3 = m68k_getpc ();
+               last_addr_for_exception_3 = m68k_getpc();
        } else {
                last_addr_for_exception_3 = pc;
        }
@@ -7195,6 +7228,7 @@ static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool in
        last_fc_for_exception_3 = fc >= 0 ? fc : (instructionaccess ? 2 : 1);
        last_notinstruction_for_exception_3 = notinstruction;
        last_size_for_exception_3 = size;
+       last_sr_for_exception3 = secondarysr;
        Exception (3);
 #if EXCEPTION3_DEBUGGER
        activate_debugger();
@@ -7204,11 +7238,11 @@ static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool in
 void exception3_notinstruction(uae_u32 opcode, uaecptr addr)
 {
        last_di_for_exception_3 = 1;
-       exception3f (opcode, addr, true, false, true, 0xffffffff, 1, -1);
+       exception3f (opcode, addr, true, false, true, 0xffffffff, 1, -1, 0);
 }
 static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc)
 {
-       exception3f(opcode, addr, false, 0, false, 0xffffffff, size, fc);
+       exception3f(opcode, addr, false, 0, false, 0xffffffff, size, fc, 0);
 }
 
 // 68010 special prefetch handling
@@ -7222,7 +7256,7 @@ void exception3_read_prefetch_only(uae_u32 opcode, uae_u32 addr)
                x_do_cycles(4 * cpucycleunit);
        }
        last_di_for_exception_3 = 0;
-       exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1);
+       exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1, 0);
 }
 
 // Some hardware accepts address error aborted reads or writes as normal reads/writes.
@@ -7233,8 +7267,15 @@ void exception3_read_prefetch(uae_u32 opcode, uaecptr addr)
        if (currprefs.cpu_model == 68000) {
                m68k_incpci(2);
        }
-       exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1);
+       exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1, 0);
+}
+void exception3_read_prefetch_68040bug(uae_u32 opcode, uaecptr addr, uae_u16 secondarysr)
+{
+       x_do_cycles(4 * cpucycleunit);
+       last_di_for_exception_3 = 0;
+       exception3f(opcode | 0x10000, addr, false, true, false, m68k_getpc(), sz_word, -1, secondarysr);
 }
+
 void exception3_read_access(uae_u32 opcode, uaecptr addr, int size, int fc)
 {
        x_do_cycles(4 * cpucycleunit);
@@ -7268,7 +7309,7 @@ void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc)
                opcode = regs.ir;
        }
        last_di_for_exception_3 = 1;
-       exception3f(opcode, addr, false, ia, ni, 0xffffffff, size & 15, fc);
+       exception3f(opcode, addr, false, ia, ni, 0xffffffff, size & 15, fc, 0);
 }
 void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc)
 {
@@ -7287,7 +7328,7 @@ void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int f
        }
        last_di_for_exception_3 = 1;
        regs.write_buffer = val;
-       exception3f(opcode, addr, true, ia, ni, 0xffffffff, size & 15, fc);
+       exception3f(opcode, addr, true, ia, ni, 0xffffffff, size & 15, fc, 0);
 }
 
 void exception2_setup(uae_u32 opcode, uaecptr addr, bool read, int size, uae_u32 fc)
index b0d389f436fdc11d7e51710f0d36a58b65bc0851..9a7918622d8eefaa5f02474581f6b2d4fc343bd2 100644 (file)
@@ -1726,6 +1726,7 @@ void areg_68000_long_replace_low(int reg, uae_u16 v)
 }
 
 // Change F-line to privilege violation if missing co-pro
+// 68040 and 68060 always return F-line
 bool privileged_copro_instruction(uae_u16 opcode)
 {
        if (currprefs.cpu_model >= 68020 && !regs.s) {
@@ -1735,14 +1736,16 @@ bool privileged_copro_instruction(uae_u16 opcode)
                // cpSAVE and cpRESTORE: privilege violation if user mode.
                if ((opcode & 0xf1c0) == 0xf100) {
                        // cpSAVE
+                       // check if valid EA
                        if (mode == 2 || (mode >= 4 && mode <= 6) || (mode == 7 && (reg == 0 || reg == 1))) {
-                               if ((currprefs.cpu_model >= 68040 && id > 0) || currprefs.cpu_model < 68040)
+                               if (currprefs.cpu_model < 68040 || (currprefs.cpu_model >= 68040 && id == 1))
                                        return true;
                        }
                } else if ((opcode & 0xf1c0) == 0xf140) {
                        // cpRESTORE
+                       // check if valid EA
                        if (mode == 2 || mode == 3 || (mode >= 5 && mode <= 6) || (mode == 7 && reg <= 3)) {
-                               if ((currprefs.cpu_model >= 68040 && id > 0) || currprefs.cpu_model < 68040)
+                               if (currprefs.cpu_model < 68040 || (currprefs.cpu_model >= 68040 && id == 1))
                                        return true;
                        }
                }