]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
68000 IPL fix
authorToni Wilen <twilen@winuae.net>
Sun, 30 Oct 2022 15:56:27 +0000 (17:56 +0200)
committerToni Wilen <twilen@winuae.net>
Sun, 30 Oct 2022 15:56:27 +0000 (17:56 +0200)
custom.cpp
gencpu.cpp
include/newcpu.h
newcpu.cpp

index d72ff789c344f9ce4690b7b8c8dc97983c853627..05e47b76ae2d8df6f397633a8092f9d7657ad031 100644 (file)
@@ -14890,7 +14890,6 @@ extern int cpu_tracer;
 static int dma_cycle(uaecptr addr, uae_u32 value, int *mode, int *ipl)
 {
        int hpos_next, hpos_old;
-       int ws = 0;
 
        blt_info.nasty_cnt = 1;
        blt_info.wait_nasty = 0;
@@ -14927,10 +14926,7 @@ static int dma_cycle(uaecptr addr, uae_u32 value, int *mode, int *ipl)
                if (blt_info.nasty_cnt > 0) {
                        blt_info.nasty_cnt++;
                }
-               if (!ws) {
-                       *ipl = regs.ipl_pin;
-                       ws = 1;
-               }
+               *ipl = regs.ipl_pin;
                do_cycles(1 * CYCLE_UNIT);
                /* bus was allocated to dma channel, wait for next cycle.. */
        }
@@ -14963,7 +14959,7 @@ uae_u32 wait_cpu_cycle_read(uaecptr addr, int mode)
 {
        uae_u32 v = 0;
        int hpos;
-       int ipl = regs.ipl_pin;
+       int ipl = regs.ipl[0];
        evt_t now = get_cycles();
 
        sync_cycles();
@@ -15031,7 +15027,7 @@ uae_u32 wait_cpu_cycle_read(uaecptr addr, int mode)
 void wait_cpu_cycle_write(uaecptr addr, int mode, uae_u32 v)
 {
        int hpos;
-       int ipl = regs.ipl_pin;
+       int ipl = regs.ipl[0];
        evt_t now = get_cycles();
 
        sync_cycles();
index 141cfd98caeca6685cc45334266216b3b4773b49..06fbbbbfa88913732013762203bf81e614125869 100644 (file)
@@ -1390,6 +1390,7 @@ static void fill_prefetch_full_ntx(int beopcode)
                                        out("if(t1) opcode |= 0x10000;\n");
                        }
                        next_level_000();
+                       set_ipl();
                        fill_prefetch_1(2);
                } else {
                        fill_prefetch_1_empty(2);
@@ -6799,12 +6800,10 @@ static void gen_opcode (unsigned int opcode)
                        addcycles000(4);
                        out("MakeSR();\nregs.sr &= 0xFF00;\nregs.sr |= src & 0xFF;\n");
                        makefromsr();
-                       set_ipl();
                } else {
                        // MOVE TO SR
                        check_trace();
                        addcycles000(4);
-                       set_ipl();
                        out("regs.sr = src;\n");
                        makefromsr_t0();
                }
@@ -7258,6 +7257,7 @@ static void gen_opcode (unsigned int opcode)
                } else {
                        addop_ce020(curi, 0, 0);
                        // smode must be first in case it is A7. Except if 68040!
+                       set_ipl();
                        if (cpu_level == 4) {
                                genamode(NULL, Apdi, "7", sz_long, "old", 2, 0, GF_AA | GF_NOEXC3);
                                genamode(NULL, curi->smode, "srcreg", sz_long, "src", 1, 0, GF_AA);
@@ -7276,7 +7276,7 @@ static void gen_opcode (unsigned int opcode)
                                write_return_cycles(0);
                                out("}\n");
                        }
-                       genastore_2("src", Apdi, "7", sz_long, "old", 0, GF_IPLMID);
+                       genastore_2("src", Apdi, "7", sz_long, "old", 0, 0);
                        genastore("m68k_areg(regs, 7)", curi->smode, "srcreg", sz_long, "src");
                        out("m68k_areg(regs, 7) += offs;\n");
                        fill_prefetch_next_t();
@@ -7293,8 +7293,9 @@ static void gen_opcode (unsigned int opcode)
                        out("m68k_areg(regs, srcreg) = old;\n");
                } else {
                        m68k_pc_offset = 4;
+                       set_ipl();
                        genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
-                       genamode(NULL, am_unknown, "src", sz_long, "old", 1, 0, GF_IPLMID);
+                       genamode(NULL, am_unknown, "src", sz_long, "old", 1, 0, 0);
                        out("m68k_areg(regs, 7) = src + 4;\n");
                        m68k_pc_offset = 2;
                        genastore("old", curi->smode, "srcreg", curi->size, "src");
index 28da2183d87531d2b026d6a0b88c2a9ecd4d2417..e29f027764ac5871a7f316a7a51e860859ebf817 100644 (file)
@@ -206,8 +206,8 @@ struct regstruct
        int halted;
        int exception;
        int intmask;
-       int ipl[2], ipl_pin;
-       evt_t ipl_pin_change_evt;
+       int ipl[2], ipl_pin, ipl_pin_p;
+       evt_t ipl_pin_change_evt, ipl_pin_change_evt_p;
        evt_t ipl_evt, ipl_evt_pre;
        int ipl_evt_pre_mode;
 
index 4f4ec968b9d484a9756540d930c5dd885e4ad510..60d1432a0c42a146473ff737f01242bad20a0a00 100644 (file)
@@ -2376,16 +2376,18 @@ static void MakeFromSR_x(int t0trace)
        SET_ZFLG((regs.sr >> 2) & 1);
        SET_VFLG((regs.sr >> 1) & 1);
        SET_CFLG(regs.sr & 1);
+
        if (regs.t1 == ((regs.sr >> 15) & 1) &&
                regs.t0 == ((regs.sr >> 14) & 1) &&
                regs.s  == ((regs.sr >> 13) & 1) &&
                regs.m  == ((regs.sr >> 12) & 1) &&
                regs.intmask == ((regs.sr >> 8) & 7))
                return;
+
        regs.t1 = (regs.sr >> 15) & 1;
        regs.t0 = (regs.sr >> 14) & 1;
        regs.s  = (regs.sr >> 13) & 1;
-       regs.m = (regs.sr >> 12) & 1;
+       regs.m  = (regs.sr >> 12) & 1;
 
        if (regs.intmask != ((regs.sr >> 8) & 7)) {
                int newimask = (regs.sr >> 8) & 7;
@@ -2394,11 +2396,12 @@ static void MakeFromSR_x(int t0trace)
                        if (t0trace < 0 && regs.ipl[0] <= regs.intmask && regs.ipl[0] > newimask && regs.ipl[0] < 7) {
                                regs.ipl[0] = 0;
                        }
+               } else {
+                       if (regs.ipl[0] <= regs.intmask && regs.ipl_pin > newimask) {
+                               set_special(SPCFLAG_INT);
+                       }
                }
                regs.intmask = newimask;
-               if (regs.ipl_pin > regs.intmask) {
-                       set_special(SPCFLAG_INT);
-               }
        }
 
        if (currprefs.cpu_model >= 68020) {
@@ -2865,11 +2868,8 @@ kludge_me_do:
                return;
        }
        regs.ird = regs.ir;
-       if (m68k_accurate_ipl && interrupt) {
-               ipl_fetch_now();
-       }
        x_do_cycles(2 * cpucycleunit);
-       if (m68k_accurate_ipl && !interrupt) {
+       if (m68k_accurate_ipl) {
                ipl_fetch_next();
        }
        regs.irc = x_get_word(m68k_getpc() + 2); // prefetch 2
@@ -4416,13 +4416,14 @@ static int time_for_interrupt(void)
 // ipl check mid next memory cycle
 void ipl_fetch_next_pre(void)
 {
+       ipl_fetch_next();
        regs.ipl_evt_pre = get_cycles();
        regs.ipl_evt_pre_mode = 1;
 }
 
 void ipl_fetch_now_pre(void)
 {
-       regs.ipl[1] = regs.ipl_pin;
+       ipl_fetch_now();
        regs.ipl_evt_pre = get_cycles();
        regs.ipl_evt_pre_mode = 0;
 }
@@ -4431,6 +4432,7 @@ void ipl_fetch_now_pre(void)
 void ipl_fetch_now(void)
 {
        evt_t c = get_cycles();
+
        regs.ipl_evt = c;
        regs.ipl[0] = regs.ipl_pin;
        regs.ipl[1] = 0;
@@ -4442,9 +4444,13 @@ void ipl_fetch_now(void)
 void ipl_fetch_next(void)
 {
        evt_t c = get_cycles();
+
        if (c - regs.ipl_pin_change_evt >= cpuipldelay4) {
                regs.ipl[0] = regs.ipl_pin;
                regs.ipl[1] = 0;
+       } else if (c - regs.ipl_pin_change_evt_p >= cpuipldelay2) {
+               regs.ipl[0] = regs.ipl_pin_p;
+               regs.ipl[1] = 0;
        } else {
                regs.ipl[1] = regs.ipl_pin;
        }
@@ -4458,6 +4464,36 @@ void intlev_load(void)
        doint();
 }
 
+static void update_ipl(int ipl)
+{
+       evt_t c = get_cycles();
+       regs.ipl_pin_change_evt_p = regs.ipl_pin_change_evt;
+       regs.ipl_pin_p = regs.ipl_pin;
+       regs.ipl_pin_change_evt = c;
+       regs.ipl_pin = ipl;
+       if (m68k_accurate_ipl) {
+               // check if 68000/010 interrupt was detected mid memory access,
+               // 2 cycles from start of memory cycle
+               if (ipl > 0 && c == regs.ipl_evt_pre + cpuipldelay2) {
+                       if (regs.ipl_evt_pre_mode) {
+                               ipl_fetch_next();
+                       } else {
+                               ipl_fetch_now();
+                       }
+               }
+       }
+#ifdef DEBUGGER
+       if (debug_dma) {
+               record_dma_ipl(current_hpos(), vpos);
+       }
+#endif
+}
+
+static void doint_delayed(uae_u32 v)
+{
+       update_ipl(v);
+}
+
 void doint(void)
 {
 #ifdef WITH_PPC
@@ -4466,26 +4502,23 @@ void doint(void)
                        return;
        }
 #endif
-       int il = intlev();
-       if (regs.ipl_pin != il) {
-               regs.ipl_pin = il;
-               regs.ipl_pin_change_evt = get_cycles();
-               if (m68k_accurate_ipl) {
-                       // check if 68000/010 interrupt was detected mid memory access,
-                       // 2 cycles from start of memory cycle
-                       if (il > 0 && get_cycles() == regs.ipl_evt_pre + cpuipldelay2) {
-                               if (regs.ipl_evt_pre_mode) {
-                                       ipl_fetch_next();
-                               } else {
-                                       ipl_fetch_now();
-                               }
-                       }
-               }
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_ipl(current_hpos(), vpos);
+       int ipl = intlev();
+
+       if (regs.ipl_pin != ipl) {
+
+               // Paula does low to high IPL changes about 1.5 CPU clocks later than high to low.
+               // -> CPU detects IPL change 1 CCK later if any IPL pin has high to low transition.
+               // (In real world IPL is active low and delay is added if 0 to 1 transition)
+               if (m68k_accurate_ipl && regs.ipl_pin >= 0 && ipl >= 0 && (
+                       ((regs.ipl_pin & 1) && !(ipl & 1)) ||
+                       ((regs.ipl_pin & 2) && !(ipl & 2)) ||
+                       ((regs.ipl_pin & 4) && !(ipl & 4))
+                       )) {
+                               event2_newevent_xx(-1, CYCLE_UNIT, ipl, doint_delayed);
+                               return;
                }
-#endif
+
+               update_ipl(ipl);
        }
        if (m68k_interrupt_delay) {
                if (!m68k_accurate_ipl && regs.ipl_pin > regs.intmask) {
@@ -4801,7 +4834,7 @@ static void m68k_run_1 (void)
                                cpu_cycles = adjust_cycles (cpu_cycles);
                                do_cycles(cpu_cycles);
                                regs.instruction_cnt++;
-                               if (r->spcflags || regs.ipl[0]) {
+                               if (r->spcflags || regs.ipl[0] > 0) {
                                        if (do_specialties (cpu_cycles))
                                                exit = true;
                                }
@@ -4931,7 +4964,7 @@ cont:
                                        log_dma_record ();
                                }
 
-                               if (r->spcflags || regs.ipl[0]) {
+                               if (r->spcflags || regs.ipl[0] > 0) {
                                        if (do_specialties (0))
                                                exit = true;
                                }
@@ -5997,7 +6030,7 @@ static void m68k_run_2ce (void)
                                regs.instruction_cnt++;
 
                cont:
-                               if (r->spcflags || regs.ipl[0]) {
+                               if (r->spcflags || regs.ipl[0] > 0) {
                                        if (do_specialties (0))
                                                exit = true;
                                }
@@ -6140,7 +6173,7 @@ static void m68k_run_2p (void)
                                        x_do_cycles(cpu_cycles);
 
 cont:
-                               if (r->spcflags || regs.ipl[0]) {
+                               if (r->spcflags || regs.ipl[0] > 0) {
                                        if (do_specialties (cpu_cycles))
                                                exit = true;
                                }
@@ -6919,9 +6952,11 @@ uae_u8 *restore_cpu (uae_u8 *src)
                        regs.ipl[0] = restore_u8();
                        regs.ipl[1] = restore_u8();
                        regs.ipl_pin = (uae_s32)restore_u8();
+                       regs.ipl_pin_p = (uae_s32)restore_u8();
                        regs.ipl_evt = restore_u64();
                        regs.ipl_evt_pre = restore_u64();
                        regs.ipl_pin_change_evt = restore_u64();
+                       regs.ipl_pin_change_evt_p = restore_u64();
                }
        }
 
@@ -7359,9 +7394,11 @@ uae_u8 *save_cpu(size_t *len, uae_u8 *dstptr)
                save_u8(regs.ipl[0]);
                save_u8(regs.ipl[1]);
                save_u8(regs.ipl_pin);
+               save_u8(regs.ipl_pin_p);
                save_u64(regs.ipl_evt);
                save_u64(regs.ipl_evt_pre);
                save_u64(regs.ipl_pin_change_evt);
+               save_u64(regs.ipl_pin_change_evt_p);
        }
        *len = dst - dstbak;
        return dstbak;