]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
68030 MMU fixes. Software fixed pipeline stage fixes and more compatible (prefetch...
authorToni Wilen <twilen@winuae.net>
Thu, 21 May 2020 13:48:20 +0000 (16:48 +0300)
committerToni Wilen <twilen@winuae.net>
Thu, 21 May 2020 13:48:20 +0000 (16:48 +0300)
cpummu30.cpp
gencpu.cpp
include/cpummu030.h
newcpu.cpp

index 24eb66d87e6cfe0edd4c590ff5567ca2d1767649..96d14ae53a8a9e4038b385109e780de8fd5d2754 100644 (file)
@@ -72,7 +72,7 @@ uae_u32 mmu030_disp_store[2];
 uae_u32 mmu030_fmovem_store[2];
 uae_u8 mmu030_cache_state;
 struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS + 1];
-bool ismoves030;
+bool ismoves030, islrmw030;
 
 static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write);
 static uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level);
@@ -1803,7 +1803,6 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
                fc = regs.mmu_ssw & MMU030_SSW_FC_MASK;
                flags = regs.mmu_ssw & ~(MMU030_SSW_FC | MMU030_SSW_RC | MMU030_SSW_FB | MMU030_SSW_RB | MMU030_SSW_RW | 7);
        }
-       ismoves030 = false;
        regs.wb3_status = 0;
        regs.wb2_status = 0;
        regs.mmu_fault_addr = addr;
@@ -1817,6 +1816,10 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
                }
        } else {
                if (currprefs.cpu_compatible) {
+                       regs.wb2_status = mmu030fixupreg(0);
+                       mmu030fixupmod(regs.wb2_status, 0, 0);
+                       regs.wb3_status = mmu030fixupreg(1);
+                       mmu030fixupmod(regs.wb3_status, 0, 1);
                        if (regs.prefetch020_valid[1] != 1 && regs.prefetch020_valid[2] == 1) {
                                regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
                        } else if (regs.prefetch020_valid[2] != 1) {
@@ -1833,6 +1836,7 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
        regs.mmu_ssw |= read ? MMU030_SSW_RW : 0;
        regs.mmu_ssw |= flags;
        regs.mmu_ssw |= fc;
+       regs.mmu_ssw |= islrmw030 ? MMU030_SSW_RM : 0;
        // temporary store in 68040+ variables because stack frame creation may modify them.
        regs.wb3_data = mmu030_data_buffer_out;
        regs.wb2_address = mmu030_state[1];
@@ -1848,8 +1852,11 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
        write_log(_T("\n"));
 #endif
 
+       ismoves030 = false;
+       islrmw030 = false;
+
 #if 0
-       if (addr == 0x00016060)
+       if (addr == 0xc1026ea0)
                write_log("!");
 #endif
 #if 0
@@ -2441,7 +2448,7 @@ uae_u8 uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size)
 }
 
 /* Locked RMW is rarely used */
-uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc)
+static uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc)
 {
        if (size == sz_byte) {
                return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
@@ -2460,10 +2467,13 @@ uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc)
 uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
 {
        uae_u32 fc = (regs.s ? 4 : 0) | 1;
-       return uae_mmu030_get_lrmw_fcx(addr, size, fc);
+       islrmw030 = true;
+       uae_u32 v = uae_mmu030_get_lrmw_fcx(addr, size, fc);
+       islrmw030 = false;
+       return v;
 }
 
-void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc)
+static void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc)
 {
        if (size == sz_byte) {
                mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
@@ -2482,7 +2492,9 @@ void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc)
 void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size)
 {
        uae_u32 fc = (regs.s ? 4 : 0) | 1;
+       islrmw030 = true;
        uae_mmu030_put_lrmw_fcx(addr, val, size, fc);
+       islrmw030 = false;
 }
 
 uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
@@ -2947,8 +2959,8 @@ void m68k_do_rte_mmu030 (uaecptr a7)
                                mmu030_opcode_stageb = stageb;
                                write_log(_T("Software fixed stage B! opcode = %04x\n"), stageb);
                        } else {
-                               mmu030_ad_v[idxsize].val = stageb;
-                               idxsize_done = idxsize;
+                               mmu030_ad_v[idxsize_done].val = stageb;
+                               idxsize_done++;
                                write_log(_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode_v, stageb);
                        }
                }
@@ -3007,9 +3019,6 @@ void m68k_do_rte_mmu030 (uaecptr a7)
                                write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
                        }
                }
-               if (idxsize >= 0 && mmu030_ad[idxsize].done) {
-                       write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
-               }
 #endif
 
 #if MMU030_DEBUG
@@ -3366,6 +3375,11 @@ void m68k_do_rte_mmu030c (uaecptr a7)
                        mmu030_ad_v[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4);
                }
 
+               regs.wb2_status = v >> 8;
+               regs.wb3_status = mmu030_state_2 >> 8;
+               mmu030fixupmod(regs.wb2_status, 1, -1);
+               mmu030fixupmod(regs.wb3_status, 1, -1);
+
                // did we have data fault but DF bit cleared?
                if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
                        // DF not set: mark access as done
@@ -3474,10 +3488,6 @@ void m68k_do_rte_mmu030c (uaecptr a7)
                        if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
                                write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
                        }
-               } else {
-                       if (idxsize >= 0 && mmu030_ad[idxsize].done) {
-                               write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
-                       }
                }
 #endif
                if (read) {
index 502a526681b1c2364a0f6e720c37e38c4f3f783c..518095255e51e7c2fbaff7a89e0ed7dbc4c43ec0 100644 (file)
@@ -411,8 +411,18 @@ static bool needmmufixup(void)
        }
        if (!using_mmu)
                return false;
-       if (using_mmu == 68040 && (mmufixupstate || mmufixupcnt > 0))
+       if (using_mmu == 68040 && (mmufixupstate || mmufixupcnt > 0)) {
                return false;
+       }
+       if (using_mmu == 68030) {
+               switch (g_instr->mnemo)
+               {
+               case i_LINK:
+               case i_RTD:
+               case i_RTR:
+                       return false;
+               }
+       }
        return true;
 }
 
index 85a6d532bbb69d43e0ba880e088cfab46391f589..13691ac1ca2afb456ddf9fd11c2c8879a18bf4db 100644 (file)
@@ -26,7 +26,7 @@ extern uae_u32 mmu030_data_buffer_out;
 extern uae_u32 mmu030_disp_store[2];
 extern uae_u32 mmu030_fmovem_store[2];
 extern uae_u8 mmu030_cache_state, mmu030_cache_state_default;
-extern bool ismoves030;
+extern bool ismoves030, islrmw030;
 
 #define MMU030_STATEFLAG1_FMOVEM 0x2000
 #define MMU030_STATEFLAG1_MOVEM1 0x4000
@@ -84,9 +84,7 @@ uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc);
 uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc);
 
 uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size);
-uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc);
 void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size);
-void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc);
 
 void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags);
 uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags);
@@ -750,9 +748,11 @@ STATIC_INLINE void put_byte_mmu030c_state (uaecptr addr, uae_u32 v)
 }
 STATIC_INLINE void put_lrmw_byte_mmu030c_state (uaecptr addr, uae_u32 v)
 {
+       islrmw030 = true;
        ACCESS_CHECK_PUT
        write_dcache030_lrmw_mmu(addr, v, 0);
        ACCESS_EXIT_PUT
+       islrmw030 = false;
 }
 STATIC_INLINE void put_word_mmu030c_state (uaecptr addr, uae_u32 v)
 {
@@ -762,9 +762,11 @@ STATIC_INLINE void put_word_mmu030c_state (uaecptr addr, uae_u32 v)
 }
 STATIC_INLINE void put_lrmw_word_mmu030c_state (uaecptr addr, uae_u32 v)
 {
+       islrmw030 = true;
        ACCESS_CHECK_PUT
        write_dcache030_lrmw_mmu(addr, v, 1);
        ACCESS_EXIT_PUT
+       islrmw030 = false;
 }
 STATIC_INLINE void put_long_mmu030c_state (uaecptr addr, uae_u32 v)
 {
@@ -774,9 +776,11 @@ STATIC_INLINE void put_long_mmu030c_state (uaecptr addr, uae_u32 v)
 }
 STATIC_INLINE void put_lrmw_long_mmu030c_state (uaecptr addr, uae_u32 v)
 {
+       islrmw030 = true;
        ACCESS_CHECK_PUT
        write_dcache030_lrmw_mmu(addr, v, 2);
        ACCESS_EXIT_PUT
+       islrmw030 = false;
 }
 
 STATIC_INLINE uae_u32 get_byte_mmu030c_state (uaecptr addr)
@@ -790,9 +794,11 @@ STATIC_INLINE uae_u32 get_byte_mmu030c_state (uaecptr addr)
 STATIC_INLINE uae_u32 get_lrmw_byte_mmu030c_state (uaecptr addr)
 {
        uae_u32 v;
+       islrmw030 = true;
        ACCESS_CHECK_GET
     v = read_dcache030_lrmw_mmu(addr, 0);
        ACCESS_EXIT_GET
+       islrmw030 = false;
        return v;
 }
 
@@ -807,9 +813,11 @@ STATIC_INLINE uae_u32 get_word_mmu030c_state (uaecptr addr)
 STATIC_INLINE uae_u32 get_lrmw_word_mmu030c_state (uaecptr addr)
 {
        uae_u32 v;
+       islrmw030 = true;
        ACCESS_CHECK_GET
     v = read_dcache030_lrmw_mmu(addr, 1);
        ACCESS_EXIT_GET
+       islrmw030 = false;
        return v;
 }
 STATIC_INLINE uae_u32 get_long_mmu030c_state (uaecptr addr)
@@ -823,9 +831,11 @@ STATIC_INLINE uae_u32 get_long_mmu030c_state (uaecptr addr)
 STATIC_INLINE uae_u32 get_lrmw_long_mmu030c_state (uaecptr addr)
 {
        uae_u32 v;
+       islrmw030 = true;
        ACCESS_CHECK_GET
     v = read_dcache030_lrmw_mmu(addr, 2);
        ACCESS_EXIT_GET
+       islrmw030 = false;
        return v;
 }
 
index 759edc5cb85e9f67809b70fc3852af864590280a..82a51c81352ea68eca7a261a4ac6c00b1fb06535 100644 (file)
@@ -823,6 +823,7 @@ static void put_byte030_cicheck(uaecptr addr, uae_u32 v)
 }
 
 static uae_u32 (*icache_fetch)(uaecptr);
+static uae_u16 (*icache_fetch_word)(uaecptr);
 static uae_u32 (*dcache_lget)(uaecptr);
 static uae_u32 (*dcache_wget)(uaecptr);
 static uae_u32 (*dcache_bget)(uaecptr);
@@ -1356,6 +1357,7 @@ static void set_x_funcs (void)
        dcache_check = dcache_check_nommu;
 
        icache_fetch = get_longi;
+       icache_fetch_word = NULL;
        if (currprefs.cpu_cycle_exact) {
                icache_fetch = mem_access_delay_longi_read_ce020;
        }
@@ -1404,8 +1406,10 @@ static void set_x_funcs (void)
                if (currprefs.mmu_model) {
                        if (currprefs.cpu_compatible) {
                                icache_fetch = uae_mmu030_get_ilong_fc;
+                               icache_fetch_word = uae_mmu030_get_iword_fc;
                        } else {
                                icache_fetch = uae_mmu030_get_ilong;
+                               icache_fetch_word = uae_mmu030_get_iword_fc;
                        }
                        dcache_lput = uae_mmu030_put_long_fc;
                        dcache_wput = uae_mmu030_put_word_fc;
@@ -8088,7 +8092,28 @@ STATIC_INLINE void update_dcache030 (struct cache030 *c, uae_u32 val, uae_u32 ta
        c->data[lws] = val;
 }
 
-static void fill_icache030 (uae_u32 addr)
+static bool maybe_icache030(uae_u32 addr)
+{
+       int lws;
+       uae_u32 tag;
+       uae_u32 data;
+       struct cache030 *c;
+
+       regs.fc030 = (regs.s ? 4 : 0) | 2;
+       addr &= ~3;
+       if (regs.cacheholdingaddr020 == addr || regs.cacheholdingdata_valid == 0)
+               return true;
+       c = geticache030(icaches030, addr, &tag, &lws);
+       if ((regs.cacr & 1) && c->valid[lws] && c->tag == tag) {
+               // cache hit
+               regs.cacheholdingaddr020 = addr;
+               regs.cacheholdingdata020 = c->data[lws];
+               return true;
+       }
+       return false;
+}
+
+static void fill_icache030(uae_u32 addr)
 {
        int lws;
        uae_u32 tag;
@@ -8645,6 +8670,10 @@ uae_u32 get_word_030_prefetch (int o)
        regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
        regs.prefetch020_valid[2] = false;
        if (!regs.prefetch020_valid[1]) {
+               if (regs.pipeline_stop) {
+                       regs.db = regs.prefetch020[0];
+                       return v;
+               }
                do_access_or_bus_error(0xffffffff, pc + 4);
        }
 #if MORE_ACCURATE_68020_PIPELINE
@@ -9426,15 +9455,59 @@ void fill_prefetch_030_ntx_continue (void)
        regs.cacheholdingdata_valid = 1;
        regs.cacheholdingaddr020 = 0xffffffff;
 
-       for (int i = 2; i >= 0; i--) {
-               if (!regs.prefetch020_valid[i])
-                       break;
+       if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1] && regs.prefetch020_valid[2]) {
+               for (int i = 2; i >= 0; i--) {
+                       regs.prefetch020[i + 1] = regs.prefetch020[i];
+               }
+               for (int i = 1; i <= 3; i++) {
+#if MORE_ACCURATE_68020_PIPELINE
+                       pipeline_020(pc);
+#endif
+                       regs.prefetch020[i - 1] = regs.prefetch020[i];
+                       pc += 2;
+                       idx++;
+               }
+       } else if (regs.prefetch020_valid[2] && !regs.prefetch020_valid[1]) {
+               regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
+               regs.prefetch020[1] = regs.prefetch020[2];
+               regs.prefetch020_valid[2] = 0;
+               pc += 2;
+               idx++;
+#if MORE_ACCURATE_68020_PIPELINE
+               pipeline_020(pc);
+#endif
+               if (!regs.pipeline_stop) {
+                       if (maybe_icache030(pc)) {
+                               regs.prefetch020[2] = regs.cacheholdingdata020 >> (regs.cacheholdingaddr020 == pc ? 16 : 0);
+                       } else {
+                               regs.prefetch020[2] = icache_fetch_word(pc);
+                       }
+                       regs.prefetch020_valid[2] = 1;
+                       pc += 2;
+                       idx++;
 #if MORE_ACCURATE_68020_PIPELINE
-               if (idx >= 1) {
                        pipeline_020(pc);
+#endif
                }
+
+       } else if (regs.prefetch020_valid[2] && regs.prefetch020_valid[1]) {
+               pc += 2;
+#if MORE_ACCURATE_68020_PIPELINE
+               pipeline_020(pc);
 #endif
                pc += 2;
+#if MORE_ACCURATE_68020_PIPELINE
+               pipeline_020(pc);
+#endif
+               idx += 2;
+       }
+
+       while (idx < 2) {
+               regs.prefetch020[0] = regs.prefetch020[1];
+               regs.prefetch020[1] = regs.prefetch020[2];
+               regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
+               regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
+               regs.prefetch020_valid[2] = false;
                idx++;
        }
 
@@ -9465,9 +9538,9 @@ void fill_prefetch_030_ntx_continue (void)
 
        ipl_fetch();
        if (currprefs.cpu_cycle_exact)
-               regs.irc = get_word_ce030_prefetch_opcode (0);
+               regs.irc = get_word_ce030_prefetch_opcode(0);
        else
-               regs.irc = get_word_030_prefetch (0);
+               regs.irc = get_word_030_prefetch(0);
 }
 
 void fill_prefetch_020_ntx(void)