From 08eec257ab6a94b94f2ef3e9e0e973b60f8dd50e Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 24 Nov 2018 16:17:39 +0200 Subject: [PATCH] 68030 MMU prefetch+data cache mode bus error retry fix. --- cpummu30.cpp | 44 +++++++------ include/newcpu.h | 2 + newcpu.cpp | 167 ++++++++++++++++++++++++++++------------------- 3 files changed, 126 insertions(+), 87 deletions(-) diff --git a/cpummu30.cpp b/cpummu30.cpp index 11a75b24..1a984aac 100644 --- a/cpummu30.cpp +++ b/cpummu30.cpp @@ -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) { diff --git a/include/newcpu.h b/include/newcpu.h index f139275d..0c7a0a7f 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -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); diff --git a/newcpu.cpp b/newcpu.cpp index c88d3e73..cc0cbf52 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -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); -- 2.47.3