From f285d5d081982b2db669f1df0773a61d0b5c91a4 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Thu, 27 Jul 2017 21:00:31 +0300 Subject: [PATCH] 68030 MMU + full prefetch pipeline, instruction and data cache emulation. --- cpummu30.cpp | 394 ++++++++++++-- gencpu.cpp | 153 ++++-- include/cpu_prefetch.h | 32 +- include/cpummu030.h | 346 ++++++++++-- include/newcpu.h | 30 +- newcpu.cpp | 1155 +++++++++++++++++++++++++++------------- od-win32/sysconfig.h | 1 + 7 files changed, 1557 insertions(+), 554 deletions(-) diff --git a/cpummu30.cpp b/cpummu30.cpp index e953e0cb..4e2fab6f 100644 --- a/cpummu30.cpp +++ b/cpummu30.cpp @@ -34,6 +34,7 @@ #include "options.h" #include "memory.h" #include "newcpu.h" +#include "debug.h" #include "cpummu030.h" #define MMU030_OP_DBG_MSG 0 @@ -68,6 +69,7 @@ uae_u16 mmu030_state[3]; uae_u32 mmu030_data_buffer; uae_u32 mmu030_disp_store[2]; uae_u32 mmu030_fmovem_store[2]; +int mmu030_cache_inhibit; struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS]; #if MMU_DPAGECACHE030 @@ -84,6 +86,8 @@ static struct mmufastcache030 atc_data_cache_write[MMUFASTCACHE_ENTRIES030]; /* for debugging messages */ char table_letter[4] = {'A','B','C','D'}; +static const uae_u32 mmu030_size[3] = { MMU030_SSW_SIZE_B, MMU030_SSW_SIZE_W, MMU030_SSW_SIZE_L }; + uae_u64 srp_030, crp_030; uae_u32 tt0_030, tt1_030, tc_030; uae_u16 mmusr_030; @@ -145,6 +149,7 @@ static struct { uae_u16 status; #if MMU_IPAGECACHE030 + int mmu030_cache_inhibit; #if MMU_DIRECT_ACCESS uae_u8 *mmu030_last_physical_address_real; #else @@ -311,29 +316,29 @@ bool mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra) #if MMU030_OP_DBG_MSG switch (preg) { case 0x10: - write_log(_T("PMOVE: %s TC %08X\n"), rw?"read":"write", - rw?tc_030:x_get_long(extra)); + write_log(_T("PMOVE: %s TC %08X\n"), rw ? _T("read"): _T("write"), + rw ? tc_030 : x_get_long(extra)); break; case 0x12: - write_log(_T("PMOVE: %s SRP %08X%08X\n"), rw?"read":"write", + write_log(_T("PMOVE: %s SRP %08X%08X\n"), rw ? _T("read") : _T("write"), rw?(uae_u32)(srp_030>>32)&0xFFFFFFFF:x_get_long(extra), rw?(uae_u32)srp_030&0xFFFFFFFF:x_get_long(extra+4)); break; case 0x13: - write_log(_T("PMOVE: %s CRP %08X%08X\n"), rw?"read":"write", + write_log(_T("PMOVE: %s CRP %08X%08X\n"), rw ? _T("read") : _T("write"), rw?(uae_u32)(crp_030>>32)&0xFFFFFFFF:x_get_long(extra), rw?(uae_u32)crp_030&0xFFFFFFFF:x_get_long(extra+4)); break; case 0x18: - write_log(_T("PMOVE: %s MMUSR %04X\n"), rw?"read":"write", + write_log(_T("PMOVE: %s MMUSR %04X\n"), rw ? _T("read") : _T("write"), rw?mmusr_030:x_get_word(extra)); break; case 0x02: - write_log(_T("PMOVE: %s TT0 %08X\n"), rw?"read":"write", + write_log(_T("PMOVE: %s TT0 %08X\n"), rw ? _T("read") : _T("write"), rw?tt0_030:x_get_long(extra)); break; case 0x03: - write_log(_T("PMOVE: %s TT1 %08X\n"), rw?"read":"write", + write_log(_T("PMOVE: %s TT1 %08X\n"), rw ? _T("read") : _T("write"), rw?tt1_030:x_get_long(extra)); break; default: @@ -647,13 +652,12 @@ TT_info mmu030_decode_tt(uae_u32 TT) { static int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write) { if (tt & TT_ENABLE) { /* transparent translation enabled */ - + /* Compare actual function code with function code base using mask */ if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) { - + /* Compare actual address with address base using mask */ if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) { - if (tt&TT_RWM) { /* r/w field disabled */ return TT_OK_MATCH; } else { @@ -672,13 +676,12 @@ static int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 f static int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc) { if ((tt & TT_ENABLE) && (tt & TT_RWM)) { /* transparent translation enabled */ - + /* Compare actual function code with function code base using mask */ if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) { - + /* Compare actual address with address base using mask */ if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) { - return TT_OK_MATCH; } } @@ -693,17 +696,15 @@ static int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write) { int tt0, tt1; - bool cache_inhibit = false; /* TODO: pass to memory access function */ - tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write); if (tt0&TT_OK_MATCH) { - cache_inhibit = (tt0_030&TT_CI) ? true : false; - } + if (tt0_030&TT_CI) + mmu030_cache_inhibit = 1; + } tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write); if (tt1&TT_OK_MATCH) { - if (!cache_inhibit) { - cache_inhibit = (tt1_030&TT_CI) ? true : false; - } + if (tt0_030&TT_CI) + mmu030_cache_inhibit = 1; } return (tt0|tt1); @@ -785,6 +786,8 @@ static int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc) static void mmu030_do_fake_prefetch(void) { + if (currprefs.cpu_compatible) + return; // fetch next opcode before MMU state switches. // There are programs that do following: // - enable MMU @@ -1700,9 +1703,29 @@ uae_u32 mmu030_ptest_table_search(uaecptr logical_addr, uae_u32 fc, bool write, #define ATC030_PHYS_CI 0x04000000 #define ATC030_PHYS_BE 0x08000000 -void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) { +void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) +{ + if (flags < 0) { + read = (regs.mmu_ssw & MMU030_SSW_RW) ? 1 : 0; + fc = regs.mmu_ssw & 7; + flags = regs.mmu_ssw & ~(MMU030_SSW_FC | MMU030_SSW_RC | MMU030_SSW_FB | MMU030_SSW_RB | MMU030_SSW_RW | 7); + } regs.mmu_fault_addr = addr; - regs.mmu_ssw = (fc & 1) ? MMU030_SSW_DF | (MMU030_SSW_DF << 1) : (MMU030_SSW_FB | MMU030_SSW_RB); + if (fc & 1) { + regs.mmu_ssw = MMU030_SSW_DF | (MMU030_SSW_DF << 1); + } else { + if (currprefs.cpu_compatible) { + 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) { + regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB; + } else { + write_log(_T("mmu030_page_fault without invalid prefetch!\n")); + } + } else { + regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB; + } + } regs.mmu_ssw |= read ? MMU030_SSW_RW : 0; regs.mmu_ssw |= flags; regs.mmu_ssw |= fc; @@ -1713,9 +1736,6 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) { addr, regs.mmu_ssw, read, (flags & MMU030_SSW_SIZE_B) ? 1 : (flags & MMU030_SSW_SIZE_W) ? 2 : 4, fc, regs.instruction_pc, (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val, mmu030_opcode & 0xffff); #endif - -// extern void activate_debugger(void); -// activate_debugger (); THROW(2); } @@ -1754,12 +1774,14 @@ static uaecptr mmu030_put_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) { l, physical_addr, page_index); #endif - if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) { + if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) { mmu030_page_fault(addr, false, MMU030_SSW_SIZE_B, fc); return 0; } - mmu030_add_data_write_cache(addr, physical_addr, fc); + mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit; + + mmu030_add_data_write_cache(addr, physical_addr, fc); return physical_addr + page_index; } @@ -1774,11 +1796,13 @@ static uaecptr mmu030_get_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) { physical_addr, page_index); #endif - if (mmu030.atc[l].physical.bus_error) { + if (mmu030.atc[l].physical.bus_error) { mmu030_page_fault(addr, true, size, fc); return 0; } + mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit; + mmu030_add_data_read_cache(addr, physical_addr, fc); return physical_addr + page_index; @@ -1800,6 +1824,7 @@ static uaecptr mmu030_get_i_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) { } #if MMU_IPAGECACHE030 + mmu030.mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit; #if MMU_DIRECT_ACCESS mmu030.mmu030_last_physical_address_real = get_real_address(physical_addr); #else @@ -1808,6 +1833,8 @@ static uaecptr mmu030_get_i_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) { mmu030.mmu030_last_logical_address = (addr & mmu030.translation.page.imask) | fc; #endif + mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit; + return physical_addr + page_index; } @@ -1818,8 +1845,8 @@ static uaecptr mmu030_put_atc_generic(uaecptr addr, int l, uae_u32 fc, int flags uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask; #if MMU030_ATC_DBG_MSG - write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n"), - l, physical_addr, page_index, val); + write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), + l, physical_addr, page_index); #endif if (mmu030.atc[l].physical.write_protect || mmu030.atc[l].physical.bus_error) { @@ -1898,9 +1925,16 @@ static int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) { * create a new ATC entry and then look up the physical address. */ +STATIC_INLINE void cacheablecheck(uaecptr addr) +{ + if (!ce_cachable[addr >> 16] && !mmu030_cache_inhibit) + mmu030_cache_inhibit = -1; // CIN active +} + void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) { #if MMU_DPAGECACHE030 uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc; uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1); @@ -1918,12 +1952,14 @@ void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc) } } } + cacheablecheck(addr); x_phys_put_long(addr,val); } void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) { #if MMU_DPAGECACHE030 uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc; uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1); @@ -1941,12 +1977,14 @@ void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc) } } } + cacheablecheck(addr); x_phys_put_word(addr,val); } void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) { #if MMU_DPAGECACHE030 uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc; uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1); @@ -1964,13 +2002,15 @@ void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) } } } + cacheablecheck(addr); x_phys_put_byte(addr,val); } uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) { #if MMU_DPAGECACHE030 uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc; uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1); @@ -1988,12 +2028,14 @@ uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) } } } + cacheablecheck(addr); return x_phys_get_long(addr); } uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) { #if MMU_DPAGECACHE030 uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc; uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1); @@ -2011,12 +2053,14 @@ uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc) } } } + cacheablecheck(addr); return x_phys_get_word(addr); } uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) { #if MMU_DPAGECACHE030 uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc; uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1); @@ -2034,6 +2078,7 @@ uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc) } } } + cacheablecheck(addr); return x_phys_get_byte(addr); } @@ -2046,13 +2091,15 @@ uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc) uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask]; return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); #else + mmu030_cache_inhibit = mmu030.mmu030_cache_inhibit; return x_phys_get_ilong(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask)); #endif } mmu030.mmu030_last_logical_address = 0xffffffff; #endif - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) { int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false); if (atc_line_num >= 0) { addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L); @@ -2072,13 +2119,15 @@ uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) { uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask]; return (p[0] << 8) | p[1]; #else + mmu030_cache_inhibit = mmu030.mmu030_cache_inhibit; return x_phys_get_iword(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask)); #endif } mmu030.mmu030_last_logical_address = 0xffffffff; #endif - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) { int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false); if (atc_line_num >= 0) { addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W); @@ -2093,7 +2142,8 @@ uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) { /* Not commonly used access function */ void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) { int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true); if (atc_line_num>=0) { addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags); @@ -2104,6 +2154,7 @@ void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int fla } } + cacheablecheck(addr); if (size == sz_byte) x_phys_put_byte(addr, val); else if (size == sz_word) @@ -2114,7 +2165,8 @@ void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int fla static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int flags) { - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) { + mmu030_cache_inhibit = 0; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) { int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true); if (atc_line_num>=0) { addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true); @@ -2125,6 +2177,7 @@ static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int f } } + cacheablecheck(addr); if (size == sz_byte) return x_phys_get_byte(addr); else if (size == sz_word) @@ -2134,11 +2187,13 @@ static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int f uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags) { + mmu030_cache_inhibit = 0; + if (flags & MMU030_SSW_RM) { return mmu030_get_generic_lrmw(addr, fc, size, flags); } - if (((fc != 7) || (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false))) && (mmu030.enabled)) { + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) { int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false); if (atc_line_num>=0) { addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false); @@ -2149,6 +2204,7 @@ uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags) } } + cacheablecheck(addr); if (size == sz_byte) return x_phys_get_byte(addr); else if (size == sz_word) @@ -2156,6 +2212,23 @@ uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags) return x_phys_get_long(addr); } +bool uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size) +{ + uae_u32 fc = regs.fc030; + if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,write)) && mmu030.enabled) { + uae_u32 flags = mmu030_size[size]; + int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write); + if (atc_line_num>=0) { + addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, write); + } else { + mmu030_table_search(addr, fc, write, 0); + atc_line_num = mmu030_logical_is_in_atc(addr, fc, write); + addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false); + } + } + cacheablecheck(addr); + return mmu030_cache_inhibit == 0; +} /* Locked RMW is rarely used */ uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size) @@ -2335,27 +2408,27 @@ uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write) static uae_u32 get_dcache_byte(uaecptr addr) { - return read_dcache030(addr, 0); + return read_dcache030(addr, 0, (regs.s ? 4 : 0) | 1); } static uae_u32 get_dcache_word(uaecptr addr) { - return read_dcache030(addr, 1); + return read_dcache030(addr, 1, (regs.s ? 4 : 0) | 1); } static uae_u32 get_dcache_long(uaecptr addr) { - return read_dcache030(addr, 2); + return read_dcache030(addr, 2, (regs.s ? 4 : 0) | 1); } static void put_dcache_byte(uaecptr addr, uae_u32 v) { - write_dcache030(addr, v, 0); + write_dcache030(addr, v, 0, (regs.s ? 4 : 0) | 1); } static void put_dcache_word(uaecptr addr, uae_u32 v) { - write_dcache030(addr, v, 1); + write_dcache030(addr, v, 1, (regs.s ? 4 : 0) | 1); } static void put_dcache_long(uaecptr addr, uae_u32 v) { - write_dcache030(addr, v, 2); + write_dcache030(addr, v, 2, (regs.s ? 4 : 0) | 1); } /* MMU Reset */ @@ -2385,15 +2458,15 @@ void mmu030_set_funcs(void) { if (currprefs.mmu_model != 68030) return; - if (currprefs.cpu_memory_cycle_exact || currprefs.cpu_compatible) { - x_phys_get_iword = get_word_icache030; - x_phys_get_ilong = get_long_icache030; - x_phys_get_byte = get_dcache_byte; - x_phys_get_word = get_dcache_word; - x_phys_get_long = get_dcache_long; - x_phys_put_byte = put_dcache_byte; - x_phys_put_word = put_dcache_word; - x_phys_put_long = put_dcache_long; + if (currprefs.cpu_memory_cycle_exact) { + x_phys_get_iword = mem_access_delay_wordi_read_ce020; + x_phys_get_ilong = mem_access_delay_longi_read_ce020; + x_phys_get_byte = mem_access_delay_byte_read_ce020; + x_phys_get_word = mem_access_delay_word_read_ce020; + x_phys_get_long = mem_access_delay_long_read_ce020; + x_phys_put_byte = mem_access_delay_byte_write_ce020; + x_phys_put_word = mem_access_delay_word_write_ce020; + x_phys_put_long = mem_access_delay_long_write_ce020; } else { x_phys_get_iword = phys_get_word; x_phys_get_ilong = phys_get_long; @@ -2422,8 +2495,11 @@ void m68k_do_rte_mmu030 (uaecptr a7) else get_word_mmu030(a7 + 32 - 2); + // Internal register, misc flags + uae_u32 ps = get_long_mmu030c(a7 + 0x28); // Internal register, our opcode storage area - mmu030_opcode = get_long_mmu030 (a7 + 0x14); + uae_u32 oc = get_long_mmu030c (a7 + 0x14); + mmu030_opcode = (ps & 0x80000000) ? -1 : (oc & 0xffff); // Misc state data mmu030_state[0] = get_word_mmu030 (a7 + 0x30); mmu030_state[1] = get_word_mmu030 (a7 + 0x32); @@ -2572,3 +2648,207 @@ uae_u32 REGPARAM2 get_disp_ea_020_mmu030 (uae_u32 base, int idx) return v; } + +// cache + +void m68k_do_rts_mmu030c (void) +{ + m68k_setpc (get_long_mmu030c_state (m68k_areg (regs, 7))); + m68k_areg (regs, 7) += 4; +} + +void m68k_do_bsr_mmu030c (uaecptr oldpc, uae_s32 offset) +{ + put_long_mmu030c_state (m68k_areg (regs, 7) - 4, oldpc); + m68k_areg (regs, 7) -= 4; + m68k_incpci (offset); +} + + +uae_u32 REGPARAM2 get_disp_ea_020_mmu030c (uae_u32 base, int idx) +{ + uae_u16 dp; + int reg; + uae_u32 v; + int oldidx; + int pcadd = 0; + + // we need to do this hack here because in worst case we don't have enough + // stack frame space to store two very large 020 addressing mode access state + // + whatever the instruction itself does. + + if (mmu030_state[1] & (1 << idx)) { + m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2); + return mmu030_disp_store[idx]; + } + + oldidx = mmu030_idx; + dp = next_iword_mmu030c_state (); + pcadd += 1; + + reg = (dp >> 12) & 15; + uae_s32 regd = regs.regs[reg]; + if ((dp & 0x800) == 0) + regd = (uae_s32)(uae_s16)regd; + regd <<= (dp >> 9) & 3; + if (dp & 0x100) { + uae_s32 outer = 0; + if (dp & 0x80) + base = 0; + if (dp & 0x40) + regd = 0; + + if ((dp & 0x30) == 0x20) { + base += (uae_s32)(uae_s16) next_iword_mmu030c_state (); + pcadd += 1; + } + if ((dp & 0x30) == 0x30) { + base += next_ilong_mmu030c_state (); + pcadd += 2; + } + + if ((dp & 0x3) == 0x2) { + outer = (uae_s32)(uae_s16) next_iword_mmu030c_state (); + pcadd += 1; + } + if ((dp & 0x3) == 0x3) { + outer = next_ilong_mmu030c_state (); + pcadd += 2; + } + + if ((dp & 0x4) == 0) { + base += regd; + } + if (dp & 0x3) { + base = get_long_mmu030c_state (base); + } + if (dp & 0x4) { + base += regd; + } + v = base + outer; + } else { + v = base + (uae_s32)((uae_s8)dp) + regd; + } + + mmu030_state[1] |= 1 << idx; + mmu030_state[2] |= pcadd << (idx * 4); + mmu030_disp_store[idx] = v; + mmu030_idx = oldidx; + mmu030_ad[mmu030_idx].done = false; + + return v; +} + +void m68k_do_rte_mmu030c (uaecptr a7) +{ + // Restore access error exception state + + uae_u16 format = get_word_mmu030c (a7 + 6); + uae_u16 frame = format >> 12; + uae_u16 ssw = get_word_mmu030c (a7 + 10); + uae_u16 sr = get_word_mmu030c (a7); + uae_u32 pc = get_long_mmu030c (a7 + 2); + + // Fetch last word, real CPU does it to allow OS bus handler to map + // the page if frame crosses pages and following page is not resident. + if (frame == 0xb) + get_word_mmu030c(a7 + 92 - 2); + else + get_word_mmu030c(a7 + 32 - 2); + + // Internal register, misc flags + uae_u32 ps = get_long_mmu030c(a7 + 0x28); + // Internal register, our opcode storage area + uae_u32 oc = get_long_mmu030c (a7 + 0x14); + mmu030_opcode = (ps & 0x80000000) ? -1 : (oc & 0xffff); + // Misc state data + mmu030_state[0] = get_word_mmu030c (a7 + 0x30); + mmu030_state[1] = get_word_mmu030c (a7 + 0x32); + mmu030_state[2] = get_word_mmu030c (a7 + 0x34); + mmu030_disp_store[0] = get_long_mmu030c (a7 + 0x1c); + mmu030_disp_store[1] = get_long_mmu030c (a7 + 0x1c + 4); + if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) { + mmu030_fmovem_store[0] = get_long_mmu030c (a7 + 0x5c - (7 + 1) * 4); + mmu030_fmovem_store[1] = get_long_mmu030c (a7 + 0x5c - (8 + 1) * 4); + } + // Rerun "mmu030_opcode" using restored state. + mmu030_retry = true; + + if (frame == 0xb) { + uae_u16 idxsize = get_word_mmu030c(a7 + 0x36); + for (int i = 0; i < idxsize + 1; i++) { + mmu030_ad[i].done = i < idxsize; + mmu030_ad[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4); + } + mmu030_ad[idxsize + 1].done = false; + // 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 + if (ssw & MMU030_SSW_RM) { + // Read-Modify-Write: whole instruction is considered done + write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc); + mmu030_retry = false; + } else if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + // if movem, skip next move + mmu030_data_buffer = get_long_mmu030c(a7 + 0x2c); + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else { + mmu030_ad[idxsize].done = true; + if (ssw & MMU030_SSW_RW) { + // Read and no DF: use value in data input buffer + mmu030_data_buffer = get_long_mmu030c(a7 + 0x2c); + mmu030_ad[idxsize].val = mmu030_data_buffer; + } + } + } + + regs.prefetch020_valid[0] = (ps & 1) ? 1 : 0; + regs.prefetch020_valid[1] = (ps & 2) ? 1 : 0; + regs.prefetch020_valid[2] = (ps & 4) ? 1 : 0; + regs.pipeline_r8[0] = (ps >> 8) & 7; + regs.pipeline_r8[1] = (ps >> 11) & 7; + regs.pipeline_pos = (ps >> 16) & 15; + regs.pipeline_stop = ((ps >> 20) & 15) == 15 ? -1 : (ps >> 20) & 15; + + uae_u32 stagesbc = get_long_mmu030c(a7 + 0x0c); + regs.prefetch020[2] = stagesbc; + regs.prefetch020[1] = stagesbc >> 16; + regs.prefetch020[0] = oc >> 16; + + if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) { + regs.prefetch020_valid[2] = 1; + write_log (_T("Software fixed stage B! opcode = %04x\n"), regs.prefetch020[2]); + } + if ((ssw & MMU030_SSW_FC) && !(ssw & MMU030_SSW_RC)) { + regs.prefetch020_valid[1] = 1; + write_log (_T("Software fixed stage C! opcode = %04x\n"), regs.prefetch020[1]); + } + + m68k_areg (regs, 7) += 92; + + regs.sr = sr; + MakeFromSR_T0(); + if (pc & 1) { + exception3i (0x4E73, pc); + return; + } + m68k_setpci (pc); + + if (!(ssw & (MMU030_SSW_DF << 1))) { + if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) { + // Prefetch was software fixed, continue pipeline refill + fill_prefetch_030_ntx_continue(); + } else if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1]) { + // Finished? + fill_prefetch_030_ntx_continue(); + } else if (mmu030_opcode == -1) { + // Previous branch instruction finished successfully but its pipeline refill + // step caused the exception, retry the refill, do not retry branch instruction. + fill_prefetch_030_ntx(); + } + } + + } else { + m68k_areg (regs, 7) += 32; + } +} diff --git a/gencpu.cpp b/gencpu.cpp index 19f8e315..64fc53c8 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -184,11 +184,6 @@ static void fpulimit (void) n_braces = 0; } -static void cpulimit (void) -{ - printf ("#ifndef CPUEMU_68000_ONLY\n"); -} - static int s_count_read, s_count_write, s_count_cycles, s_count_ncycles; static void push_ins_cnt(void) @@ -1654,21 +1649,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char if (getv == 1) { start_brace (); - if (using_ce020 || using_prefetch_020) { - switch (size) { - case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = %s (%sa);\n", name, srcb, name); count_read++; break; - case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = %s (%sa);\n", name, srcw, name); count_read++; break; - case sz_long: insn_n_cycles += 8; printf ("\tuae_s32 %s = %s (%sa);\n", name, srcl, name); count_read += 2; break; - default: term (); - } - } else if (using_ce || using_prefetch) { - switch (size) { - case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = %s (%sa);\n", name, srcb, name); count_read++; break; - case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = %s (%sa);\n", name, srcw, name); count_read++; break; - case sz_long: insn_n_cycles += 8; printf ("\tuae_s32 %s = %s (%sa) << 16; %s |= %s (%sa + 2);\n", name, srcw, name, name, srcw, name); count_read += 2; break; - default: term (); - } - } else if (using_mmu) { + if (using_mmu) { if (flags & GF_FC) { switch (size) { case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = sfc%s_get_byte (%sa);\n", name, mmu_postfix, name); break; @@ -1684,6 +1665,20 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char default: term (); } } + } else if (using_ce020 || using_prefetch_020) { + switch (size) { + case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = %s (%sa);\n", name, srcb, name); count_read++; break; + case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = %s (%sa);\n", name, srcw, name); count_read++; break; + case sz_long: insn_n_cycles += 8; printf ("\tuae_s32 %s = %s (%sa);\n", name, srcl, name); count_read += 2; break; + default: term (); + } + } else if (using_ce || using_prefetch) { + switch (size) { + case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = %s (%sa);\n", name, srcb, name); count_read++; break; + case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = %s (%sa);\n", name, srcw, name); count_read++; break; + case sz_long: insn_n_cycles += 8; printf ("\tuae_s32 %s = %s (%sa) << 16; %s |= %s (%sa + 2);\n", name, srcw, name, name, srcw, name); count_read += 2; break; + default: term (); + } } else { switch (size) { case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = %s (%sa);\n", name, srcb, name); count_read++; break; @@ -1861,7 +1856,37 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz case PC8r: if (!(flags & GF_NOFAULTPC)) gen_set_fault_pc (); - if (using_ce020 || using_prefetch_020) { + if (using_mmu) { + switch (size) { + case sz_byte: + insn_n_cycles += 4; + if (flags & GF_FC) + printf ("\tdfc%s_put_byte (%sa, %s);\n", mmu_postfix, to, from); + else + printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstblrmw : (candormw ? dstbrmw : dstb), to, from); + break; + case sz_word: + insn_n_cycles += 4; + if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) + term (); + if (flags & GF_FC) + printf ("\tdfc%s_put_word (%sa, %s);\n", mmu_postfix, to, from); + else + printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstwlrmw : (candormw ? dstwrmw : dstw), to, from); + break; + case sz_long: + insn_n_cycles += 8; + if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) + term (); + if (flags & GF_FC) + printf ("\tdfc%s_put_long (%sa, %s);\n", mmu_postfix, to, from); + else + printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstllrmw : (candormw ? dstlrmw : dstl), to, from); + break; + default: + term (); + } + } else if (using_ce020 || using_prefetch_020) { switch (size) { case sz_byte: printf ("\t%s (%sa, %s);\n", dstb, to, from); @@ -1913,36 +1938,6 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz default: term (); } - } else if (using_mmu) { - switch (size) { - case sz_byte: - insn_n_cycles += 4; - if (flags & GF_FC) - printf ("\tdfc%s_put_byte (%sa, %s);\n", mmu_postfix, to, from); - else - printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstblrmw : (candormw ? dstbrmw : dstb), to, from); - break; - case sz_word: - insn_n_cycles += 4; - if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) - term (); - if (flags & GF_FC) - printf ("\tdfc%s_put_word (%sa, %s);\n", mmu_postfix, to, from); - else - printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstwlrmw : (candormw ? dstwrmw : dstw), to, from); - break; - case sz_long: - insn_n_cycles += 8; - if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) - term (); - if (flags & GF_FC) - printf ("\tdfc%s_put_long (%sa, %s);\n", mmu_postfix, to, from); - else - printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstllrmw : (candormw ? dstlrmw : dstl), to, from); - break; - default: - term (); - } } else if (using_prefetch) { switch (size) { case sz_byte: @@ -2786,7 +2781,35 @@ static void resetvars (void) if (using_indirect > 0) { // tracer getpc = "m68k_getpci ()"; - if (!using_ce020 && !using_prefetch_020 && !using_ce) { + if (using_mmu == 68030) { + // 68030 cache MMU + disp020 = "get_disp_ea_020_mmu030c"; + prefetch_long = "get_ilong_mmu030c_state"; + prefetch_word = "get_iword_mmu030c_state"; + prefetch_opcode = "get_iword_mmu030c_opcode_state"; + nextw = "next_iword_mmu030c_state"; + nextl = "next_ilong_mmu030c_state"; + srcli = "get_ilong_mmu030c_state"; + srcwi = "get_iword_mmu030c_state"; + srcbi = "get_ibyte_mmu030c_state"; + srcl = "get_long_mmu030c_state"; + dstl = "put_long_mmu030c_state"; + srcw = "get_word_mmu030c_state"; + dstw = "put_word_mmu030c_state"; + srcb = "get_byte_mmu030c_state"; + dstb = "put_byte_mmu030c_state"; + srcblrmw = "get_lrmw_byte_mmu030c_state"; + srcwlrmw = "get_lrmw_word_mmu030c_state"; + srcllrmw = "get_lrmw_long_mmu030c_state"; + dstblrmw = "put_lrmw_byte_mmu030c_state"; + dstwlrmw = "put_lrmw_word_mmu030c_state"; + dstllrmw = "put_lrmw_long_mmu030c_state"; + srcld = "get_long_mmu030c"; + srcwd = "get_word_mmu030c"; + dstld = "put_long_mmu030c"; + dstwd = "put_word_mmu030c"; + getpc = "m68k_getpci ()"; + } else if (!using_ce020 && !using_prefetch_020 && !using_ce) { // generic + indirect disp020 = "x_get_disp_ea_020"; prefetch_long = "get_iilong_jit"; @@ -3890,8 +3913,13 @@ static void gen_opcode (unsigned int opcode) if (cpu_level == 2 || cpu_level == 3) { // 68020/68030 only printf ("\t\telse if (frame == 0x9) { m68k_areg (regs, 7) += offset + 12; break; }\n"); if (using_mmu == 68030) { - printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030 (a); break; }\n"); - printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030 (a); break; }\n"); + if (using_prefetch_020) { + printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030c (a); break; }\n"); + printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr); + } else { + printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030 (a); break; }\n"); + printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030 (a); break; }\n"); + } } else { printf ("\t\telse if (frame == 0xa) { m68k_areg (regs, 7) += offset + 24; break; }\n"); printf ("\t\telse if (frame == 0xb) { m68k_areg (regs, 7) += offset + 84; break; }\n"); @@ -5483,7 +5511,7 @@ static void generate_includes (FILE * f, int id) fprintf (f, "#include \"cputbl.h\"\n"); if (id == 31 || id == 33) fprintf (f, "#include \"cpummu.h\"\n"); - else if (id == 32) + else if (id == 32 || id == 34) fprintf (f, "#include \"cpummu030.h\"\n"); fprintf (f, "#define CPUFUNC(x) x##_ff\n" @@ -5850,7 +5878,10 @@ static void generate_cpu (int id, int mode) } postfix = id; - if (id == 0 || id == 11 || id == 13 || id == 20 || id == 21 || id == 22 || id == 23 || id == 24 || id == 31 || id == 32 || id == 33 || id == 40 || id == 50) { + if (id == 0 || id == 11 || id == 13 || + id == 20 || id == 21 || id == 22 || id == 23 || id == 24 || + id == 31 || id == 32 || id == 33 || id == 34 || + id == 40 || id == 50) { if (generate_stbl) fprintf (stblfile, "#ifdef CPUEMU_%d%s\n", postfix, extraup); postfix2 = postfix; @@ -5957,6 +5988,14 @@ static void generate_cpu (int id, int mode) read_counts (); for (rp = 0; rp < nr_cpuop_funcs; rp++) opcode_next_clev[rp] = cpu_level; + } else if (id == 34) { // 34 = 68030 MMU + caches + mmu_postfix = "030c"; + cpu_level = 3; + using_prefetch_020 = 2; + using_mmu = 68030; + read_counts (); + for (rp = 0; rp < nr_cpuop_funcs; rp++) + opcode_next_clev[rp] = cpu_level; } else if (id < 6) { cpu_level = 5 - (id - 0); // "generic" cpu_generic = true; @@ -6021,7 +6060,7 @@ int main(int argc, char *argv[]) generate_includes (stblfile, 0); for (i = 0; i <= 55; i++) { - if ((i >= 6 && i < 11) || (i > 14 && i < 20) || (i > 25 && i < 31) || (i > 33 && i < 40)) + if ((i >= 6 && i < 11) || (i > 14 && i < 20) || (i > 25 && i < 31) || (i > 34 && i < 40)) continue; generate_stbl = 1; generate_cpu (i, 0); diff --git a/include/cpu_prefetch.h b/include/cpu_prefetch.h index 4db7b148..da2bf1f4 100644 --- a/include/cpu_prefetch.h +++ b/include/cpu_prefetch.h @@ -101,14 +101,6 @@ STATIC_INLINE void do_head_cycles_ce020 (int h) } #endif -void mem_access_delay_long_write_ce020 (uaecptr addr, uae_u32 v); -void mem_access_delay_word_write_ce020 (uaecptr addr, uae_u32 v); -void mem_access_delay_byte_write_ce020 (uaecptr addr, uae_u32 v); -uae_u32 mem_access_delay_byte_read_ce020 (uaecptr addr); -uae_u32 mem_access_delay_word_read_ce020 (uaecptr addr); -uae_u32 mem_access_delay_longi_read_ce020 (uaecptr addr); -uae_u32 mem_access_delay_long_read_ce020 (uaecptr addr); - STATIC_INLINE uae_u32 get_long_ce020 (uaecptr addr) { return mem_access_delay_long_read_ce020 (addr); @@ -185,27 +177,27 @@ extern uae_u32 get_word_030_prefetch(int); STATIC_INLINE void put_long_030(uaecptr addr, uae_u32 v) { - write_dcache030(addr, v, 2); + write_dcache030(addr, v, 2, (regs.s ? 4 : 0) | 1); } STATIC_INLINE void put_word_030(uaecptr addr, uae_u32 v) { - write_dcache030(addr, v, 1); + write_dcache030(addr, v, 1, (regs.s ? 4 : 0) | 1); } STATIC_INLINE void put_byte_030(uaecptr addr, uae_u32 v) { - write_dcache030(addr, v, 0); + write_dcache030(addr, v, 0, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_long_030(uaecptr addr) { - return read_dcache030(addr, 2); + return read_dcache030(addr, 2, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_word_030(uaecptr addr) { - return read_dcache030(addr, 1); + return read_dcache030(addr, 1, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_byte_030(uaecptr addr) { - return read_dcache030(addr, 0); + return read_dcache030(addr, 0, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_long_030_prefetch(int o) @@ -251,27 +243,27 @@ extern uae_u32 get_word_ce030_prefetch_opcode(int); STATIC_INLINE void put_long_ce030 (uaecptr addr, uae_u32 v) { - write_dcache030 (addr, v, 2); + write_dcache030 (addr, v, 2, (regs.s ? 4 : 0) | 1); } STATIC_INLINE void put_word_ce030 (uaecptr addr, uae_u32 v) { - write_dcache030 (addr, v, 1); + write_dcache030 (addr, v, 1, (regs.s ? 4 : 0) | 1); } STATIC_INLINE void put_byte_ce030 (uaecptr addr, uae_u32 v) { - write_dcache030 (addr, v, 0); + write_dcache030 (addr, v, 0, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_long_ce030 (uaecptr addr) { - return read_dcache030 (addr, 2); + return read_dcache030 (addr, 2, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_word_ce030 (uaecptr addr) { - return read_dcache030 (addr, 1); + return read_dcache030 (addr, 1, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_byte_ce030 (uaecptr addr) { - return read_dcache030 (addr, 0); + return read_dcache030 (addr, 0, (regs.s ? 4 : 0) | 1); } STATIC_INLINE uae_u32 get_long_ce030_prefetch (int o) diff --git a/include/cpummu030.h b/include/cpummu030.h index 7cb4d04f..9bd41f4c 100644 --- a/include/cpummu030.h +++ b/include/cpummu030.h @@ -23,6 +23,7 @@ extern uae_u16 mmu030_state[3]; extern uae_u32 mmu030_data_buffer; extern uae_u32 mmu030_disp_store[2]; extern uae_u32 mmu030_fmovem_store[2]; +extern int mmu030_cache_inhibit; #define MMU030_STATEFLAG1_FMOVEM 0x2000 #define MMU030_STATEFLAG1_MOVEM1 0x4000 @@ -37,7 +38,6 @@ struct mmu030_access }; extern struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS]; -uae_u32 REGPARAM3 get_disp_ea_020_mmu030 (uae_u32 base, int idx) REGPARAM; void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc); bool mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra); @@ -117,7 +117,7 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_long(uaecptr addr) return mmu030_get_long_unaligned(addr, fc, 0); return mmu030_get_long(addr, fc); } -static ALWAYS_INLINE uae_u16 uae_mmu030_get_word(uaecptr addr) +static ALWAYS_INLINE uae_u32 uae_mmu030_get_word(uaecptr addr) { uae_u32 fc = (regs.s ? 4 : 0) | 1; @@ -125,7 +125,7 @@ static ALWAYS_INLINE uae_u16 uae_mmu030_get_word(uaecptr addr) return mmu030_get_word_unaligned(addr, fc, 0); return mmu030_get_word(addr, fc); } -static ALWAYS_INLINE uae_u8 uae_mmu030_get_byte(uaecptr addr) +static ALWAYS_INLINE uae_u32 uae_mmu030_get_byte(uaecptr addr) { uae_u32 fc = (regs.s ? 4 : 0) | 1; @@ -140,7 +140,7 @@ static ALWAYS_INLINE void uae_mmu030_put_long(uaecptr addr, uae_u32 val) else mmu030_put_long(addr, val, fc); } -static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u16 val) +static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u32 val) { uae_u32 fc = (regs.s ? 4 : 0) | 1; @@ -149,13 +149,100 @@ static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u16 val) else mmu030_put_word(addr, val, fc); } -static ALWAYS_INLINE void uae_mmu030_put_byte(uaecptr addr, uae_u8 val) +static ALWAYS_INLINE void uae_mmu030_put_byte(uaecptr addr, uae_u32 val) { uae_u32 fc = (regs.s ? 4 : 0) | 1; mmu030_put_byte(addr, val, fc); } +static ALWAYS_INLINE uae_u32 uae_mmu030_get_ilong_fc(uaecptr addr) +{ + if (unlikely(is_unaligned(addr, 4))) + return mmu030_get_ilong_unaligned(addr, regs.fc030, 0); + return mmu030_get_ilong(addr, regs.fc030); +} +static ALWAYS_INLINE uae_u16 uae_mmu030_get_iword_fc(uaecptr addr) +{ + return mmu030_get_iword(addr, regs.fc030); +} +static ALWAYS_INLINE uae_u16 uae_mmu030_get_ibyte_fc(uaecptr addr) +{ + return mmu030_get_byte(addr, regs.fc030); +} +static ALWAYS_INLINE uae_u32 uae_mmu030_get_long_fc(uaecptr addr) +{ + if (unlikely(is_unaligned(addr, 4))) + return mmu030_get_long_unaligned(addr, regs.fc030, 0); + return mmu030_get_long(addr, regs.fc030); +} +static ALWAYS_INLINE uae_u32 uae_mmu030_get_word_fc(uaecptr addr) +{ + if (unlikely(is_unaligned(addr, 2))) + return mmu030_get_word_unaligned(addr, regs.fc030, 0); + return mmu030_get_word(addr, regs.fc030); +} +static ALWAYS_INLINE uae_u32 uae_mmu030_get_byte_fc(uaecptr addr) +{ + return mmu030_get_byte(addr, regs.fc030); +} +static ALWAYS_INLINE void uae_mmu030_put_long_fc(uaecptr addr, uae_u32 val) +{ + if (unlikely(is_unaligned(addr, 4))) + mmu030_put_long_unaligned(addr, val, regs.fc030, 0); + else + mmu030_put_long(addr, val, regs.fc030); +} +static ALWAYS_INLINE void uae_mmu030_put_word_fc(uaecptr addr, uae_u32 val) +{ + if (unlikely(is_unaligned(addr, 2))) + mmu030_put_word_unaligned(addr, val, regs.fc030, 0); + else + mmu030_put_word(addr, val, regs.fc030); +} +static ALWAYS_INLINE void uae_mmu030_put_byte_fc(uaecptr addr, uae_u32 val) +{ + mmu030_put_byte(addr, val, regs.fc030); +} +bool uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size); + +#define ACCESS_CHECK_PUT \ + if (!mmu030_ad[mmu030_idx].done) { \ + mmu030_ad[mmu030_idx].val = v; \ + } else if (mmu030_ad[mmu030_idx].done) { \ + mmu030_idx++; \ + return; \ + } + +#define ACCESS_CHECK_GET \ + if (mmu030_ad[mmu030_idx].done) { \ + v = mmu030_ad[mmu030_idx].val; \ + mmu030_idx++; \ + return v; \ + } + +#define ACCESS_CHECK_GET_PC(pc) \ + if (mmu030_ad[mmu030_idx].done) { \ + v = mmu030_ad[mmu030_idx].val; \ + mmu030_idx++; \ + m68k_incpci (pc); \ + return v; \ + } + +#define ACCESS_EXIT_PUT \ + mmu030_ad[mmu030_idx].done = true; \ + mmu030_idx++; \ + mmu030_ad[mmu030_idx].done = false; + +#define ACCESS_EXIT_GET \ + mmu030_ad[mmu030_idx].val = v; \ + mmu030_ad[mmu030_idx].done = true; \ + mmu030_idx++; \ + mmu030_ad[mmu030_idx].done = false; + +// non-cache + + static ALWAYS_INLINE uae_u32 sfc030_get_long(uaecptr addr) { uae_u32 fc = regs.sfc; @@ -220,39 +307,7 @@ static ALWAYS_INLINE void dfc030_put_byte(uaecptr addr, uae_u8 val) mmu030_put_byte(addr, val, fc); } -#define ACCESS_CHECK_PUT \ - if (!mmu030_ad[mmu030_idx].done) { \ - mmu030_ad[mmu030_idx].val = v; \ - } else if (mmu030_ad[mmu030_idx].done) { \ - mmu030_idx++; \ - return; \ - } - -#define ACCESS_CHECK_GET \ - if (mmu030_ad[mmu030_idx].done) { \ - v = mmu030_ad[mmu030_idx].val; \ - mmu030_idx++; \ - return v; \ - } - -#define ACCESS_CHECK_GET_PC(pc) \ - if (mmu030_ad[mmu030_idx].done) { \ - v = mmu030_ad[mmu030_idx].val; \ - mmu030_idx++; \ - m68k_incpci (pc); \ - return v; \ - } - -#define ACCESS_EXIT_PUT \ - mmu030_ad[mmu030_idx].done = true; \ - mmu030_idx++; \ - mmu030_ad[mmu030_idx].done = false; - -#define ACCESS_EXIT_GET \ - mmu030_ad[mmu030_idx].val = v; \ - mmu030_ad[mmu030_idx].done = true; \ - mmu030_idx++; \ - mmu030_ad[mmu030_idx].done = false; +uae_u32 REGPARAM3 get_disp_ea_020_mmu030 (uae_u32 base, int idx) REGPARAM; STATIC_INLINE void put_byte_mmu030_state (uaecptr addr, uae_u32 v) { @@ -405,7 +460,6 @@ STATIC_INLINE void put_byte_mmu030 (uaecptr addr, uae_u32 v) { uae_mmu030_put_byte (addr, v); } - STATIC_INLINE void put_word_mmu030 (uaecptr addr, uae_u32 v) { uae_mmu030_put_word (addr, v); @@ -452,4 +506,218 @@ extern void m68k_do_rte_mmu030 (uaecptr a7); extern void flush_mmu030 (uaecptr, int); extern void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset); +// cache + +static ALWAYS_INLINE uae_u32 sfc030c_get_long(uaecptr addr) +{ +#if MMUDEBUG > 2 + write_log(_T("sfc030_get_long: FC = %i\n"),fc); +#endif + return read_dcache030(addr, 2, regs.sfc); +} + +static ALWAYS_INLINE uae_u16 sfc030c_get_word(uaecptr addr) +{ +#if MMUDEBUG > 2 + write_log(_T("sfc030_get_word: FC = %i\n"),fc); +#endif + return read_dcache030(addr, 1, regs.sfc); +} + +static ALWAYS_INLINE uae_u8 sfc030c_get_byte(uaecptr addr) +{ +#if MMUDEBUG > 2 + write_log(_T("sfc030_get_byte: FC = %i\n"),fc); +#endif + return read_dcache030(addr, 0, regs.sfc); +} + +static ALWAYS_INLINE void dfc030c_put_long(uaecptr addr, uae_u32 val) +{ +#if MMUDEBUG > 2 + write_log(_T("dfc030_put_long: %08X = %08X FC = %i\n"), addr, val, fc); +#endif + write_dcache030(addr, val, 2, regs.dfc); +} + +static ALWAYS_INLINE void dfc030c_put_word(uaecptr addr, uae_u16 val) +{ +#if MMUDEBUG > 2 + write_log(_T("dfc030_put_word: %08X = %04X FC = %i\n"), addr, val, fc); +#endif + write_dcache030(addr, val, 1, regs.dfc); +} + +static ALWAYS_INLINE void dfc030c_put_byte(uaecptr addr, uae_u8 val) +{ +#if MMUDEBUG > 2 + write_log(_T("dfc030_put_byte: %08X = %02X FC = %i\n"), addr, val, fc); +#endif + write_dcache030(addr, val, 0, regs.dfc); +} + +uae_u32 REGPARAM3 get_disp_ea_020_mmu030c (uae_u32 base, int idx) REGPARAM; + +STATIC_INLINE void put_byte_mmu030c_state (uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + write_dcache030_mmu(addr, v, 0); + ACCESS_EXIT_PUT +} +STATIC_INLINE void put_lrmw_byte_mmu030c_state (uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + write_dcache030_lrmw_mmu(addr, v, 0); + ACCESS_EXIT_PUT +} +STATIC_INLINE void put_word_mmu030c_state (uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + write_dcache030_mmu(addr, v, 1); + ACCESS_EXIT_PUT +} +STATIC_INLINE void put_lrmw_word_mmu030c_state (uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + write_dcache030_lrmw_mmu(addr, v, 1); + ACCESS_EXIT_PUT +} +STATIC_INLINE void put_long_mmu030c_state (uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + write_dcache030_mmu(addr, v, 2); + ACCESS_EXIT_PUT +} +STATIC_INLINE void put_lrmw_long_mmu030c_state (uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + write_dcache030_lrmw_mmu(addr, v, 2); + ACCESS_EXIT_PUT +} + +STATIC_INLINE uae_u32 get_byte_mmu030c_state (uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = read_dcache030_mmu(addr, 0); + ACCESS_EXIT_GET + return v; +} +STATIC_INLINE uae_u32 get_lrmw_byte_mmu030c_state (uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = read_dcache030_lrmw_mmu(addr, 0); + ACCESS_EXIT_GET + return v; +} + +STATIC_INLINE uae_u32 get_word_mmu030c_state (uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = read_dcache030_mmu(addr, 1); + ACCESS_EXIT_GET + return v; +} +STATIC_INLINE uae_u32 get_lrmw_word_mmu030c_state (uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = read_dcache030_lrmw_mmu(addr, 1); + ACCESS_EXIT_GET + return v; +} +STATIC_INLINE uae_u32 get_long_mmu030c_state (uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = read_dcache030_mmu(addr, 2); + ACCESS_EXIT_GET + return v; +} +STATIC_INLINE uae_u32 get_lrmw_long_mmu030c_state (uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = read_dcache030_lrmw_mmu(addr, 2); + ACCESS_EXIT_GET + return v; +} + +STATIC_INLINE uae_u32 get_ibyte_mmu030c_state (int o) +{ + uae_u32 v; + uae_u32 addr = m68k_getpci () + o; + ACCESS_CHECK_GET + v = get_word_icache030(addr); + ACCESS_EXIT_GET + return v; +} +uae_u32 get_word_030_prefetch(int o); +STATIC_INLINE uae_u32 get_iword_mmu030c_state (int o) +{ + uae_u32 v; + ACCESS_CHECK_GET; + v = get_word_030_prefetch(o); + ACCESS_EXIT_GET + return v; +} +uae_u32 get_long_030_prefetch(int o); +STATIC_INLINE uae_u32 get_ilong_mmu030c_state (int o) +{ + uae_u32 v; + ACCESS_CHECK_GET; + v = get_word_030_prefetch(o + 0) << 16; + v |= get_word_030_prefetch(o + 2); + ACCESS_EXIT_GET + return v; +} +STATIC_INLINE uae_u32 get_iword_mmu030c_opcode_state(int o) +{ + return get_iword_mmu030c_state(o); +} + + +STATIC_INLINE uae_u32 next_iword_mmu030c_state (void) +{ + uae_u32 v; + ACCESS_CHECK_GET_PC(2); + v = get_word_030_prefetch(0); + m68k_incpci(2); + ACCESS_EXIT_GET + return v; +} +STATIC_INLINE uae_u32 next_ilong_mmu030c_state (void) +{ + uae_u32 v; + ACCESS_CHECK_GET_PC(4); + v = get_word_030_prefetch(0) << 16; + v |= get_word_030_prefetch(2); + m68k_incpci (4); + ACCESS_EXIT_GET + return v; +} + +STATIC_INLINE uae_u32 get_word_mmu030c (uaecptr addr) +{ + return read_dcache030_mmu(addr, 1); +} +STATIC_INLINE uae_u32 get_long_mmu030c (uaecptr addr) +{ + return read_dcache030_mmu(addr, 2); +} +STATIC_INLINE void put_word_mmu030c (uaecptr addr, uae_u32 v) +{ + write_dcache030_mmu(addr, v, 1); +} +STATIC_INLINE void put_long_mmu030c (uaecptr addr, uae_u32 v) +{ + write_dcache030_mmu(addr, v, 2); +} + +extern void m68k_do_rts_mmu030c(void); +extern void m68k_do_rte_mmu030c(uaecptr a7); +extern void m68k_do_bsr_mmu030c(uaecptr oldpc, uae_s32 offset); + #endif /* UAE_CPUMMU030_H */ diff --git a/include/newcpu.h b/include/newcpu.h index c3db99ab..374a7c2a 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -121,6 +121,7 @@ struct cache030 uae_u32 data[4]; bool valid[4]; uae_u32 tag; + uae_u8 fc; }; #define CACHESETS040 64 @@ -211,13 +212,16 @@ struct regstruct uae_u32 pcr; uae_u32 address_space_mask; - uae_u32 prefetch020[CPU_PIPELINE_MAX]; + uae_u16 prefetch020[CPU_PIPELINE_MAX]; + uae_u8 prefetch020_valid[CPU_PIPELINE_MAX]; uae_u32 prefetch020addr; uae_u32 cacheholdingdata020; uae_u32 cacheholdingaddr020; + uae_u8 cacheholdingdata_valid; int pipeline_pos; int pipeline_r8[2]; int pipeline_stop; + uae_u8 fc030; int ce020endcycle; int ce020startcycle; @@ -249,7 +253,8 @@ struct cputracestruct uae_u32 msp, vbr; uae_u32 cacr, caar; - uae_u32 prefetch020[CPU_PIPELINE_MAX]; + uae_u16 prefetch020[CPU_PIPELINE_MAX]; + uae_u8 prefetch030_valid[CPU_PIPELINE_MAX]; uae_u32 prefetch020addr; uae_u32 cacheholdingdata020; uae_u32 cacheholdingaddr020; @@ -313,6 +318,15 @@ extern void(*x_cp_put_long)(uaecptr addr, uae_u32 v); extern uae_u32(*x_cp_next_iword)(void); extern uae_u32(*x_cp_next_ilong)(void); +void mem_access_delay_long_write_ce020 (uaecptr addr, uae_u32 v); +void mem_access_delay_word_write_ce020 (uaecptr addr, uae_u32 v); +void mem_access_delay_byte_write_ce020 (uaecptr addr, uae_u32 v); +uae_u32 mem_access_delay_byte_read_ce020 (uaecptr addr); +uae_u32 mem_access_delay_word_read_ce020 (uaecptr addr); +uae_u32 mem_access_delay_long_read_ce020 (uaecptr addr); +uae_u32 mem_access_delay_longi_read_ce020 (uaecptr addr); +uae_u32 mem_access_delay_wordi_read_ce020 (uaecptr addr); + extern uae_u32(REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM; /* direct (regs.pc_p) access */ @@ -505,9 +519,15 @@ STATIC_INLINE void m68k_setpc_normal(uaecptr pc) } } +extern void write_dcache030(uaecptr, uae_u32, uae_u32, uae_u32); +extern uae_u32 read_dcache030(uaecptr, uae_u32, uae_u32); + +extern void write_dcache030_mmu(uaecptr, uae_u32, uae_u32); +extern uae_u32 read_dcache030_mmu(uaecptr, uae_u32); +extern void write_dcache030_lrmw_mmu(uaecptr, uae_u32, uae_u32); +extern uae_u32 read_dcache030_lrmw_mmu(uaecptr, uae_u32); + extern void check_t0_trace(void); -extern void write_dcache030(uaecptr, uae_u32, int); -extern uae_u32 read_dcache030(uaecptr, int); extern uae_u32 get_word_icache030(uaecptr addr); extern uae_u32 get_long_icache030(uaecptr addr); @@ -614,6 +634,7 @@ extern void cpu_fallback(int mode); extern void fill_prefetch (void); extern void fill_prefetch_020_ntx(void); extern void fill_prefetch_030_ntx(void); +extern void fill_prefetch_030_ntx_continue(void); extern void fill_prefetch_020(void); extern void fill_prefetch_030(void); @@ -638,6 +659,7 @@ extern const struct cputbl op_smalltbl_52_ff[]; extern const struct cputbl op_smalltbl_22_ff[]; // prefetch extern const struct cputbl op_smalltbl_23_ff[]; // CE extern const struct cputbl op_smalltbl_32_ff[]; // MMU +extern const struct cputbl op_smalltbl_34_ff[]; // MMU + cache /* 68020 */ extern const struct cputbl op_smalltbl_3_ff[]; extern const struct cputbl op_smalltbl_43_ff[]; diff --git a/newcpu.cpp b/newcpu.cpp index 9cd43348..9de571a8 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -77,6 +77,9 @@ static int baseclock; int m68k_pc_indirect; bool m68k_interrupt_delay; static bool m68k_reset_delay; + +static bool dcache_complete_inhibit; + static int cpu_prefs_changed_flag; int cpucycleunit; @@ -246,15 +249,27 @@ static void set_x_cp_funcs(void) x_cp_get_disp_ea_020 = x_get_disp_ea_020; if (currprefs.mmu_model == 68030) { - x_cp_put_long = put_long_mmu030_state; - x_cp_put_word = put_word_mmu030_state; - x_cp_put_byte = put_byte_mmu030_state; - x_cp_get_long = get_long_mmu030_state; - x_cp_get_word = get_word_mmu030_state; - x_cp_get_byte = get_byte_mmu030_state; - x_cp_next_iword = next_iword_mmu030_state; - x_cp_next_ilong = next_ilong_mmu030_state; - x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030; + if (currprefs.cpu_compatible) { + x_cp_put_long = put_long_mmu030c_state; + x_cp_put_word = put_word_mmu030c_state; + x_cp_put_byte = put_byte_mmu030c_state; + x_cp_get_long = get_long_mmu030c_state; + x_cp_get_word = get_word_mmu030c_state; + x_cp_get_byte = get_byte_mmu030c_state; + x_cp_next_iword = next_iword_mmu030c_state; + x_cp_next_ilong = next_ilong_mmu030c_state; + x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030c; + } else { + x_cp_put_long = put_long_mmu030_state; + x_cp_put_word = put_word_mmu030_state; + x_cp_put_byte = put_byte_mmu030_state; + x_cp_get_long = get_long_mmu030_state; + x_cp_get_word = get_word_mmu030_state; + x_cp_get_byte = get_byte_mmu030_state; + x_cp_next_iword = next_iword_mmu030_state; + x_cp_next_ilong = next_ilong_mmu030_state; + x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030; + } } } @@ -746,6 +761,20 @@ static void do_cycles_ce020_post (unsigned long cycles, uae_u32 v) do_cycles_ce020 (cycles); } +static bool dcache030_check_dummy(uaecptr addr, bool write, uae_u32 size) +{ + return true; +} + +static uae_u32 (*icache_fetch)(uaecptr); +static uae_u32 (*dcache030_lget)(uaecptr); +static uae_u32 (*dcache030_wget)(uaecptr); +static uae_u32 (*dcache030_bget)(uaecptr); +static bool (*dcache030_check)(uaecptr, bool, uae_u32); +static void (*dcache030_lput)(uaecptr, uae_u32); +static void (*dcache030_wput)(uaecptr, uae_u32); +static void (*dcache030_bput)(uaecptr, uae_u32); + static void set_x_ifetches(void) { if (m68k_pc_indirect) { @@ -810,18 +839,53 @@ static void set_x_funcs (void) } else { - x_prefetch = get_iword_mmu030; - x_get_ilong = get_ilong_mmu030; - x_get_iword = get_iword_mmu030; - x_get_ibyte = get_ibyte_mmu030; - x_next_iword = next_iword_mmu030; - x_next_ilong = next_ilong_mmu030; - x_put_long = put_long_mmu030; - x_put_word = put_word_mmu030; - x_put_byte = put_byte_mmu030; - x_get_long = get_long_mmu030; - x_get_word = get_word_mmu030; - x_get_byte = get_byte_mmu030; + if (currprefs.cpu_memory_cycle_exact) { + x_prefetch = get_iword_mmu030c_state; + x_get_ilong = get_ilong_mmu030c_state; + x_get_iword = get_iword_mmu030c_state; + x_get_ibyte = NULL; + x_next_iword = next_iword_mmu030c_state; + x_next_ilong = next_ilong_mmu030c_state; + x_put_long = put_long_ce030; + x_put_word = put_word_ce030; + x_put_byte = put_byte_ce030; + x_get_long = get_long_ce030; + x_get_word = get_word_ce030; + x_get_byte = get_byte_ce030; + x_do_cycles = do_cycles; + x_do_cycles_pre = do_cycles; + x_do_cycles_post = do_cycles_post; + } else if (currprefs.cpu_compatible) { + x_prefetch = get_iword_mmu030c_state; + x_get_ilong = get_ilong_mmu030c_state; + x_get_iword = get_iword_mmu030c_state; + x_get_ibyte = NULL; + x_next_iword = next_iword_mmu030c_state; + x_next_ilong = next_ilong_mmu030c_state; + x_put_long = put_long_ce030; + x_put_word = put_word_ce030; + x_put_byte = put_byte_ce030; + x_get_long = get_long_ce030; + x_get_word = get_word_ce030; + x_get_byte = get_byte_ce030; + x_do_cycles = do_cycles; + x_do_cycles_pre = do_cycles; + x_do_cycles_post = do_cycles_post; + } else { + x_prefetch = get_iword_mmu030; + x_get_ilong = get_ilong_mmu030; + x_get_iword = get_iword_mmu030; + x_get_ibyte = get_ibyte_mmu030; + x_next_iword = next_iword_mmu030; + x_next_ilong = next_ilong_mmu030; + x_put_long = put_long_mmu030; + x_put_word = put_word_mmu030; + x_put_byte = put_byte_mmu030; + x_get_long = get_long_mmu030; + x_get_word = get_word_mmu030; + x_get_byte = get_byte_mmu030; + } + } x_do_cycles = do_cycles; x_do_cycles_pre = do_cycles; @@ -987,12 +1051,12 @@ static void set_x_funcs (void) x_get_ibyte = NULL; x_next_iword = next_iword_030_prefetch; x_next_ilong = next_ilong_030_prefetch; - x_put_long = put_long; - x_put_word = put_word; - x_put_byte = put_byte; - x_get_long = get_long; - x_get_word = get_word; - x_get_byte = get_byte; + x_put_long = put_long_030; + x_put_word = put_word_030; + x_put_byte = put_byte_030; + x_get_long = get_long_030; + x_get_word = get_word_030; + x_get_byte = get_byte_030; x_do_cycles = do_cycles; x_do_cycles_pre = do_cycles; x_do_cycles_post = do_cycles_post; @@ -1154,6 +1218,47 @@ static void set_x_funcs (void) mmu_set_funcs(); mmu030_set_funcs(); + icache_fetch = get_longi; + dcache030_lput = put_long; + dcache030_wput = put_word; + dcache030_bput = put_byte; + dcache030_lget = get_long; + dcache030_wget = get_word; + dcache030_bget = get_byte; + dcache030_check = dcache030_check_dummy; + if (currprefs.cpu_cycle_exact) { + icache_fetch = mem_access_delay_longi_read_ce020; + } + if (currprefs.cpu_model == 68030) { + if (currprefs.mmu_model) { + if (currprefs.cpu_compatible) { + icache_fetch = uae_mmu030_get_ilong_fc; + dcache030_lput = uae_mmu030_put_long_fc; + dcache030_wput = uae_mmu030_put_word_fc; + dcache030_bput = uae_mmu030_put_byte_fc; + dcache030_lget = uae_mmu030_get_long_fc; + dcache030_wget = uae_mmu030_get_word_fc; + dcache030_bget = uae_mmu030_get_byte_fc; + dcache030_check = uae_mmu030_check_fc; + } else { + icache_fetch = uae_mmu030_get_ilong; + dcache030_lput = uae_mmu030_put_long; + dcache030_wput = uae_mmu030_put_word; + dcache030_bput = uae_mmu030_put_byte; + dcache030_lget = uae_mmu030_get_long; + dcache030_wget = uae_mmu030_get_word; + dcache030_bget = uae_mmu030_get_byte; + } + } else if (currprefs.cpu_memory_cycle_exact) { + icache_fetch = mem_access_delay_longi_read_ce020; + dcache030_lput = mem_access_delay_long_write_ce020; + dcache030_wput = mem_access_delay_word_write_ce020; + dcache030_bput = mem_access_delay_byte_write_ce020; + dcache030_lget = mem_access_delay_long_read_ce020; + dcache030_wget = mem_access_delay_word_read_ce020; + dcache030_bget = mem_access_delay_byte_read_ce020; + } + } } bool can_cpu_tracer (void) @@ -1292,21 +1397,21 @@ static uae_u32 REGPARAM2 op_unimpl_1 (uae_u32 opcode) return 4; } -// generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu -static const struct cputbl *cputbls[6][6] = +// generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu, mm+more compatible +static const struct cputbl *cputbls[6][7] = { // 68000 - { op_smalltbl_5_ff, op_smalltbl_45_ff, op_smalltbl_55_ff, op_smalltbl_12_ff, op_smalltbl_14_ff, NULL }, + { op_smalltbl_5_ff, op_smalltbl_45_ff, op_smalltbl_55_ff, op_smalltbl_12_ff, op_smalltbl_14_ff, NULL, NULL }, // 68010 - { op_smalltbl_4_ff, op_smalltbl_44_ff, op_smalltbl_54_ff, op_smalltbl_11_ff, op_smalltbl_13_ff, NULL }, + { op_smalltbl_4_ff, op_smalltbl_44_ff, op_smalltbl_54_ff, op_smalltbl_11_ff, op_smalltbl_13_ff, NULL, NULL }, // 68020 - { op_smalltbl_3_ff, op_smalltbl_43_ff, op_smalltbl_53_ff, op_smalltbl_20_ff, op_smalltbl_21_ff, NULL }, + { op_smalltbl_3_ff, op_smalltbl_43_ff, op_smalltbl_53_ff, op_smalltbl_20_ff, op_smalltbl_21_ff, NULL, NULL }, // 68030 - { op_smalltbl_2_ff, op_smalltbl_42_ff, op_smalltbl_52_ff, op_smalltbl_22_ff, op_smalltbl_23_ff, op_smalltbl_32_ff }, + { op_smalltbl_2_ff, op_smalltbl_42_ff, op_smalltbl_52_ff, op_smalltbl_22_ff, op_smalltbl_23_ff, op_smalltbl_32_ff, op_smalltbl_34_ff }, // 68040 - { op_smalltbl_1_ff, op_smalltbl_41_ff, op_smalltbl_51_ff, op_smalltbl_25_ff, op_smalltbl_25_ff, op_smalltbl_31_ff }, + { op_smalltbl_1_ff, op_smalltbl_41_ff, op_smalltbl_51_ff, op_smalltbl_25_ff, op_smalltbl_25_ff, op_smalltbl_31_ff, NULL }, // 68060 - { op_smalltbl_0_ff, op_smalltbl_40_ff, op_smalltbl_50_ff, op_smalltbl_24_ff, op_smalltbl_24_ff, op_smalltbl_33_ff } + { op_smalltbl_0_ff, op_smalltbl_40_ff, op_smalltbl_50_ff, op_smalltbl_24_ff, op_smalltbl_24_ff, op_smalltbl_33_ff, NULL } }; static void build_cpufunctbl (void) @@ -1317,14 +1422,18 @@ static void build_cpufunctbl (void) int lvl, mode; if (!currprefs.cachesize) { - if (currprefs.mmu_model) - mode = 5; - else if (currprefs.cpu_cycle_exact) + if (currprefs.mmu_model) { + if (currprefs.cpu_compatible) + mode = 6; + else + mode = 5; + } else if (currprefs.cpu_cycle_exact) { mode = 4; - else if (currprefs.cpu_compatible) + } else if (currprefs.cpu_compatible) { mode = 3; - else + } else { mode = 0; + } m68k_pc_indirect = mode != 0 ? 1 : 0; } else { mode = 1; @@ -1569,6 +1678,7 @@ static void prefs_changed_cpu (void) fake_crp_030 = crp_030; } } + currprefs.mmu_ec = changed_prefs.mmu_ec; currprefs.cpu_compatible = changed_prefs.cpu_compatible; currprefs.address_space_24 = changed_prefs.address_space_24; currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact; @@ -1589,6 +1699,7 @@ static int check_prefs_changed_cpu2(void) || currprefs.cpu_model != changed_prefs.cpu_model || currprefs.fpu_model != changed_prefs.fpu_model || currprefs.mmu_model != changed_prefs.mmu_model + || currprefs.mmu_ec != changed_prefs.mmu_ec || currprefs.int_no_unimplemented != changed_prefs.int_no_unimplemented || currprefs.fpu_no_unimplemented != changed_prefs.fpu_no_unimplemented || currprefs.cpu_compatible != changed_prefs.cpu_compatible @@ -2552,10 +2663,17 @@ static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 m68k_areg (regs, 7) -= 4; x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // 2xinternal - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); + { + uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0); + ps |= ((regs.pipeline_r8[0] & 7) << 8); + ps |= ((regs.pipeline_r8[1] & 7) << 11); + ps |= ((regs.pipeline_pos & 15) << 16); + ps |= ((regs.pipeline_stop & 15) << 20); + if (mmu030_opcode == -1) + ps |= 1 << 31; + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), ps); + } // stage b address m68k_areg (regs, 7) -= 4; x_put_long (m68k_areg (regs, 7), mm030_stageb_address); @@ -2570,13 +2688,13 @@ static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 // Data output buffer = value that was going to be written x_put_long (m68k_areg (regs, 7), (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val); m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), mmu030_opcode); // Internal register (opcode storage) + x_put_long (m68k_areg (regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage) m68k_areg (regs, 7) -= 4; x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage B + x_put_word (m68k_areg (regs, 7), regs.prefetch020[2]); // Instr. pipe stage B m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage C + x_put_word (m68k_areg (regs, 7), regs.prefetch020[1]); // Instr. pipe stage C m68k_areg (regs, 7) -= 2; x_put_word (m68k_areg (regs, 7), ssw); m68k_areg (regs, 7) -= 2; @@ -2652,13 +2770,12 @@ static void Exception_mmu030 (int nr, uaecptr oldpc) } #endif + newpc = x_get_long (regs.vbr + 4 * nr); + #if 0 - write_log (_T("Exception %d -> %08x\n", nr, newpc)); + write_log (_T("Exception %d -> %08x\n"), nr, newpc); #endif - - newpc = x_get_long (regs.vbr + 4 * nr); - if (regs.m && interrupt) { /* M + Interrupt */ Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x0); MakeSR (); @@ -3192,6 +3309,9 @@ static void m68k_reset2(bool hardreset) mmufixup[0].reg = -1; mmufixup[1].reg = -1; + mmu030_cache_inhibit = 0; + dcache_complete_inhibit = uae_boot_rom_type > 0; + //dcache_complete_inhibit = true; if (currprefs.mmu_model >= 68040) { mmu_reset (); mmu_set_tc (regs.tcr); @@ -5025,7 +5145,10 @@ insretry: } mmu030_fake_prefetch = -1; } else if (mmu030_opcode_stageb < 0) { - regs.opcode = x_prefetch (0); + if (currprefs.cpu_compatible) + regs.opcode = regs.irc; + else + regs.opcode = x_prefetch (0); } else { regs.opcode = mmu030_opcode_stageb; mmu030_opcode_stageb = -1; @@ -5036,7 +5159,7 @@ insretry: cnt = 50; for (;;) { - regs.opcode = mmu030_opcode; + regs.opcode = regs.irc = mmu030_opcode; mmu030_idx = 0; count_instr (regs.opcode); do_cycles (cpu_cycles); @@ -5064,20 +5187,27 @@ insretry: } } CATCH (prb) { - regflags.cznv = f.cznv; - regflags.x = f.x; - - m68k_setpci (regs.instruction_pc); - - if (mmufixup[0].reg >= 0) { - m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value; + if (mmu030_opcode == -1 && currprefs.cpu_compatible) { + // full prefetch fill access fault + // TODO: this should create shorter A-frame mmufixup[0].reg = -1; - } - if (mmufixup[1].reg >= 0) { - m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value; mmufixup[1].reg = -1; + } else { + regflags.cznv = f.cznv; + regflags.x = f.x; + + if (mmufixup[0].reg >= 0) { + m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value; + mmufixup[0].reg = -1; + } + if (mmufixup[1].reg >= 0) { + m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value; + mmufixup[1].reg = -1; + } } + m68k_setpci (regs.instruction_pc); + TRY (prb2) { Exception (prb); } CATCH (prb2) { @@ -5191,7 +5321,7 @@ static void m68k_run_2ce (void) r->cacheholdingdata020 = cputrace.cacheholdingdata020; r->cacheholdingaddr020 = cputrace.cacheholdingaddr020; r->prefetch020addr = cputrace.prefetch020addr; - memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32)); + memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16)); memcpy (&caches020, &cputrace.caches020, sizeof caches020); m68k_setpc (cputrace.pc); @@ -5259,7 +5389,7 @@ static void m68k_run_2ce (void) cputrace.cacheholdingdata020 = r->cacheholdingdata020; cputrace.cacheholdingaddr020 = r->cacheholdingaddr020; cputrace.prefetch020addr = r->prefetch020addr; - memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32)); + memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16)); memcpy (&cputrace.caches020, &caches020, sizeof caches020); cputrace.memoryoffset = 0; @@ -5328,7 +5458,7 @@ static void m68k_run_2p (void) r->cacheholdingdata020 = cputrace.cacheholdingdata020; r->cacheholdingaddr020 = cputrace.cacheholdingaddr020; r->prefetch020addr = cputrace.prefetch020addr; - memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32)); + memcpy (&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16)); memcpy (&caches020, &cputrace.caches020, sizeof caches020); m68k_setpc (cputrace.pc); @@ -5379,7 +5509,7 @@ static void m68k_run_2p (void) cputrace.cacheholdingdata020 = r->cacheholdingdata020; cputrace.cacheholdingaddr020 = r->cacheholdingaddr020; cputrace.prefetch020addr = r->prefetch020addr; - memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u32)); + memcpy (&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16)); memcpy (&cputrace.caches020, &caches020, sizeof caches020); cputrace.memoryoffset = 0; @@ -6740,7 +6870,7 @@ void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cn } else if (lookup->mnemo == i_MOVES) { TCHAR *p; pc += 2; - if (!(extra & 0x1000)) { + if (!(extra & 0x0800)) { pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode); p = instrname + _tcslen(instrname); _stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7); @@ -7106,16 +7236,24 @@ void m68k_dumpstate (uaecptr pc, uaecptr *nextpc) console_out_f (_T("SRP: %llX CRP: %llX\n"), srp_030, crp_030); console_out_f (_T("TT0: %08X TT1: %08X TC: %08X\n"), tt0_030, tt1_030, tc_030); } - if (currprefs.cpu_compatible && currprefs.cpu_model == 68000) { - struct instr *dp; - struct mnemolookup *lookup1, *lookup2; - dp = table68k + regs.irc; - for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++) - ; - dp = table68k + regs.ir; - for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++) - ; - console_out_f (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw); + if (currprefs.cpu_compatible) { + if (currprefs.cpu_model == 68000) { + struct instr *dp; + struct mnemolookup *lookup1, *lookup2; + dp = table68k + regs.irc; + for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++) + ; + dp = table68k + regs.ir; + for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++) + ; + console_out_f (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw); + } else if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) { + console_out_f (_T("Prefetch %08x %08x (%d) %04x (%d) %04x (%d) %04x (%d)\n"), + regs.cacheholdingaddr020, regs.cacheholdingdata020, regs.cacheholdingdata_valid, + regs.prefetch020[0], regs.prefetch020_valid[0], + regs.prefetch020[1], regs.prefetch020_valid[1], + regs.prefetch020[2], regs.prefetch020_valid[2]); + } } if (pc != 0xffffffff) { @@ -7137,24 +7275,35 @@ void m68k_dumpcache (void) for (int j = 0; j < 4; j++) { int s = i + j; uaecptr addr; + int fc; struct cache020 *c = &caches020[s]; + fc = c->tag & 1; addr = c->tag & ~1; addr |= s << 2; - console_out_f (_T("%08X:%08X%c "), addr, c->data, c->valid ? '*' : ' '); + console_out_f (_T("%08X%c:%08X%c"), addr, fc ? 'S' : 'U', c->data, c->valid ? '*' : ' '); } console_out_f (_T("\n")); } } else if (currprefs.cpu_model == 68030) { - for (int i = 0; i < CACHELINES030; i++) { - struct cache030 *c = &icaches030[i]; - uaecptr addr; - addr = c->tag & ~1; - addr |= i << 4; - console_out_f (_T("%08X: "), addr); - for (int j = 0; j < 4; j++) { - console_out_f (_T("%08X%c "), c->data[j], c->valid[j] ? '*' : ' '); + for (int j = 0; j < 2; j++) { + console_out_f (_T("%s\n"), j == 0 ? _T("Instruction") : _T("Data")); + for (int i = 0; i < CACHELINES030; i++) { + struct cache030 *c = j ? &dcaches030[i] : &icaches030[i]; + int fc; + uaecptr addr; + if (j == 0) { + fc = (c->tag & 1) ? 6 : 2; + } else { + fc = c->fc; + } + addr = c->tag & ~1; + addr |= i << 4; + console_out_f (_T("%08X %d: "), addr, fc); + for (int j = 0; j < 4; j++) { + console_out_f (_T("%08X%c "), c->data[j], c->valid[j] ? '*' : ' '); + } + console_out_f (_T("\n")); } - console_out_f (_T("\n")); } } } @@ -7943,13 +8092,14 @@ static void end_020_cycle_prefetch(bool opcode) } // this one is really simple and easy -static void fill_icache020 (uae_u32 addr, uae_u32 (*fetch)(uaecptr), bool opcode) +static void fill_icache020 (uae_u32 addr, bool opcode) { int index; uae_u32 tag; uae_u32 data; struct cache020 *c; + regs.fc030 = (regs.s ? 4 : 0) | 2; addr &= ~3; if (regs.cacheholdingaddr020 == addr) return; @@ -7960,8 +8110,10 @@ static void fill_icache020 (uae_u32 addr, uae_u32 (*fetch)(uaecptr), bool opcode // cache hit regs.cacheholdingaddr020 = addr; regs.cacheholdingdata020 = c->data; + regs.cacheholdingdata_valid = true; return; } + // cache miss #if 0 // Prefetch apparently can be queued by bus controller @@ -7976,7 +8128,7 @@ static void fill_icache020 (uae_u32 addr, uae_u32 (*fetch)(uaecptr), bool opcode #endif start_020_cycle_prefetch(opcode); - data = fetch (addr); + data = icache_fetch(addr); end_020_cycle_prefetch(opcode); if (!(regs.cacr & 2)) { @@ -7986,6 +8138,7 @@ static void fill_icache020 (uae_u32 addr, uae_u32 (*fetch)(uaecptr), bool opcode } regs.cacheholdingaddr020 = addr; regs.cacheholdingdata020 = data; + regs.cacheholdingdata_valid = true; } #if MORE_ACCURATE_68020_PIPELINE @@ -7993,8 +8146,13 @@ static void fill_icache020 (uae_u32 addr, uae_u32 (*fetch)(uaecptr), bool opcode #if PIPELINE_DEBUG static uae_u16 pipeline_opcode; #endif -static void pipeline_020(uae_u16 w, uaecptr pc) +static void pipeline_020(uaecptr pc) { + uae_u16 w = regs.prefetch020[1]; + if (regs.prefetch020_valid[1] == 0) { + regs.pipeline_stop = -1; + return; + } if (regs.pipeline_pos < 0) return; if (regs.pipeline_pos > 0) { @@ -8080,26 +8238,23 @@ static uae_u32 get_word_ce020_prefetch_2 (int o, bool opcode) uae_u32 pc = m68k_getpc () + o; uae_u32 v; - if (pc & 2) { - v = regs.prefetch020[0] & 0xffff; + v = regs.prefetch020[0]; + regs.prefetch020[0] = regs.prefetch020[1]; + regs.prefetch020[1] = regs.prefetch020[2]; #if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1], pc ); + pipeline_020(pc); #endif - regs.prefetch020[0] = regs.prefetch020[1]; + if (pc & 2) { // branch instruction detected in pipeline: stop fetches until branch executed. if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) { - fill_icache020 (pc + 2 + 4, mem_access_delay_longi_read_ce020, opcode); - regs.prefetch020[1] = regs.cacheholdingdata020; + fill_icache020 (pc + 2 + 4, opcode); } - regs.db = regs.prefetch020[0] >> 16; + regs.prefetch020[2] = regs.cacheholdingdata020 >> 16; } else { - v = regs.prefetch020[0] >> 16; -#if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1] >> 16, pc); -#endif - regs.db = regs.prefetch020[1] >> 16; + regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020; } do_cycles_ce020_internal (2); + regs.db = regs.prefetch020[0]; return v; } @@ -8118,24 +8273,22 @@ uae_u32 get_word_020_prefetch (int o) uae_u32 pc = m68k_getpc () + o; uae_u32 v; - if (pc & 2) { - v = regs.prefetch020[0] & 0xffff; + v = regs.prefetch020[0]; + regs.prefetch020[0] = regs.prefetch020[1]; + regs.prefetch020[1] = regs.prefetch020[2]; #if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1], pc); + pipeline_020(pc); #endif - regs.prefetch020[0] = regs.prefetch020[1]; + if (pc & 2) { + // branch instruction detected in pipeline: stop fetches until branch executed. if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) { - fill_icache020 (pc + 2 + 4, currprefs.cpu_memory_cycle_exact ? mem_access_delay_longi_read_ce020 : get_longi, false); - regs.prefetch020[1] = regs.cacheholdingdata020; + fill_icache020 (pc + 2 + 4, false); } - regs.db = regs.prefetch020[0] >> 16; + regs.prefetch020[2] = regs.cacheholdingdata020 >> 16; } else { - v = regs.prefetch020[0] >> 16; -#if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1] >> 16, pc); -#endif - regs.db = regs.prefetch020[0]; + regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020; } + regs.db = regs.prefetch020[0]; return v; } @@ -8223,6 +8376,37 @@ uae_u32 mem_access_delay_longi_read_ce020 (uaecptr addr) return v; } +uae_u32 mem_access_delay_wordi_read_ce020 (uaecptr addr) +{ + uae_u32 v; + start_020_cycle(); + switch (ce_banktype[addr >> 16]) + { + case CE_MEMBANK_CHIP16: + case CE_MEMBANK_CHIP32: + if ((addr & 3) == 3) { + v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8; + v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0; + } else { + v = wait_cpu_cycle_read_ce020 (addr, 1); + } + break; + case CE_MEMBANK_FAST16: + case CE_MEMBANK_FAST32: + v = get_wordi (addr); + if ((addr & 3) == 3) + do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v); + else + do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v); + break; + default: + v = get_wordi (addr); + break; + } + end_020_cycle(); + return v; +} + uae_u32 mem_access_delay_word_read_ce020 (uaecptr addr) { uae_u32 v; @@ -8364,7 +8548,8 @@ void mem_access_delay_long_write_ce020 (uaecptr addr, uae_u32 v) // 68030 caches aren't so simple as 68020 cache.. -STATIC_INLINE struct cache030 *getcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp) + +STATIC_INLINE struct cache030 *geticache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp) { int index, lws; uae_u32 tag; @@ -8380,7 +8565,7 @@ STATIC_INLINE struct cache030 *getcache030 (struct cache030 *cp, uaecptr addr, u return c; } -STATIC_INLINE void update_cache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws) +STATIC_INLINE void update_icache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws) { if (c->tag != tag) c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false; @@ -8389,6 +8574,32 @@ STATIC_INLINE void update_cache030 (struct cache030 *c, uae_u32 val, uae_u32 tag c->data[lws] = val; } +STATIC_INLINE struct cache030 *getdcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp) +{ + int index, lws; + uae_u32 tag; + struct cache030 *c; + + addr &= ~3; + index = (addr >> 4) & (CACHELINES030 - 1); + tag = addr & ~((CACHELINES030 << 4) - 1); + lws = (addr >> 2) & 3; + c = &cp[index]; + *tagp = tag; + *lwsp = lws; + return c; +} + +STATIC_INLINE void update_dcache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, uae_u8 fc, int lws) +{ + if (c->tag != tag) + c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false; + c->tag = tag; + c->fc = fc; + c->valid[lws] = true; + c->data[lws] = val; +} + static void fill_icache030 (uae_u32 addr) { int lws; @@ -8396,10 +8607,11 @@ static void fill_icache030 (uae_u32 addr) uae_u32 data; struct cache030 *c; + regs.fc030 = (regs.s ? 4 : 0) | 2; addr &= ~3; - if (regs.cacheholdingaddr020 == addr) + if (regs.cacheholdingaddr020 == addr || regs.cacheholdingdata_valid == 0) return; - c = getcache030 (icaches030, addr, &tag, &lws); + c = geticache030 (icaches030, addr, &tag, &lws); if (c->valid[lws] && c->tag == tag) { // cache hit regs.cacheholdingaddr020 = addr; @@ -8407,33 +8619,71 @@ static void fill_icache030 (uae_u32 addr) return; } - // cache miss - if (currprefs.cpu_cycle_exact) { - regs.ce020memcycle_data = false; - start_020_cycle_prefetch(false); - data = mem_access_delay_longi_read_ce020 (addr); - end_020_cycle_prefetch(false); - } else if (currprefs.cpu_memory_cycle_exact) { - data = mem_access_delay_longi_read_ce020 (addr); - } else { - data = get_longi (addr); - } - if ((regs.cacr & 3) == 1) { // not frozen and enabled - update_cache030 (c, data, tag, lws); - } - if ((regs.cacr & 0x11) == 0x11 && lws == 0 && !c->valid[1] && !c->valid[2] && !c->valid[3] && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) { - // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram - c->data[1] = get_longi (addr + 4); - c->data[2] = get_longi (addr + 8); - c->data[3] = get_longi (addr + 12); - if (currprefs.cpu_cycle_exact) - do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]); - c->valid[1] = c->valid[2] = c->valid[3] = true; + TRY (prb2) { + // cache miss + if (currprefs.cpu_cycle_exact) { + regs.ce020memcycle_data = false; + start_020_cycle_prefetch(false); + data = icache_fetch(addr); + end_020_cycle_prefetch(false); + } else { + data = icache_fetch(addr); + } + } CATCH (prb2) { + // Bus error/MMU access fault: Delayed exception. + regs.cacheholdingdata_valid = 0; + regs.cacheholdingaddr020 = 0xffffffff; + regs.cacheholdingdata020 = 0xffffffff; + return; + } ENDTRY + + if (!mmu030_cache_inhibit) { + if ((regs.cacr & 0x03) == 0x01) { + // instruction cache not frozen and enabled + update_icache030 (c, data, tag, lws); + } + if ((regs.cacr & 0x11) == 0x11 && (c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) { + // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram + int i; + for (i = 0; i < 4; i++) { + if (c->valid[i]) + break; + } + uaecptr baddr = addr & ~15; + if (currprefs.mmu_model) { + if (currprefs.cpu_cycle_exact) + do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1)); + TRY (prb) { + for (int j = 0; j < 3; j++) { + i++; + i &= 3; + c->data[i] = icache_fetch(baddr + i * 4); + c->valid[i] = true; + } + } CATCH (prb) { + ; // abort burst fetch if bus error, do not report it. + } ENDTRY + } else { + for (int j = 0; j < 3; j++) { + i++; + i &= 3; + c->data[i] = icache_fetch(baddr + i * 4); + c->valid[i] = true; + } + if (currprefs.cpu_cycle_exact) + do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]); + } + } } regs.cacheholdingaddr020 = addr; regs.cacheholdingdata020 = data; } +STATIC_INLINE bool candcache030 (uaecptr addr) +{ + // mmu mode cacheability is checked in mmu030_get/mmu030_put routines + return currprefs.mmu_model || ce_cachable[addr >> 16] != 0; +} #if VALIDATE_68030_DATACACHE static void validate_dcache030(void) @@ -8447,7 +8697,6 @@ static void validate_dcache030(void) uae_u32 v = get_long(addr); if (v != c->data[j]) { write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j]); - activate_debugger(); } } addr += 4; @@ -8473,220 +8722,258 @@ static void validate_dcache030_read(uae_u32 addr, uae_u32 ov, int size) } #endif -STATIC_INLINE bool cancache030 (uaecptr addr) -{ - return ce_cachable[addr >> 16] != 0; -} - // and finally the worst part, 68030 data cache.. -static void write_dcache030x(uaecptr addr, uae_u32 val, int size) -{ - struct cache030 *c1, *c2; - int lws1, lws2; - uae_u32 tag1, tag2; - int aligned = addr & 3; - int wa = regs.cacr & 0x2000; - int hit; - - if (!(regs.cacr & 0x100)) // data cache disabled? - return; - if (!cancache030(addr)) - return; - - c1 = getcache030(dcaches030, addr, &tag1, &lws1); - - // easy one - if (size == 2 && aligned == 0 && wa) { - update_cache030(c1, val, tag1, lws1); - return; - } - - hit = (c1->tag == tag1 && c1->valid[lws1]); - if (hit || wa) { - if (size == 2) { - if (hit) { - c1->data[lws1] &= ~(0xffffffff >> (aligned * 8)); - c1->data[lws1] |= val >> (aligned * 8); - } else - c1->valid[lws1] = false; - } else if (size == 1) { - if (hit) { - c1->data[lws1] &= ~(0xffff0000 >> (aligned * 8)); - c1->data[lws1] |= (val << 16) >> (aligned * 8); - } else +static void write_dcache030x(uaecptr addr, uae_u32 val, uae_u32 size, uae_u32 fc) +{ + if (regs.cacr & 0x100) { + static const uae_u32 mask[3] = { 0xff000000, 0xffff0000, 0xffffffff }; + struct cache030 *c1, *c2; + int lws1, lws2; + uae_u32 tag1, tag2; + int aligned = addr & 3; + int wa = regs.cacr & 0x2000; + int width = 8 << size; + int offset = 8 * aligned; + int hit; + + c1 = getdcache030(dcaches030, addr, &tag1, &lws1); + hit = c1->tag == tag1 && c1->fc == fc && c1->valid[lws1]; + + // Write-allocate can create new valid cache entry if + // long aligned long write and MMU CI is not active. + // All writes ignore external CIIN signal. + + if (width == 32 && offset == 0 && wa) { + if (mmu030_cache_inhibit <= 0) { + update_dcache030(c1, val, tag1, fc, lws1); +#if VALIDATE_68030_DATACACHE + validate_dcache030(); +#endif + } else if (hit) { + // Does real 68030 do this if MMU cache inhibited? c1->valid[lws1] = false; - } else if (size == 0) { + } + return; + } + + val <<= (32 - width); + if (hit || wa) { if (hit) { - c1->data[lws1] &= ~(0xff000000 >> (aligned * 8)); - c1->data[lws1] |= (val << 24) >> (aligned * 8); - } else + c1->data[lws1] &= ~(mask[size] >> offset); + c1->data[lws1] |= val >> offset; + } else { c1->valid[lws1] = false; + } } - } - // do we need to update a 2nd cache entry ? - if ((size == 0) || (size == 1 && aligned <= 2) || (size == 2 && aligned == 0)) - return; - - c2 = getcache030(dcaches030, addr + 4, &tag2, &lws2); - hit = (c2->tag == tag2 && c2->valid[lws2]); - if (hit || wa) { - if (size == 2) { - if (hit) { - c2->data[lws2] &= 0xffffffff >> (aligned * 8); - c2->data[lws2] |= val << ((4 - aligned) * 8); - } else - c2->valid[lws2] = false; - } else if (size == 1) { - if (hit) { - c2->data[lws2] &= 0x00ffffff; - c2->data[lws2] |= val << 24; - } else - c2->valid[lws2] = false; + // do we need to update a 2nd cache entry ? + if (width + offset > 32) { + c2 = getdcache030(dcaches030, addr + 4, &tag2, &lws2); + hit = c2->tag == tag2 && c2->fc == fc && c2->valid[lws2]; + if (hit || wa) { + if (hit) { + c2->data[lws2] &= ~(mask[size] << (width + offset - 32)); + c2->data[lws2] |= val << (width + offset - 32); + } else { + c2->valid[lws2] = false; + } + } } +#if VALIDATE_68030_DATACACHE + validate_dcache030(); +#endif } } -void write_dcache030(uaecptr addr, uae_u32 v, int size) +void write_dcache030(uaecptr addr, uae_u32 v, uae_u32 size, uae_u32 fc) { - write_dcache030x(addr, v, size); - if (currprefs.cpu_memory_cycle_exact) { - if (size == 2) - mem_access_delay_long_write_ce020(addr, v); - else if (size == 1) - mem_access_delay_word_write_ce020(addr, v); - else - mem_access_delay_byte_write_ce020(addr, v); - } else { - if (size == 2) - put_long(addr, v); - else if (size == 1) - put_word(addr, v); - else - put_byte(addr, v); - } -#if VALIDATE_68030_DATACACHE - validate_dcache030(); -#endif + regs.fc030 = fc; + if (size == 2) + dcache030_lput(addr, v); + else if (size == 1) + dcache030_wput(addr, v); + else + dcache030_bput(addr, v); + write_dcache030x(addr, v, size, fc); } -uae_u32 read_dcache030 (uaecptr addr, int size) +static void dcache030_maybe_burst(uaecptr addr, struct cache030 *c, int lws) { - struct cache030 *c1, *c2; - int lws1, lws2; - uae_u32 tag1, tag2; - int aligned = addr & 3; - uae_u32 v1, v2; -#if VALIDATE_68030_DATACACHE - uae_u32 addr2 = addr; -#endif - - if (!(regs.cacr & 0x100) || !cancache030 (addr)) { // data cache disabled? - if (currprefs.cpu_memory_cycle_exact) { - if (size == 2) - return mem_access_delay_long_read_ce020 (addr); - else if (size == 1) - return mem_access_delay_word_read_ce020 (addr); - else - return mem_access_delay_byte_read_ce020 (addr); + if ((c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) { + // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram + int i; + uaecptr baddr = addr & ~15; + for (i = 0; i < 4; i++) { + if (c->valid[i]) + break; + } + if (currprefs.mmu_model) { + TRY (prb) { + if (currprefs.cpu_cycle_exact) + do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1)); + for (int j = 0; j < 3; j++) { + i++; + i &= 3; + c->data[i] = dcache030_lget (baddr + i * 4); + c->valid[i] = true; + } + } CATCH (prb) { + ; // abort burst fetch if bus error + } ENDTRY } else { - if (size == 2) - return get_long (addr); - else if (size == 1) - return get_word (addr); - else - return get_byte (addr); + for (int j = 0; j < 3; j++) { + i++; + i &= 3; + c->data[i] = dcache030_lget (baddr + i * 4); + c->valid[i] = true; + } + if (currprefs.cpu_cycle_exact) + do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[i]); } - } - c1 = getcache030 (dcaches030, addr, &tag1, &lws1); - addr &= ~3; - if (!c1->valid[lws1] || c1->tag != tag1) { - v1 = currprefs.cpu_memory_cycle_exact ? mem_access_delay_long_read_ce020 (addr) : get_long (addr); - update_cache030 (c1, v1, tag1, lws1); #if VALIDATE_68030_DATACACHE validate_dcache030(); #endif - } else { - v1 = c1->data[lws1]; - if (uae_boot_rom_type > 0) { - // this check and fix is needed for UAE filesystem handler because it runs in host side and in - // separate thread. No way to access via cache without locking that would cause major slowdown - // and unneeded complexity - uae_u32 tv = get_long(addr); - if (tv != v1) { - write_log(_T("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n"), - size, aligned, addr, tv, v1, tag1, lws1, M68K_GETPC); - v1 = tv; - } - } } +} - // only one long fetch needed? - if (size == 0) { - v1 >>= (3 - aligned) * 8; +#if 0 +static void uae_cache_check(uaecptr addr, uae_u32 *v, struct cache030 *c, int lws, int size) +{ + if (uae_boot_rom_type <= 0) + return; + // this check and fix is needed for UAE filesystem handler because it runs in host side and in + // separate thread. No way to access via cache without locking that would cause major slowdown + // and unneeded complexity + uae_u32 tv = get_long(addr); + if (tv != *v) { + write_log(_T("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n"), + size, addr, tv, v, c->tag, lws, M68K_GETPC); + *v = tv; + } +} +#endif + +uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc) +{ + uae_u32 addr_o = addr; + regs.fc030 = fc; + if ((regs.cacr & 0x100) && !dcache_complete_inhibit) { // 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) { + // Cache miss and caching inhibited -> normal read + if (mmu030_cache_inhibit || !candcache030(addr)) + goto end; + // MMU validate address, returns zero if valid but uncacheable + // throws bus error if invalid + if (!dcache030_check(addr_o, false, size)) + goto end; + v1 = dcache030_lget(addr); + update_dcache030 (c1, v1, tag1, fc, lws1); + if (!mmu030_cache_inhibit && (regs.cacr & 0x1100) == 0x1100) + dcache030_maybe_burst(addr, c1, lws1); #if VALIDATE_68030_DATACACHE - validate_dcache030_read(addr2, v1, size); + validate_dcache030(); #endif - return v1; - } else if (size == 1 && aligned <= 2) { - v1 >>= (2 - aligned) * 8; -#if VALIDATE_68030_DATACACHE - validate_dcache030_read(addr2, v1, size); + } else { + // Cache hit, inhibited caching do not prevent read hits. + v1 = c1->data[lws1]; +#if 0 + uae_cache_check(addr, &v1, c1, lws1, size); #endif - return v1; - } else if (size == 2 && aligned == 0) { - if ((regs.cacr & 0x1100) == 0x1100 && lws1 == 0 && !c1->valid[1] && !c1->valid[2] && !c1->valid[3] && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) { - // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram - c1->data[1] = get_long (addr + 4); - c1->data[2] = get_long (addr + 8); - c1->data[3] = get_long (addr + 12); - do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c1->data[3]); - c1->valid[1] = c1->valid[2] = c1->valid[3] = true; } + + // only one long fetch needed? + if (width + offset <= 32) { + out = v1 >> (32 - (offset + width)); + out &= mask[size]; #if VALIDATE_68030_DATACACHE - validate_dcache030_read(addr2, v1, size); - validate_dcache030(); -#endif - return v1; - } - // no, need another one - addr += 4; - c2 = getcache030 (dcaches030, addr, &tag2, &lws2); - if (!c2->valid[lws2] || c2->tag != tag2) { - v2 = currprefs.cpu_memory_cycle_exact ? mem_access_delay_long_read_ce020 (addr) : get_long (addr); - update_cache030 (c2, v2, tag2, lws2); + 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) { + if (mmu030_cache_inhibit || !candcache030(addr)) + goto end; + if (!dcache030_check(addr, false, 2)) + goto end; + v2 = dcache030_lget(addr); + update_dcache030 (c2, v2, tag2, fc, lws2); + if (!mmu030_cache_inhibit && (regs.cacr & 0x1100) == 0x1100) + dcache030_maybe_burst(addr, c2, lws2); #if VALIDATE_68030_DATACACHE - validate_dcache030(); + validate_dcache030(); #endif - } else { - v2 = c2->data[lws2]; - if (uae_boot_rom_type > 0) { - uae_u32 tv = get_long(addr); - if (tv != v2) { - write_log (_T("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n"), - size, aligned, addr, tv, v2, tag2, lws2, M68K_GETPC); - v2 = tv; - } - } - } - - uae_u32 ov; - if (size == 1 && aligned == 3) { - ov = (v1 << 8) | (v2 >> 24); - } else if (size == 2 && aligned == 1) { - ov = (v1 << 8) | (v2 >> 24); - } else if (size == 2 && aligned == 2) { - ov = (v1 << 16) | (v2 >> 16); - } else if (size == 2 && aligned == 3) { - ov = (v1 << 24) | (v2 >> 8); - } else { - write_log (_T("dcache030 weirdness!?\n")); - ov = 0; - } + } else { + v2 = c2->data[lws2]; +#if 0 + uae_cache_check(addr, &v2, c2, lws2, size); +#endif + } + + 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(addr2, ov, size); + validate_dcache030_read(addr_o, out, size); #endif - return ov; + return out; + + } +end: + // read from memory, data cache is disabled or inhibited. + if (size == 2) + return dcache030_lget (addr_o); + else if (size == 1) + return dcache030_wget (addr_o); + else + return dcache030_bget (addr_o); +} + +uae_u32 read_dcache030_mmu(uaecptr addr, uae_u32 size) +{ + return read_dcache030(addr, size, (regs.s ? 4 : 0) | 1); +} +void write_dcache030_mmu(uaecptr addr, uae_u32 val, uae_u32 size) +{ + write_dcache030(addr, val, size, (regs.s ? 4 : 0) | 1); +} + +uae_u32 read_dcache030_lrmw_mmu(uaecptr addr, uae_u32 size) +{ + mmu030_cache_inhibit = 1; + return read_dcache030(addr, size, (regs.s ? 4 : 0) | 1); +} +void write_dcache030_lrmw_mmu(uaecptr addr, uae_u32 val, uae_u32 size) +{ + mmu030_cache_inhibit = 1; + write_dcache030(addr, val, size, (regs.s ? 4 : 0) | 1); +} + +static void do_access_or_bus_error(uaecptr pc, uaecptr pcnow) +{ + // TODO: handle external bus errors + if (!currprefs.mmu_model) + return; + if (pc != 0xffffffff) + regs.instruction_pc = pc; + mmu030_opcode = -1; + mmu030_page_fault(pcnow, true, -1, 0); } static uae_u32 get_word_ce030_prefetch_2 (int o) @@ -8694,23 +8981,30 @@ static uae_u32 get_word_ce030_prefetch_2 (int o) uae_u32 pc = m68k_getpc () + o; uae_u32 v; - if (pc & 2) { - v = regs.prefetch020[0] & 0xffff; + v = regs.prefetch020[0]; + regs.prefetch020[0] = regs.prefetch020[1]; + regs.prefetch020[1] = regs.prefetch020[2]; #if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1], pc); + pipeline_020(pc); #endif - regs.prefetch020[0] = regs.prefetch020[1]; + if (pc & 2) { // branch instruction detected in pipeline: stop fetches until branch executed. if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) { fill_icache030 (pc + 2 + 4); - regs.prefetch020[1] = regs.cacheholdingdata020; + } else { + if (regs.cacheholdingdata_valid > 0) + regs.cacheholdingdata_valid++; } + regs.prefetch020[2] = regs.cacheholdingdata020 >> 16; } else { - v = regs.prefetch020[0] >> 16; -#if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1] >> 16, pc); -#endif + pc += 4; + // cacheholdingdata020 may be invalid if RTE from bus error + if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) { + fill_icache030 (pc); + } + regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020; } + regs.db = regs.prefetch020[0]; do_cycles_ce020_internal (2); return v; } @@ -8724,28 +9018,39 @@ uae_u32 get_word_ce030_prefetch_opcode (int o) return get_word_ce030_prefetch_2(o); } -uae_u32 get_word_030_prefetch(int o) +uae_u32 get_word_030_prefetch (int o) { - uae_u32 pc = m68k_getpc() + o; + uae_u32 pc = m68k_getpc () + o; uae_u32 v; - if (pc & 2) { - v = regs.prefetch020[0] & 0xffff; + v = regs.prefetch020[0]; + regs.prefetch020[0] = regs.prefetch020[1]; + regs.prefetch020[1] = regs.prefetch020[2]; + if (!regs.prefetch020_valid[1]) { + do_access_or_bus_error(0xffffffff, pc); + } #if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1], pc); + pipeline_020(pc); #endif - regs.prefetch020[0] = regs.prefetch020[1]; + if (pc & 2) { // branch instruction detected in pipeline: stop fetches until branch executed. if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) { - fill_icache030(pc + 2 + 4); - regs.prefetch020[1] = regs.cacheholdingdata020; + fill_icache030 (pc + 2 + 4); + } else { + if (regs.cacheholdingdata_valid > 0) + regs.cacheholdingdata_valid++; } + regs.prefetch020[2] = regs.cacheholdingdata020 >> 16; } else { - v = regs.prefetch020[0] >> 16; -#if MORE_ACCURATE_68020_PIPELINE - pipeline_020(regs.prefetch020[1] >> 16, pc); -#endif + pc += 4; + // cacheholdingdata020 may be invalid if RTE from bus error + if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) { + fill_icache030 (pc); + } + regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020; } + regs.prefetch020_valid[2] = regs.cacheholdingdata_valid; + regs.db = regs.prefetch020[0]; return v; } @@ -9150,69 +9455,165 @@ void check_t0_trace(void) } } -void fill_prefetch_030_ntx (void) +static void reset_pipeline_state(void) +{ +#if MORE_ACCURATE_68020_PIPELINE + regs.pipeline_pos = 0; + regs.pipeline_stop = 0; + regs.pipeline_r8[0] = regs.pipeline_r8[1] = -1; +#endif +} + +static int add_prefetch_030(int idx, uae_u16 w, uaecptr pc) +{ + regs.prefetch020[0] = regs.prefetch020[1]; + regs.prefetch020_valid[0] = regs.prefetch020_valid[1]; + regs.prefetch020[1] = regs.prefetch020[2]; + regs.prefetch020_valid[1] = regs.prefetch020_valid[2]; + regs.prefetch020[2] = w; + regs.prefetch020_valid[2] = regs.cacheholdingdata_valid; + +#if MORE_ACCURATE_68020_PIPELINE + if (idx >= 1) { + pipeline_020(pc); + } +#endif + + if (!regs.prefetch020_valid[2]) { + if (idx == 0 || !regs.pipeline_stop) { + // Pipeline refill and first opcode word is invalid? + // Generate previously detected bus error/MMU fault + do_access_or_bus_error(pc, pc + idx * 2); + } + } + return idx + 1; +} + +void fill_prefetch_030_ntx(void) { uaecptr pc = m68k_getpc (); uaecptr pc2 = pc; + int idx = 0; + pc &= ~3; - regs.pipeline_pos = 0; - regs.pipeline_stop = 0; + mmu030_idx = 0; + reset_pipeline_state(); + regs.cacheholdingdata_valid = 1; + regs.cacheholdingaddr020 = 0xffffffff; + regs.prefetch020_valid[0] = regs.prefetch020_valid[1] = regs.prefetch020_valid[2] = 0; - fill_icache030 (pc); + fill_icache030(pc); if (currprefs.cpu_cycle_exact) do_cycles_ce020_internal(2); - regs.prefetch020[0] = regs.cacheholdingdata020; + if (pc2 & 2) { + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2); + } else { + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2); + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2); + } - fill_icache030 (pc + 4); + fill_icache030(pc + 4); if (currprefs.cpu_cycle_exact) do_cycles_ce020_internal(2); - regs.prefetch020[1] = regs.cacheholdingdata020; - -#if MORE_ACCURATE_68020_PIPELINE if (pc2 & 2) { - pipeline_020(regs.prefetch020[0], pc); - pipeline_020(regs.prefetch020[1] >> 16, pc); + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2); + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2); } else { - pipeline_020(regs.prefetch020[0] >> 16, pc); - pipeline_020(regs.prefetch020[0], pc); + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2); } + + if (currprefs.cpu_cycle_exact) + regs.irc = get_word_ce030_prefetch_opcode (0); + else + regs.irc = get_word_030_prefetch (0); +} + +void fill_prefetch_030_ntx_continue (void) +{ + uaecptr pc = m68k_getpc (); + uaecptr pc_orig = pc; + int idx = 0; + + mmu030_idx = 0; + reset_pipeline_state(); + regs.cacheholdingdata_valid = 1; + regs.cacheholdingaddr020 = 0xffffffff; + + for (int i = 2; i >= 0; i--) { + if (!regs.prefetch020_valid[i]) + break; +#if MORE_ACCURATE_68020_PIPELINE + if (idx >= 1) { + pipeline_020(pc); + } #endif + pc += 2; + idx++; + } + + if (idx < 3 && !regs.pipeline_stop) { + uaecptr pc2 = pc; + pc &= ~3; + + fill_icache030(pc); + if (currprefs.cpu_cycle_exact) + do_cycles_ce020_internal(2); + if (pc2 & 2) { + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig); + } else { + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig); + if (idx < 3) + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig); + } + + if (idx < 3) { + fill_icache030(pc + 4); + if (currprefs.cpu_cycle_exact) + do_cycles_ce020_internal(2); + if (pc2 & 2) { + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig); + if (idx < 3) + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig); + } else { + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig); + } + } + } if (currprefs.cpu_cycle_exact) 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) { uaecptr pc = m68k_getpc (); uaecptr pc2 = pc; + int idx = 0; + pc &= ~3; - uae_u32 (*fetch)(uaecptr) = currprefs.cpu_memory_cycle_exact ? mem_access_delay_longi_read_ce020 : get_longi; - regs.pipeline_pos = 0; - regs.pipeline_stop = 0; - regs.pipeline_r8[0] = regs.pipeline_r8[1] = -1; + reset_pipeline_state(); - fill_icache020 (pc, fetch, true); + fill_icache020 (pc, true); if (currprefs.cpu_cycle_exact) do_cycles_ce020_internal(2); - regs.prefetch020[0] = regs.cacheholdingdata020; + if (pc2 & 2) { + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc); + } else { + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc); + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc); + } - fill_icache020 (pc + 4, fetch, true); + fill_icache020 (pc + 4, true); if (currprefs.cpu_cycle_exact) do_cycles_ce020_internal(2); - regs.prefetch020[1] = regs.cacheholdingdata020; - -#if MORE_ACCURATE_68020_PIPELINE if (pc2 & 2) { - pipeline_020(regs.prefetch020[0], pc); - pipeline_020(regs.prefetch020[1] >> 16, pc); + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc); + idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc); } else { - pipeline_020(regs.prefetch020[0] >> 16, pc); - pipeline_020(regs.prefetch020[0], pc); + idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc); } -#endif if (currprefs.cpu_cycle_exact) regs.irc = get_word_ce020_prefetch_opcode (0); @@ -9254,7 +9655,7 @@ void fill_prefetch_030(void) void fill_prefetch (void) { - regs.pipeline_pos = 0; + reset_pipeline_state(); if (currprefs.cachesize) return; if (!currprefs.cpu_compatible) diff --git a/od-win32/sysconfig.h b/od-win32/sysconfig.h index 9af217ed..3d33d0e6 100644 --- a/od-win32/sysconfig.h +++ b/od-win32/sysconfig.h @@ -65,6 +65,7 @@ #define CPUEMU_31 /* Aranym 68040 MMU */ #define CPUEMU_32 /* Previous 68030 MMU */ #define CPUEMU_33 /* 68060 MMU */ +#define CPUEMU_34 /* 68030 MMU + cache */ #define CPUEMU_40 /* generic 680x0 with JIT direct memory access */ #define CPUEMU_50 /* generic 680x0 with indirect memory access */ #define ACTION_REPLAY /* Action Replay 1/2/3 support */ -- 2.47.3