]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
68030 MMU prefetch+data cache mode bus error retry fix.
authorToni Wilen <twilen@winuae.net>
Sat, 24 Nov 2018 14:17:39 +0000 (16:17 +0200)
committerToni Wilen <twilen@winuae.net>
Sat, 24 Nov 2018 14:17:39 +0000 (16:17 +0200)
cpummu30.cpp
include/newcpu.h
newcpu.cpp

index 11a75b24f6d3f18bbb8bc82604a5930344c206cf..1a984aac962c322f7b641a1c410b7a978ce9d214 100644 (file)
@@ -2562,7 +2562,9 @@ void mmu030_set_funcs(void)
        st |= f; \
        mmu030_state[1] = st;
 
-static void mmu030_unaligned_read_continue(uaecptr addr, int fc)
+typedef uae_u32(*unaligned_read_func)(uaecptr addr, uae_u32 fc, int size, int flags);
+
+static void mmu030_unaligned_read_continue(uaecptr addr, int fc, unaligned_read_func func)
 {
        uae_u32 st = mmu030_state[1];
 
@@ -2575,32 +2577,32 @@ static void mmu030_unaligned_read_continue(uaecptr addr, int fc)
                        // odd long access: byte + word + byte
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
                                mmu030_data_buffer_out &= 0x00ffffff;
-                               mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_L) << 24;
+                               mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_L) << 24;
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
                                addr++;
                        }
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
                                mmu030_data_buffer_out &= 0xff0000ff;
-                               mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 8;
+                               mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 8;
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
                                addr += 2;
                        }
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
                                mmu030_data_buffer_out &= 0xffffff00;
-                               mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
+                               mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
                        }
                } else {
                        // even but unaligned long access: word + word
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
                                mmu030_data_buffer_out &= 0x0000ffff;
-                               mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_L) << 16;
+                               mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_L) << 16;
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
                                addr += 2;
                        }
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
                                mmu030_data_buffer_out &= 0xffff0000;
-                               mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 0;
+                               mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 0;
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
                        }
                }
@@ -2608,13 +2610,13 @@ static void mmu030_unaligned_read_continue(uaecptr addr, int fc)
                // odd word access: byte + byte
                if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
                        mmu030_data_buffer_out &= 0x00ff;
-                       mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_W) << 8;
+                       mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_W) << 8;
                        unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
                        addr++;
                }
                if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
                        mmu030_data_buffer_out &= 0xff00;
-                       mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
+                       mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
                        unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
                }
        }
@@ -2624,7 +2626,9 @@ static void mmu030_unaligned_read_continue(uaecptr addr, int fc)
 #endif
 }
 
-static void mmu030_unaligned_write_continue(uaecptr addr, int fc)
+typedef void (*unaligned_write_func)(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags);
+
+static void mmu030_unaligned_write_continue(uaecptr addr, int fc, unaligned_write_func func)
 {
        uae_u32 st = mmu030_state[1];
 
@@ -2636,40 +2640,40 @@ static void mmu030_unaligned_write_continue(uaecptr addr, int fc)
                // odd long access: byte + word + byte
                if (st & MMU030_STATEFLAG1_SUBACCESSX) {
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
-                               mmu030_put_generic(addr, mmu030_data_buffer_out >> 24, fc, sz_byte, MMU030_SSW_SIZE_L);
+                               func(addr, mmu030_data_buffer_out >> 24, fc, sz_byte, MMU030_SSW_SIZE_L);
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
                                addr++;
                        }
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
-                               mmu030_put_generic(addr, mmu030_data_buffer_out >> 8, fc, sz_word, MMU030_SSW_SIZE_W);
+                               func(addr, mmu030_data_buffer_out >> 8, fc, sz_word, MMU030_SSW_SIZE_W);
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
                                addr += 2;
                        }
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
-                               mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
+                               func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
                        }
                } else {
                        // even but unaligned long access: word + word
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
-                               mmu030_put_generic(addr, mmu030_data_buffer_out >> 16, fc, sz_word, MMU030_SSW_SIZE_L);
+                               func(addr, mmu030_data_buffer_out >> 16, fc, sz_word, MMU030_SSW_SIZE_L);
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
                                addr += 2;
                        }
                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
-                               mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_word, MMU030_SSW_SIZE_W);
+                               func(addr, mmu030_data_buffer_out >> 0, fc, sz_word, MMU030_SSW_SIZE_W);
                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
                        }
                }
        } else {
                // odd word access: byte + byte
                if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
-                       mmu030_put_generic(addr, mmu030_data_buffer_out >> 8, fc, sz_byte, MMU030_SSW_SIZE_W);
+                       func(addr, mmu030_data_buffer_out >> 8, fc, sz_byte, MMU030_SSW_SIZE_W);
                        unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
                        addr++;
                }
                if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
-                       mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
+                       func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
                        unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
                }
        }
@@ -2829,7 +2833,7 @@ void m68k_do_rte_mmu030 (uaecptr a7)
                                        mmu030_data_buffer_out = mmu030_ad[idxsize].val;
                                }
                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
-                                       mmu030_unaligned_read_continue(addr, fc);
+                                       mmu030_unaligned_read_continue(addr, fc, mmu030_get_generic);
                                } else {
                                        switch (size)
                                        {
@@ -2852,7 +2856,7 @@ void m68k_do_rte_mmu030 (uaecptr a7)
                                }
                        } else {
                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
-                                       mmu030_unaligned_write_continue(addr, fc);
+                                       mmu030_unaligned_write_continue(addr, fc, mmu030_put_generic);
                                } else {
                                        switch (size)
                                        {
@@ -3235,7 +3239,7 @@ void m68k_do_rte_mmu030c (uaecptr a7)
                                        mmu030_data_buffer_out = mmu030_ad[idxsize].val;
                                }
                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
-                                       mmu030_unaligned_read_continue(addr, fc);
+                                       mmu030_unaligned_read_continue(addr, fc, read_dcache030_retry);
                                } else {
                                        switch (size)
                                        {
@@ -3258,7 +3262,7 @@ void m68k_do_rte_mmu030c (uaecptr a7)
                                }
                        } else {
                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
-                                       mmu030_unaligned_write_continue(addr, fc);
+                                       mmu030_unaligned_write_continue(addr, fc, write_dcache030_retry);
                                } else {
                                        switch (size)
                                        {
index f139275d172a4d8a37d56dbe217359236c5609ec..0c7a0a7f52ef7cec3ce236fb695863dcd84666c6 100644 (file)
@@ -584,9 +584,11 @@ extern void(*write_data_030_fc_lput)(uaecptr, uae_u32, uae_u32);
 extern void write_dcache030_bput(uaecptr, uae_u32, uae_u32);
 extern void write_dcache030_wput(uaecptr, uae_u32, uae_u32);
 extern void write_dcache030_lput(uaecptr, uae_u32, uae_u32);
+extern void write_dcache030_retry(uaecptr addr, uae_u32 v, uae_u32 fc, int size, int flags);
 extern uae_u32 read_dcache030_bget(uaecptr, uae_u32);
 extern uae_u32 read_dcache030_wget(uaecptr, uae_u32);
 extern uae_u32 read_dcache030_lget(uaecptr, uae_u32);
+extern uae_u32 read_dcache030_retry(uaecptr addr, uae_u32 fc, int size, int flags);
 
 extern void write_dcache030_mmu_bput(uaecptr, uae_u32);
 extern void write_dcache030_mmu_wput(uaecptr, uae_u32);
index c88d3e73eaed1062f26e5c2fbdaaaff24f5dfb03..cc0cbf52a3e7a9074f885f869224cdbaac133e85 100644 (file)
@@ -9792,6 +9792,14 @@ void write_dcache030_lput(uaecptr addr, uae_u32 v,uae_u32 fc)
        write_dcache030x(addr, v, 2, fc);
 }
 
+// 68030 MMU bus fault retry case, direct write, store to cache if enabled
+void write_dcache030_retry(uaecptr addr, uae_u32 v, uae_u32 fc, int size, int flags)
+{
+       regs.fc030 = fc;
+       mmu030_put_generic(addr, v, fc, size, flags);
+       write_dcache030x(addr, v, size, fc);
+}
+
 static void dcache030_maybe_burst(uaecptr addr, struct cache030 *c, int lws)
 {
        if ((c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
@@ -9885,88 +9893,113 @@ static uae_u32 read_dcache030_debug(uaecptr addr, uae_u32 size, uae_u32 fc, bool
        return out;
 }
 
-uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
+static bool read_dache030_2(uaecptr addr, uae_u32 size, uae_u32 *valp)
 {
+       // data cache enabled?
+       if (!(regs.cacr & 0x100))
+               return false;
+
        uae_u32 addr_o = addr;
-       regs.fc030 = fc;
-       if (regs.cacr & 0x100) { // data cache enabled?
-               static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
-               struct cache030 *c1, *c2;
-               int lws1, lws2;
-               uae_u32 tag1, tag2;
-               int aligned = addr & 3;
-               uae_u32 v1, v2;
-               int width = 8 << size;
-               int offset = 8 * aligned;
-               uae_u32 out;
-
-               c1 = getdcache030 (dcaches030, addr, &tag1, &lws1);
-               addr &= ~3;
-               if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
-                       // MMU validate address, returns zero if valid but uncacheable
-                       // throws bus error if invalid
-                       uae_u8 cs = dcache_check(addr_o, false, size);
-                       if (!(cs & CACHE_ENABLE_DATA))
-                               goto end;
-                       v1 = dcache_lget(addr);
-                       update_dcache030 (c1, v1, tag1, fc, lws1);
-                       if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
-                               dcache030_maybe_burst(addr, c1, lws1);
+       uae_u32 fc = regs.fc030;
+       static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
+       struct cache030 *c1, *c2;
+       int lws1, lws2;
+       uae_u32 tag1, tag2;
+       int aligned = addr & 3;
+       uae_u32 v1, v2;
+       int width = 8 << size;
+       int offset = 8 * aligned;
+       uae_u32 out;
+
+       c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
+       addr &= ~3;
+       if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
+               // MMU validate address, returns zero if valid but uncacheable
+               // throws bus error if invalid
+               uae_u8 cs = dcache_check(addr_o, false, size);
+               if (!(cs & CACHE_ENABLE_DATA))
+                       return false;
+               v1 = dcache_lget(addr);
+               update_dcache030(c1, v1, tag1, fc, lws1);
+               if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
+                       dcache030_maybe_burst(addr, c1, lws1);
 #if VALIDATE_68030_DATACACHE
-                       validate_dcache030();
+               validate_dcache030();
 #endif
-               } else {
-                       // Cache hit, inhibited caching do not prevent read hits.
-                       v1 = c1->data[lws1];
-               }
+       } else {
+               // Cache hit, inhibited caching do not prevent read hits.
+               v1 = c1->data[lws1];
+       }
 
-               // only one long fetch needed?
-               if (width + offset <= 32) {
-                       out = v1 >> (32 - (offset + width));
-                       out &= mask[size];
+       // only one long fetch needed?
+       if (width + offset <= 32) {
+               out = v1 >> (32 - (offset + width));
+               out &= mask[size];
 #if VALIDATE_68030_DATACACHE
-                       validate_dcache030_read(addr_o, out, size);
-#endif
-                       return out;
-               }
-
-               // no, need another one
-               addr += 4;
-               c2 = getdcache030 (dcaches030, addr, &tag2, &lws2);
-               if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
-                       uae_u8 cs = dcache_check(addr, false, 2);
-                       if (!(cs & CACHE_ENABLE_DATA))
-                               goto end;
-                       v2 = dcache_lget(addr);
-                       update_dcache030 (c2, v2, tag2, fc, lws2);
-                       if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
-                               dcache030_maybe_burst(addr, c2, lws2);
+               validate_dcache030_read(addr_o, out, size);
+#endif
+               *valp = out;
+               return true;
+       }
+
+       // no, need another one
+       addr += 4;
+       c2 = getdcache030(dcaches030, addr, &tag2, &lws2);
+       if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
+               uae_u8 cs = dcache_check(addr, false, 2);
+               if (!(cs & CACHE_ENABLE_DATA))
+                       return false;
+               v2 = dcache_lget(addr);
+               update_dcache030(c2, v2, tag2, fc, lws2);
+               if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
+                       dcache030_maybe_burst(addr, c2, lws2);
 #if VALIDATE_68030_DATACACHE
-                       validate_dcache030();
+               validate_dcache030();
 #endif
-               } else {
-                       v2 = c2->data[lws2];
-               }
+       } else {
+               v2 = c2->data[lws2];
+       }
 
-               uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
-               out = (uae_u32)(v64 >> (64 - (offset + width)));
-               out &= mask[size];
+       uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
+       out = (uae_u32)(v64 >> (64 - (offset + width)));
+       out &= mask[size];
 
 #if VALIDATE_68030_DATACACHE
-               validate_dcache030_read(addr_o, out, size);
+       validate_dcache030_read(addr_o, out, size);
 #endif
-               return out;
+       *valp = out;
+       return true;
+}
+
+uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
+{
+       uae_u32 val;
+       regs.fc030 = fc;
 
+       if (!read_dache030_2(addr, size, &val)) {
+               // read from memory, data cache is disabled or inhibited.
+               if (size == 2)
+                       return dcache_lget(addr);
+               else if (size == 1)
+                       return dcache_wget(addr);
+               else
+                       return dcache_bget(addr);
        }
-end:
-       // read from memory, data cache is disabled or inhibited.
-       if (size == 2)
-               return dcache_lget (addr_o);
-       else if (size == 1)
-               return dcache_wget (addr_o);
-       else
-               return dcache_bget (addr_o);
+       return val;
 }
+
+// 68030 MMU bus fault retry case, either read from cache or use direct reads
+uae_u32 read_dcache030_retry(uaecptr addr, uae_u32 fc, int size, int flags)
+{
+       uae_u32 val;
+       regs.fc030 = fc;
+
+       if (!read_dache030_2(addr, size, &val)) {
+               return mmu030_get_generic(addr, fc, size, flags);
+       }
+       return val;
+}
+
 uae_u32 read_dcache030_bget(uaecptr addr, uae_u32 fc)
 {
        return read_dcache030(addr, 0, fc);