From 5f648f27fbdeb6daa4b38596064c1a26923994b1 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Thu, 21 May 2020 16:48:20 +0300 Subject: [PATCH] 68030 MMU fixes. Software fixed pipeline stage fixes and more compatible (prefetch) locked rmw and mmufixup fix. --- cpummu30.cpp | 40 +++++++++++++-------- gencpu.cpp | 12 ++++++- include/cpummu030.h | 16 +++++++-- newcpu.cpp | 87 +++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 129 insertions(+), 26 deletions(-) diff --git a/cpummu30.cpp b/cpummu30.cpp index 24eb66d8..96d14ae5 100644 --- a/cpummu30.cpp +++ b/cpummu30.cpp @@ -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) { diff --git a/gencpu.cpp b/gencpu.cpp index 502a5266..51809525 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -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; } diff --git a/include/cpummu030.h b/include/cpummu030.h index 85a6d532..13691ac1 100644 --- a/include/cpummu030.h +++ b/include/cpummu030.h @@ -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; } diff --git a/newcpu.cpp b/newcpu.cpp index 759edc5c..82a51c81 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -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) -- 2.47.3