]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
68030 MMU mode cache enable/cache inhibit emulation improved. 68040/060 MMU mode...
authorToni Wilen <twilen@winuae.net>
Fri, 28 Jul 2017 14:56:25 +0000 (17:56 +0300)
committerToni Wilen <twilen@winuae.net>
Fri, 28 Jul 2017 14:56:25 +0000 (17:56 +0300)
cpummu30.cpp
include/cpummu.h
include/cpummu030.h
include/memory.h
include/newcpu.h
memory.cpp
newcpu.cpp

index 4e2fab6f64e27290fdf744babf047fcaf3d0be0b..91043cbd201cc1eeabb4fd281d8948d7b90f6a02 100644 (file)
@@ -69,7 +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;
+uae_u8 mmu030_cache_state;
 struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS];
 
 #if MMU_DPAGECACHE030
@@ -100,7 +100,7 @@ typedef struct {
         uaecptr addr;
         bool modified;
         bool write_protect;
-        bool cache_inhibit;
+        uae_u8 cache_inhibit;
         bool bus_error;
     } physical;
     
@@ -149,7 +149,7 @@ static struct {
     uae_u16 status;
 
 #if MMU_IPAGECACHE030
-       int mmu030_cache_inhibit;
+       uae_u8 mmu030_cache_state;
 #if MMU_DIRECT_ACCESS
        uae_u8 *mmu030_last_physical_address_real;
 #else
@@ -699,12 +699,12 @@ static int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write)
     tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
     if (tt0&TT_OK_MATCH) {
                if (tt0_030&TT_CI)
-               mmu030_cache_inhibit = 1;
+               mmu030_cache_state = CACHE_DISABLE_MMU;
        }
     tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
     if (tt1&TT_OK_MATCH) {
                if (tt0_030&TT_CI)
-               mmu030_cache_inhibit = 1;
+               mmu030_cache_state = CACHE_DISABLE_MMU;
     }
     
     return (tt0|tt1);
@@ -1196,7 +1196,7 @@ uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level) {
         bool super = (fc&4) ? true : false;
         bool super_violation = false;
         bool write_protected = false;
-        bool cache_inhibit = false;
+        uae_u8 cache_inhibit = CACHE_ENABLE_ALL;
         bool descr_modified = false;
         
         mmu030.status = 0; /* Reset status */
@@ -1483,7 +1483,7 @@ uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level) {
             mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;
 
             /* check if caching is inhibited */
-            cache_inhibit = descr[0]&DESCR_CI ? true : false;
+            cache_inhibit = (descr[0]&DESCR_CI) ? CACHE_DISABLE_MMU : CACHE_ENABLE_ALL;
             
             /* check for the modified bit and set it in the status register */
             mmu030.status |= (descr[0]&DESCR_M) ? MMUSR_MODIFIED : 0;
@@ -1779,7 +1779,7 @@ static uaecptr mmu030_put_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
         return 0;
     }
 
-       mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit;
+       mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
 
        mmu030_add_data_write_cache(addr, physical_addr, fc);
 
@@ -1801,7 +1801,7 @@ static uaecptr mmu030_get_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
         return 0;
     }
 
-       mmu030_cache_inhibit = mmu030.atc[l].physical.cache_inhibit;
+       mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
        
        mmu030_add_data_read_cache(addr, physical_addr, fc);
 
@@ -1824,7 +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;
+       mmu030.mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
 #if MMU_DIRECT_ACCESS
        mmu030.mmu030_last_physical_address_real = get_real_address(physical_addr);
 #else
@@ -1833,7 +1833,7 @@ 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;
+       mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
 
        return physical_addr + page_index;
 }
@@ -1927,13 +1927,15 @@ static int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
 
 STATIC_INLINE void cacheablecheck(uaecptr addr)
 {
-       if (!ce_cachable[addr >> 16] && !mmu030_cache_inhibit)
-               mmu030_cache_inhibit = -1; // CIN active
+       if (mmu030_cache_state == CACHE_ENABLE_ALL) {
+               // MMU didn't inhibit caches, use hardware cache state
+               mmu030_cache_state = ce_cachable[addr >> 16];
+       }
 }
 
 void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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;
@@ -1958,7 +1960,7 @@ void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc)
 
 void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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;
@@ -1983,7 +1985,7 @@ void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc)
 
 void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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;
@@ -2009,7 +2011,7 @@ void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc)
 
 uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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;
@@ -2034,7 +2036,7 @@ uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc)
 
 uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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;
@@ -2059,7 +2061,7 @@ uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc)
 
 uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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;
@@ -2091,14 +2093,14 @@ 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;
+               mmu030_cache_state = mmu030.mmu030_cache_state;
                return x_phys_get_ilong(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
 #endif
        }
        mmu030.mmu030_last_logical_address = 0xffffffff;
 #endif
 
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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) {
@@ -2108,6 +2110,7 @@ uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc)
                        addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_L);
                }
        }
+       cacheablecheck(addr);
        return x_phys_get_ilong(addr);
 }
 
@@ -2119,14 +2122,14 @@ 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;
+               mmu030_cache_state = mmu030.mmu030_cache_state;
                return x_phys_get_iword(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
 #endif
        }
        mmu030.mmu030_last_logical_address = 0xffffffff;
 #endif
 
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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) {
@@ -2136,13 +2139,14 @@ uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
                        addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_W);
                }
        }
+       cacheablecheck(addr);
        return x_phys_get_iword(addr);
 }
 
 /* Not commonly used access function */
 void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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) {
@@ -2165,7 +2169,7 @@ 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)
 {
-       mmu030_cache_inhibit = 0;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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) {
@@ -2187,7 +2191,7 @@ 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;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
 
        if (flags & MMU030_SSW_RM) {
                return mmu030_get_generic_lrmw(addr, fc, size, flags);
@@ -2212,9 +2216,10 @@ 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_u8 uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size)
 {
        uae_u32 fc = regs.fc030;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
        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);
@@ -2226,8 +2231,10 @@ bool uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size)
                        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
                }
        }
-       cacheablecheck(addr);
-       return mmu030_cache_inhibit == 0;
+       // MMU inhibited
+       if (mmu030_cache_state != CACHE_ENABLE_ALL)
+               return mmu030_cache_state;
+       return ce_cachable[addr >> 16];
 }
 
 /* Locked RMW is rarely used */
index a7cde2d0b7ff8457f1f6d216029c574596354b19..a60baf75d25a7ab5500ca73f65e47b3475c5d74f 100644 (file)
@@ -271,7 +271,7 @@ static ALWAYS_INLINE uae_u32 mmu_get_ilong(uaecptr addr, int size)
                }
 #endif
        }
-       return phys_get_long(addr);
+       return x_phys_get_ilong(addr);
 }
 
 static ALWAYS_INLINE uae_u16 mmu_get_iword(uaecptr addr, int size)
@@ -293,7 +293,7 @@ static ALWAYS_INLINE uae_u16 mmu_get_iword(uaecptr addr, int size)
                }
 #endif
        }
-       return phys_get_word(addr);
+       return x_phys_get_iword(addr);
 }
 
 
index 9bd41f4c19ba1e2cdda51b890492b981ffd75163..3e3baa33acbcc94626269cb7788e4ed4ba8397c0 100644 (file)
@@ -23,7 +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;
+extern uae_u8 mmu030_cache_state, mmu030_cache_state_default;
 
 #define MMU030_STATEFLAG1_FMOVEM 0x2000
 #define MMU030_STATEFLAG1_MOVEM1 0x4000
@@ -204,7 +204,7 @@ 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);
+uae_u8 uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size);
 
 #define ACCESS_CHECK_PUT \
        if (!mmu030_ad[mmu030_idx].done) { \
@@ -663,7 +663,6 @@ STATIC_INLINE uae_u32 get_iword_mmu030c_state (int 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;
index 1666db6cf5edabe75a117c0fb0f23343ed16773f..951b4ac2b86d8e47745bd11aa284ddab8b281d7f 100644 (file)
@@ -166,6 +166,14 @@ struct autoconfig_info
 #define CE_MEMBANK_CHIP32 2
 #define CE_MEMBANK_CIA 3
 #define CE_MEMBANK_FAST16 4
+//#define CE_MEMBANK_FAST16_EXTRA_ACCURACY 5
+#define CACHE_ENABLE_DATA 0x01
+#define CACHE_ENABLE_DATA_BURST 0x02
+#define CACHE_ENABLE_INS 0x80
+#define CACHE_ENABLE_INS_BURST 0x40
+#define CACHE_ENABLE_BOTH (CACHE_ENABLE_DATA | CACHE_ENABLE_INS)
+#define CACHE_ENABLE_ALL (CACHE_ENABLE_BOTH | CACHE_ENABLE_INS_BURST | CACHE_ENABLE_DATA_BURST)
+#define CACHE_DISABLE_MMU 0x10
 extern uae_u8 ce_banktype[65536], ce_cachable[65536];
 
 #define MEMORY_LGET(name) \
index 374a7c2a55015239ac65a7abc53d62874d41204a..f3699f5b66e2dce9afa2948a12085e66c3b879da 100644 (file)
@@ -125,6 +125,7 @@ struct cache030
 };
 
 #define CACHESETS040 64
+#define CACHESETS060 128
 #define CACHELINES040 4
 struct cache040
 {
@@ -223,6 +224,8 @@ struct regstruct
        int pipeline_stop;
        uae_u8 fc030;
 
+       uae_u32 prefetch040[CPU_PIPELINE_MAX];
+
        int ce020endcycle;
        int ce020startcycle;
        int ce020prefetchendcycle;
index 81eb6588fe5455ced520fef519c58c0e9e8573bf..b75e5813d35fdef4ed2cd3050cf52182d91a6bda 100644 (file)
@@ -1822,7 +1822,7 @@ static void add_shmmaps (uae_u32 start, addrbank *what)
        y = xmalloc (shmpiece, 1);
        *y = *x;
        base = ((uae_u8 *) NATMEM_OFFSET) + start;
-       y->native_address = (uae_u8*)uae_shmat (what, y->id, base, 0);
+       y->native_address = (uae_u8*)uae_shmat (what, y->id, base, 0, NULL);
        if (y->native_address == (void *) -1) {
                write_log (_T("NATMEM: Failure to map existing at %08x (%p)\n"), start, base);
                dumplist ();
@@ -1902,7 +1902,7 @@ bool mapped_malloc (addrbank *ab)
                return ab->baseaddr != NULL;
        }
        if (!(ab->flags & ABFLAG_NOALLOC)) {
-               answer = uae_shmat (ab, id, 0, 0);
+               answer = uae_shmat (ab, id, NULL, 0, &md);
                uae_shmctl (id, UAE_IPC_RMID, NULL);
        } else {
                write_log(_T("MMAN: mapped_malloc using existing baseaddr %p\n"), ab->baseaddr);
@@ -2216,18 +2216,25 @@ static void fill_ce_banks (void)
        } else {
                memset (ce_banktype, CE_MEMBANK_FAST32, sizeof ce_banktype);
        }
-       // data cachable regions (2 = burst supported)
-       memset(ce_cachable, 0, sizeof ce_cachable);
-       memset(ce_cachable + (0x00c00000 >> 16), 1, currprefs.bogomem_size >> 16);
+
+       memset(ce_cachable, CACHE_ENABLE_INS, sizeof ce_cachable);
+       memset(ce_cachable + (0x00f80000 >> 16), CACHE_ENABLE_BOTH, 524288 >> 16);
+       memset(ce_cachable + (0x00c00000 >> 16), CACHE_ENABLE_BOTH, currprefs.bogomem_size >> 16);
        for (int i = 0; i < MAX_RAM_BOARDS; i++) {
                if (fastmem_bank[i].start != 0xffffffff)
-                       memset(ce_cachable + (fastmem_bank[i].start >> 16), 1 | 2, currprefs.fastmem[i].size >> 16);
+                       memset(ce_cachable + (fastmem_bank[i].start >> 16), CACHE_ENABLE_BOTH, currprefs.fastmem[i].size >> 16);
                if (z3fastmem_bank[i].start != 0xffffffff)
-                       memset(ce_cachable + (z3fastmem_bank[i].start >> 16), 1 | 2, currprefs.z3fastmem[i].size >> 16);
+                       memset(ce_cachable + (z3fastmem_bank[i].start >> 16), CACHE_ENABLE_ALL, currprefs.z3fastmem[i].size >> 16);
+       }
+       memset(ce_cachable + (a3000hmem_bank.start >> 16), CACHE_ENABLE_ALL, currprefs.mbresmem_high_size >> 16);
+       memset(ce_cachable + (a3000lmem_bank.start >> 16), CACHE_ENABLE_ALL, currprefs.mbresmem_low_size >> 16);
+       memset(ce_cachable + (mem25bit_bank.start >> 16), CACHE_ENABLE_ALL, currprefs.mem25bit_size >> 16);
+
+       if (uae_boot_rom_type > 0) {
+               for (int i = 0; i < sizeof(ce_cachable); i++) {
+                       ce_cachable[i] &= ~(CACHE_ENABLE_DATA | CACHE_ENABLE_DATA_BURST);
+               }
        }
-       memset(ce_cachable + (a3000hmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_high_size >> 16);
-       memset(ce_cachable + (a3000lmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_low_size >> 16);
-       memset(ce_cachable + (mem25bit_bank.start >> 16), 1 | 2, currprefs.mem25bit_size >> 16);
 
        addrbank *ab = &get_mem_bank(0);
        if (ab && (ab->flags & ABFLAG_CHIPRAM)) {
index 9de571a831b4e69dd730a261d8b8198428b07ca6..ce5f30ecadd7eb2a95f0574fc05ba409446501b6 100644 (file)
@@ -78,7 +78,7 @@ int m68k_pc_indirect;
 bool m68k_interrupt_delay;
 static bool m68k_reset_delay;
 
-static bool dcache_complete_inhibit;
+static int cachesets04060, cachesets04060minus1;
 
 static int cpu_prefs_changed_flag;
 
@@ -116,8 +116,8 @@ static struct cache020 caches020[CACHELINES020];
 static struct cache030 icaches030[CACHELINES030];
 static struct cache030 dcaches030[CACHELINES030];
 static int icachelinecnt, dcachelinecnt;
-static struct cache040 icaches040[CACHESETS040];
-static struct cache040 dcaches040[CACHESETS040];
+static struct cache040 icaches040[CACHESETS060];
+static struct cache040 dcaches040[CACHESETS060];
 
 static int fallback_cpu_model, fallback_mmu_model, fallback_fpu_model;
 static bool fallback_cpu_compatible, fallback_cpu_address_space_24;
@@ -761,16 +761,16 @@ 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)
+static uae_u8 dcache030_check_nommu(uaecptr addr, bool write, uae_u32 size)
 {
-       return true;
+       return ce_cachable[addr >> 16];
 }
 
 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 uae_u8 (*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);
@@ -1225,7 +1225,7 @@ static void set_x_funcs (void)
        dcache030_lget = get_long;
        dcache030_wget = get_word;
        dcache030_bget = get_byte;
-       dcache030_check = dcache030_check_dummy;
+       dcache030_check = dcache030_check_nommu;
        if (currprefs.cpu_cycle_exact) {
                icache_fetch = mem_access_delay_longi_read_ce020;
        }
@@ -1341,7 +1341,7 @@ void flush_cpu_caches(bool force)
                icachelinecnt = 0;
                dcachelinecnt = 0;
                if (doflush) {
-                       for (int i = 0; i < CACHESETS040; i++) {
+                       for (int i = 0; i < CACHESETS060; i++) {
                                icaches040[i].valid[0] = 0;
                                icaches040[i].valid[1] = 0;
                                icaches040[i].valid[2] = 0;
@@ -1397,7 +1397,7 @@ static uae_u32 REGPARAM2 op_unimpl_1 (uae_u32 opcode)
        return 4;
 }
 
-// generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu, mm+more compatible
+// generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu, mmu+more compatible
 static const struct cputbl *cputbls[6][7] =
 {
        // 68000
@@ -1409,9 +1409,9 @@ static const struct cputbl *cputbls[6][7] =
        // 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_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, NULL },
+       { 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_31_ff },
        // 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, NULL }
+       { 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_33_ff }
 };
 
 static void build_cpufunctbl (void)
@@ -3309,9 +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;
+       mmu030_cache_state = CACHE_ENABLE_ALL;
+       cachesets04060 = currprefs.cpu_model == 68060 ? CACHESETS060 : CACHESETS040;
+       cachesets04060minus1 = cachesets04060 - 1;
        if (currprefs.mmu_model >= 68040) {
                mmu_reset ();
                mmu_set_tc (regs.tcr);
@@ -7395,12 +7395,18 @@ uae_u8 *restore_cpu (uae_u8 *src)
                        regs.cacheholdingaddr020 = restore_u32 ();
                        regs.cacheholdingdata020 = restore_u32 ();
                        if (flags & 0x20000000) {
-                               // 2.7.0 new
-                               for (int i = 0; i < CPU_PIPELINE_MAX; i++)
-                                       regs.prefetch020[i] = restore_u32 ();
+                               if (flags & 0x4000000) {
+                                       // 3.6 new (back to 16 bits)
+                                       for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
+                                               uae_u32 v = restore_u32();
+                                               regs.prefetch020[i] = v >> 16;
+                                               regs.prefetch020_valid[i] = (v & 1) != 0;
+                                       }
+                               }
                        } else {
                                for (int i = 0; i < CPU_PIPELINE_MAX; i++)
                                        regs.prefetch020[i] = restore_u16 ();
+                                       regs.prefetch020_valid[i] = false;
                        }
                } else if (model == 68030) {
                        for (int i = 0; i < CACHELINES030; i++) {
@@ -7420,11 +7426,21 @@ uae_u8 *restore_cpu (uae_u8 *src)
                        regs.prefetch020addr = restore_u32 ();
                        regs.cacheholdingaddr020 = restore_u32 ();
                        regs.cacheholdingdata020 = restore_u32 ();
-                       for (int i = 0; i < CPU_PIPELINE_MAX; i++)
-                               regs.prefetch020[i] = restore_u32 ();
+                       if (flags & 0x4000000) {
+                               for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
+                                       uae_u32 v = restore_u32();
+                                       regs.prefetch020[i] = v >> 16;
+                                       regs.prefetch020_valid[i] = (v & 1) != 0;
+                               }
+                       } else {
+                               for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
+                                       regs.prefetch020[i] = restore_u32 ();
+                                       regs.prefetch020_valid[i] = false;
+                               }
+                       }
                } else if (model == 68040) {
                        if (flags & 0x8000000) {
-                               for (int i = 0; i < CACHESETS040; i++) {
+                               for (int i = 0; i < ((model == 68060 && (flags & 0x4000000)) ? CACHESETS060 : CACHESETS040); i++) {
                                        for (int j = 0; j < CACHELINES040; j++) {
                                                icaches040[i].data[j][0] = restore_u32();
                                                icaches040[i].data[j][1] = restore_u32();
@@ -7438,7 +7454,7 @@ uae_u8 *restore_cpu (uae_u8 *src)
                                regs.cacheholdingaddr020 = restore_u32();
                                regs.cacheholdingdata020 = restore_u32();
                                for (int i = 0; i < CPU_PIPELINE_MAX; i++)
-                                       regs.prefetch020[i] = restore_u32();
+                                       regs.prefetch040[i] = restore_u32();
                        }
                }
                if (model >= 68020) {
@@ -7682,7 +7698,7 @@ uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
                dstbak = dst = xmalloc (uae_u8, 1000 + 20000);
        model = currprefs.cpu_model;
        save_u32 (model);                                       /* MODEL */
-       save_u32(0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 | 0x8000000 |(currprefs.address_space_24 ? 1 : 0)); /* FLAGS */
+       save_u32(0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 | 0x8000000 | 0x4000000 | (currprefs.address_space_24 ? 1 : 0)); /* FLAGS */
        for (i = 0;i < 15; i++)
                save_u32 (regs.regs[i]);                /* D0-D7 A0-A6 */
        save_u32 (m68k_getpc ());                       /* PC */
@@ -7751,7 +7767,7 @@ uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
                save_u32 (regs.cacheholdingaddr020);
                save_u32 (regs.cacheholdingdata020);
                for (int i = 0; i < CPU_PIPELINE_MAX; i++)
-                       save_u32 (regs.prefetch020[i]);
+                       save_u32 ((regs.prefetch020[i] << 16) | (regs.prefetch020_valid[i] ? 1 : 0));
        } else if (model == 68030) {
                for (int i = 0; i < CACHELINES030; i++) {
                        for (int j = 0; j < 4; j++) {
@@ -7773,7 +7789,7 @@ uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
                for (int i = 0; i < CPU_PIPELINE_MAX; i++)
                        save_u32 (regs.prefetch020[i]);
        } else if (model >= 68040) {
-               for (int i = 0; i < CACHESETS040; i++) {
+               for (int i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
                        for (int j = 0; j < CACHELINES040; j++) {
                                save_u32(icaches040[i].data[j][0]);
                                save_u32(icaches040[i].data[j][1]);
@@ -7787,7 +7803,7 @@ uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
                save_u32(regs.cacheholdingaddr020);
                save_u32(regs.cacheholdingdata020);
                for (int i = 0; i < CPU_PIPELINE_MAX; i++)
-                       save_u32(regs.prefetch020[i]);
+                       save_u32(regs.prefetch040[i]);
        }
        if (currprefs.cpu_model >= 68020) {
                save_u32 (0); //save_u32 (regs.ce020memcycles);
@@ -8637,12 +8653,12 @@ static void fill_icache030 (uae_u32 addr)
                return;
        } ENDTRY
 
-       if (!mmu030_cache_inhibit) {
+       if (mmu030_cache_state & CACHE_ENABLE_INS) {
                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) {
+               if ((mmu030_cache_state & CACHE_ENABLE_INS_BURST) && (regs.cacr & 0x11) == 0x11 && (c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1)) {
                        // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
                        int i;
                        for (i = 0; i < 4; i++) {
@@ -8651,9 +8667,9 @@ static void fill_icache030 (uae_u32 addr)
                        }
                        uaecptr baddr = addr & ~15;
                        if (currprefs.mmu_model) {
-                               if (currprefs.cpu_cycle_exact)
-                                       do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
                                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;
@@ -8679,12 +8695,6 @@ static void fill_icache030 (uae_u32 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)
 {
@@ -8744,7 +8754,7 @@ static void write_dcache030x(uaecptr addr, uae_u32 val, uae_u32 size, uae_u32 fc
                // All writes ignore external CIIN signal.
 
                if (width == 32 && offset == 0 && wa) {
-                       if (mmu030_cache_inhibit <= 0) {
+                       if (!(mmu030_cache_state & CACHE_DISABLE_MMU)) {
                                update_dcache030(c1, val, tag1, fc, lws1);
 #if VALIDATE_68030_DATACACHE
                                validate_dcache030();
@@ -8857,7 +8867,7 @@ 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?
+       if (regs.cacr & 0x100) { // data cache enabled?
                static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
                struct cache030 *c1, *c2;
                int lws1, lws2;
@@ -8871,16 +8881,14 @@ uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
                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))
+                       uae_u8 cs = dcache030_check(addr_o, false, size);
+                       if (!(cs & CACHE_ENABLE_DATA))
                                goto end;
                        v1 = dcache030_lget(addr);
                        update_dcache030 (c1, v1, tag1, fc, lws1);
-                       if (!mmu030_cache_inhibit && (regs.cacr & 0x1100) == 0x1100)
+                       if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
                                dcache030_maybe_burst(addr, c1, lws1);
 #if VALIDATE_68030_DATACACHE
                        validate_dcache030();
@@ -8907,13 +8915,12 @@ uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
                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))
+                       uae_u8 cs = dcache030_check(addr, false, 2);
+                       if (!(cs & CACHE_ENABLE_DATA))
                                goto end;
                        v2 = dcache030_lget(addr);
                        update_dcache030 (c2, v2, tag2, fc, lws2);
-                       if (!mmu030_cache_inhibit && (regs.cacr & 0x1100) == 0x1100)
+                       if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
                                dcache030_maybe_burst(addr, c2, lws2);
 #if VALIDATE_68030_DATACACHE
                        validate_dcache030();
@@ -8956,12 +8963,12 @@ void write_dcache030_mmu(uaecptr addr, uae_u32 val, uae_u32 size)
 
 uae_u32 read_dcache030_lrmw_mmu(uaecptr addr, uae_u32 size)
 {
-       mmu030_cache_inhibit = 1;
+       mmu030_cache_state = CACHE_DISABLE_MMU;
        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;
+       mmu030_cache_state = CACHE_DISABLE_MMU;
        write_dcache030(addr, val, size, (regs.s ? 4 : 0) | 1);
 }
 
@@ -9073,51 +9080,47 @@ uae_u32 get_long_icache030(uaecptr addr)
 
 uae_u32 fill_icache040(uae_u32 addr)
 {
-       int index, i, lws;
+       int index, lws;
        uae_u32 tag;
        struct cache040 *c;
        int line;
+       static int lastline; 
 
        if (!(regs.cacr & 0x8000)) {
                uae_u32 addr2 = addr & ~15;
                lws = (addr >> 2) & 3;
                addr &= ~3;
                if (regs.prefetch020addr == addr2)
-                       return regs.prefetch020[lws];
+                       return regs.prefetch040[lws];
                regs.prefetch020addr = addr2;
-               if (currprefs.cpu_memory_cycle_exact) {
-                       regs.prefetch020[0] = mem_access_delay_longi_read_ce020(addr2 +  0);
-                       regs.prefetch020[1] = mem_access_delay_longi_read_ce020(addr2 +  4);
-                       regs.prefetch020[2] = mem_access_delay_longi_read_ce020(addr2 +  8);
-                       regs.prefetch020[3] = mem_access_delay_longi_read_ce020(addr2 + 12);
-               } else {
-                       regs.prefetch020[0] = get_longi(addr2 +  0);
-                       regs.prefetch020[1] = get_longi(addr2 +  4);
-                       regs.prefetch020[2] = get_longi(addr2 +  8);
-                       regs.prefetch020[3] = get_longi(addr2 + 12);
+               regs.prefetch040[0] = icache_fetch(addr2 +  0);
+               regs.prefetch040[1] = icache_fetch(addr2 +  4);
+               regs.prefetch040[2] = icache_fetch(addr2 +  8);
+               regs.prefetch040[3] = icache_fetch(addr2 + 12);
+               if (!currprefs.cpu_memory_cycle_exact)
                        x_do_cycles(4 * cpucycleunit);
-               }
-               return regs.prefetch020[lws];
+               return regs.prefetch040[lws];
        }
 
-       index = (addr >> 4) & (CACHESETS040 - 1);
-       tag = regs.s | (addr & ~((CACHESETS040 << 4) - 1));
+       index = (addr >> 4) & (cachesets04060minus1);
+       tag = regs.s | (addr & ~((cachesets04060 << 4) - 1));
        lws = (addr >> 2) & 3;
        addr &= ~15;
        c = &icaches040[index];
-       for (i = 0; i < CACHELINES040; i++) {
-               if (c->valid[i] && c->tag[i] == tag) {
+       for (int i = 0; i < CACHELINES040; i++) {
+               if (c->valid[lastline] && c->tag[lastline] == tag) {
                        // cache hit
                        icachelinecnt++;
                        x_do_cycles(1 * cpucycleunit);
-                       return c->data[i][lws];
+                       return c->data[lastline][lws];
                }
+               lastline++;
+               lastline &= (CACHELINES040 - 1);
        }
        // cache miss
        if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
                line = (icachelinecnt >> 1) & (CACHELINES040 - 1);
-       }
-       else {
+       } else {
                for (line = 0; line < CACHELINES040; line++) {
                        if (c->valid[line] == false)
                                break;
@@ -9125,18 +9128,12 @@ uae_u32 fill_icache040(uae_u32 addr)
        }
        c->tag[line] = tag;
        c->valid[line] = true;
-       if (currprefs.cpu_memory_cycle_exact) {
-               c->data[line][0] = mem_access_delay_longi_read_ce020(addr +  0);
-               c->data[line][1] = mem_access_delay_longi_read_ce020(addr +  4);
-               c->data[line][2] = mem_access_delay_longi_read_ce020(addr +  8);
-               c->data[line][3] = mem_access_delay_longi_read_ce020(addr + 12);
-       } else {
-               c->data[line][0] = get_longi(addr +  0);
-               c->data[line][1] = get_longi(addr +  4);
-               c->data[line][2] = get_longi(addr +  8);
-               c->data[line][3] = get_longi(addr + 12);
+       c->data[line][0] = icache_fetch(addr +  0);
+       c->data[line][1] = icache_fetch(addr +  4);
+       c->data[line][2] = icache_fetch(addr +  8);
+       c->data[line][3] = icache_fetch(addr + 12);
+       if (!currprefs.cpu_memory_cycle_exact)
                x_do_cycles(4 * cpucycleunit);
-       }
        return c->data[line][lws];
 }