]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
MMU emulation updates, experimental caching.
authorToni Wilen <twilen@winuae.net>
Tue, 11 Jul 2017 18:05:50 +0000 (21:05 +0300)
committerToni Wilen <twilen@winuae.net>
Tue, 11 Jul 2017 18:05:50 +0000 (21:05 +0300)
cpummu.cpp
cpummu30.cpp
include/cpummu.h
include/cpummu030.h
newcpu.cpp

index 489be33efee4dd38b9b9fab982eda10dad3af89d..980cbb6a6072cbbc8f5662efe452b1e92e65b1db 100644 (file)
 
 uae_u32 mmu_is_super;
 uae_u32 mmu_tagmask, mmu_pagemask, mmu_pagemaski;
-struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_WAYS][ATC_SLOTS];
+struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_SLOTS][ATC_WAYS];
 bool mmu_pagesize_8k;
+int mmu_pageshift, mmu_pageshift1m;
 
 int mmu060_state;
 uae_u16 mmu_opcode;
 bool mmu_restart;
 static bool locked_rmw_cycle;
 static bool ismoves;
-bool mmu_ttr_enabled;
+bool mmu_ttr_enabled, mmu_ttr_enabled_ins, mmu_ttr_enabled_data;
 int mmu_atc_ways;
+int way_random;
 
 int mmu040_movem;
 uaecptr mmu040_movem_ea;
 uae_u32 mmu040_move16[4];
 
+#if MMU_ICACHE
+struct mmu_icache mmu_icache_data[MMU_ICACHE_SZ];
+#endif
+#if MMU_IPAGECACHE
+uae_u32 atc_last_ins_laddr, atc_last_ins_paddr;
+#endif
+#if MMU_DPAGECACHE
+struct mmufastcache atc_data_cache_read[MMUFASTCACHE_ENTRIES];
+struct mmufastcache atc_data_cache_write[MMUFASTCACHE_ENTRIES];
+#endif
+
+#if CACHE_HIT_COUNT
+int mmu_ins_hit, mmu_ins_miss;
+int mmu_data_read_hit, mmu_data_read_miss;
+int mmu_data_write_hit, mmu_data_write_miss;
+#endif
+
 static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
 {
        DUNUSED(label);
@@ -104,7 +123,9 @@ void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
 
 void mmu_tt_modified (void)
 {
-       mmu_ttr_enabled = ((regs.dtt0 | regs.dtt1 | regs.itt0 | regs.itt1) & MMU_TTR_BIT_ENABLED) != 0;
+       mmu_ttr_enabled_ins = ((regs.itt0 | regs.itt1) & MMU_TTR_BIT_ENABLED) != 0;
+       mmu_ttr_enabled_data = ((regs.dtt0 | regs.dtt1) & MMU_TTR_BIT_ENABLED) != 0;
+       mmu_ttr_enabled = mmu_ttr_enabled_ins || mmu_ttr_enabled_data;
 }
 
 
@@ -314,14 +335,23 @@ void mmu_dump_tables(void)
 }
 /* }}} */
 
-static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write, uae_u32 *status);
+static void flush_shortcut_cache(void)
+{
+#if MMU_IPAGECACHE
+       atc_last_ins_laddr = mmu_pagemask;
+#endif
+#if MMU_DPAGECACHE
+       memset(&atc_data_cache_read, 0xff, sizeof atc_data_cache_read);
+       memset(&atc_data_cache_write, 0xff, sizeof atc_data_cache_write);
+#endif
+}
 
 static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
 {
        return (super ? 4 : 0) | (data ? 1 : 2);
 }
 
-void mmu_bus_error(uaecptr addr, int fc, bool write, int size, bool rmw, uae_u32 status, bool nonmmu)
+void mmu_bus_error(uaecptr addr, uae_u32 val, int fc, bool write, int size, bool rmw, uae_u32 status, bool nonmmu)
 {
        if (currprefs.mmu_model == 68040) {
                uae_u16 ssw = 0;
@@ -354,6 +384,7 @@ void mmu_bus_error(uaecptr addr, int fc, bool write, int size, bool rmw, uae_u32
                }
 
                regs.wb3_status = write ? 0x80 | (ssw & 0x7f) : 0;
+               regs.wb3_data = val;
                regs.wb2_status = 0;
                if (!write)
                        ssw |= MMU_SSW_RW;
@@ -448,6 +479,7 @@ void mmu_bus_error(uaecptr addr, int fc, bool write, int size, bool rmw, uae_u32
        }
 
        regs.mmu_fault_addr = addr;
+       flush_shortcut_cache();
 
 #if 0
        if (m68k_getpc () == 0x0004B0AC) {
@@ -461,107 +493,86 @@ void mmu_bus_error(uaecptr addr, int fc, bool write, int size, bool rmw, uae_u32
        THROW(2);
 }
 
-void mmu_bus_error_ttr_write_fault(uaecptr addr, bool super, bool data, uae_u32 val, int size, bool rmw)
-{
-       uae_u32 status = 0;
-
-       if (currprefs.mmu_model == 68060) {
-               status |= MMU_FSLW_TTR;
-       }
-       regs.wb3_data = val;
-       mmu_bus_error(addr, mmu_get_fc (super, data), true, size, false, status, false);
-}
-
-
 /*
- * Update the atc line for a given address by doing a mmu lookup.
+ * mmu access is a 4 step process:
+ * if mmu is not enabled just read physical
+ * check transparent region, if transparent, read physical
+ * check ATC (address translation cache), read immediatly if HIT
+ * read from mmu with the long path (and allocate ATC entry if needed)
  */
-static uaecptr mmu_fill_atc(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l, uae_u32 *status)
-{
-       uae_u32 desc;
 
-       *status = 0;
-       SAVE_EXCEPTION;
-       TRY(prb) {
-               desc = mmu_lookup_pagetable(addr, super, write, status);
-#if MMUDEBUG > 2
-               write_log(_T("translate: %x,%u,%u,%u -> %x\n"), addr, super, write, data, desc);
-#endif
-               RESTORE_EXCEPTION;
-       }
-       CATCH(prb) {
-               RESTORE_EXCEPTION;
-               /* bus error during table search */
-               desc = 0;
-               *status = MMU_FSLW_TWE;
-               // goto fail;
-       } ENDTRY
-       if ((desc & 1) && (!super && desc & MMU_MMUSR_S)) {
-               *status |= MMU_FSLW_SP;
-#if MMUDEBUG > 1
-               write_log (_T("MMU: supervisor protected %x\n"), addr);
-#endif
-               l->valid = 0;
-               l->global = 0;
-       } else if ((desc & 1) == 0) {
-               l->valid = 0;
-               l->global = 0;
-       } else {
-               l->valid = 1;
-               l->phys = desc & mmu_pagemaski;
-               l->global = (desc & MMU_MMUSR_G) != 0;
-               l->modified = (desc & MMU_MMUSR_M) != 0;
-               l->write_protect = (desc & MMU_MMUSR_W) != 0;
+/* check if an address matches a ttr */
+static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
+{
+       if (ttr & MMU_TTR_BIT_ENABLED)  {       /* TTR enabled */
+               uae_u8 msb, mask;
+               
+               msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
+               mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
+               
+               if (!(msb & ~mask)) {
+                       
+                       if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
+                               if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
+                                       return TTR_NO_MATCH;
+                               }
+                       }
+                       
+                       return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
+               }
        }
-
-       return desc;
+       return TTR_NO_MATCH;
 }
 
-static ALWAYS_INLINE bool mmu_fill_atc_try(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1, uae_u32 *status)
+int mmu_match_ttr_ins(uaecptr addr, bool super)
 {
-       mmu_fill_atc(addr,super,data,write,l1, status);
-       if (!(l1->valid)) {
-#if MMUDEBUG > 2
-               write_log(_T("MMU: non-resident page (%x,%x)!\n"), addr, regs.pc);
-#endif
-               goto fail;
-       }
-       if (write) {
-               if (l1->write_protect) {
-                       *status |= MMU_FSLW_WP;
-#if MMUDEBUG > 0
-                       write_log(_T("MMU: write protected %x by atc \n"), addr);
-#endif
-                       mmu_dump_atc();
-                       goto fail;
-               }
+       int res;
+       
+       if (!mmu_ttr_enabled_ins)
+               return TTR_NO_MATCH;
+       res = mmu_do_match_ttr(regs.itt0, addr, super);
+       if (res == TTR_NO_MATCH)
+               res = mmu_do_match_ttr(regs.itt1, addr, super);
+       return res;
+}
 
+int mmu_match_ttr(uaecptr addr, bool super, bool data)
+{
+       int res;
+       
+       if (!mmu_ttr_enabled)
+               return TTR_NO_MATCH;
+       if (data) {
+               res = mmu_do_match_ttr(regs.dtt0, addr, super);
+               if (res == TTR_NO_MATCH)
+                       res = mmu_do_match_ttr(regs.dtt1, addr, super);
+       } else {
+               res = mmu_do_match_ttr(regs.itt0, addr, super);
+               if (res == TTR_NO_MATCH)
+                       res = mmu_do_match_ttr(regs.itt1, addr, super);
        }
-       return true;
+       return res;
+}
 
-fail:
-       return false;
+void mmu_bus_error_ttr_write_fault(uaecptr addr, bool super, bool data, uae_u32 val, int size, bool rmw)
+ {
+        uae_u32 status = 0;
+        
+        if (currprefs.mmu_model == 68060) {
+                status |= MMU_FSLW_TTR;
+        }
+       mmu_bus_error(addr, val, mmu_get_fc (super, data), true, size, false, status, false);
 }
 
-uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write)
+int mmu_match_ttr_write(uaecptr addr, bool super, bool data, uae_u32 val, int size, bool rmw)
 {
-       struct mmu_atc_line *l;
-       uae_u32 status = 0;
-
-       // this should return a miss but choose a valid line
-       mmu_user_lookup(addr, super, data, write, &l);
-
-       mmu_fill_atc(addr, super, data, write, l, &status);
-       if (!l->valid || (write && l->write_protect)) {
-#if MMUDEBUG > 2
-               write_log(_T("[MMU] mmu_translate error"));
-#endif
-               mmu_bus_error(addr, mmu_get_fc(super, data), write, 0, false, status, false);
-               return 0;
+       int res = TTR_NO_MATCH;
+       if (mmu_ttr_enabled) {
+               res = mmu_match_ttr(addr, super, data);
        }
-
-    return l->phys | (addr & mmu_pagemask);
-
+       if (res == TTR_NO_WRITE || (res == TTR_NO_MATCH && !regs.mmu_enabled && (regs.tcr & MMU_TCR_DWO)))
+               mmu_bus_error_ttr_write_fault(addr, super, data, val, size, rmw);
+       return res;
 }
 
 /*
@@ -573,92 +584,245 @@ static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool wri
 {
        uae_u32 desc, desc_addr, wp;
        int i;
-
+       
        wp = 0;
        desc = super ? regs.srp : regs.urp;
-
+       
        /* fetch root table descriptor */
        i = (addr >> 23) & 0x1fc;
        desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
-       desc = phys_get_long(desc_addr);
-       if ((desc & 2) == 0) {
+
+       SAVE_EXCEPTION;
+       TRY(prb) {
+               desc = phys_get_long(desc_addr);
+               if ((desc & 2) == 0) {
 #if MMUDEBUG > 1
-               write_log(_T("MMU: invalid root descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
-                               addr, desc_addr, desc);
+                       write_log(_T("MMU: invalid root descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
+                                         addr, desc_addr, desc);
 #endif
-               *status |= MMU_FSLW_PTA;
-               return 0;
-       }
-
-       wp |= desc;
-       if ((desc & MMU_DES_USED) == 0)
-               phys_put_long(desc_addr, desc | MMU_DES_USED);
-
-       /* fetch pointer table descriptor */
-       i = (addr >> 16) & 0x1fc;
-       desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
-       desc = phys_get_long(desc_addr);
-       if ((desc & 2) == 0) {
+                       *status |= MMU_FSLW_PTA;
+                       desc = 0;
+                       goto fail;
+               }
+               
+               wp |= desc;
+               if ((desc & MMU_DES_USED) == 0)
+                       phys_put_long(desc_addr, desc | MMU_DES_USED);
+               
+               /* fetch pointer table descriptor */
+               i = (addr >> 16) & 0x1fc;
+               desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
+               desc = phys_get_long(desc_addr);
+               if ((desc & 2) == 0) {
 #if MMUDEBUG > 1
-               write_log(_T("MMU: invalid ptr descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"), 
-                               addr, desc_addr, desc);
+                       write_log(_T("MMU: invalid ptr descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
+                                         addr, desc_addr, desc);
 #endif
-               *status |= MMU_FSLW_PTB;
-               return 0;
-       }
-       wp |= desc;
-       if ((desc & MMU_DES_USED) == 0)
-               phys_put_long(desc_addr, desc | MMU_DES_USED);
-
-       /* fetch page table descriptor */
-       if (mmu_pagesize_8k) {
-               i = (addr >> 11) & 0x7c;
-               desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i;
-       } else {
-               i = (addr >> 10) & 0xfc;
-               desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i;
-       }
-
-       desc = phys_get_long(desc_addr);
-       if ((desc & 3) == 2) {
-               /* indirect */
-               desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
+                       *status |= MMU_FSLW_PTB;
+                       desc = 0;
+                       goto fail;
+               }
+               wp |= desc;
+               if ((desc & MMU_DES_USED) == 0)
+                       phys_put_long(desc_addr, desc | MMU_DES_USED);
+               
+               /* fetch page table descriptor */
+               if (mmu_pagesize_8k) {
+                       i = (addr >> 11) & 0x7c;
+                       desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i;
+               } else {
+                       i = (addr >> 10) & 0xfc;
+                       desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i;
+               }
+               
                desc = phys_get_long(desc_addr);
-       }
-       if ((desc & 1) == 0) {
+               if ((desc & 3) == 2) {
+                       /* indirect */
+                       desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
+                       desc = phys_get_long(desc_addr);
+               }
+               if ((desc & 1) == 0) {
 #if MMUDEBUG > 2
-               write_log(_T("MMU: invalid page descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
+                       write_log(_T("MMU: invalid page descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
 #endif
-               if ((desc & 3) == 2) {
-                       *status |= MMU_FSLW_IL;
+                       if ((desc & 3) == 2) {
+                               *status |= MMU_FSLW_IL;
 #if MMUDEBUG > 1
-                       write_log(_T("MMU: double indirect descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
-#endif 
-               } else {
-                       *status |= MMU_FSLW_PF;
+                               write_log(_T("MMU: double indirect descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
+#endif
+                       } else {
+                               *status |= MMU_FSLW_PF;
+                       }
+                       goto fail;
                }
-               return desc;
-       }
-
-       desc |= wp & MMU_DES_WP;
-       if (write) {
-               if (desc & MMU_DES_WP) {
+               wp |= desc;
+
+               if (write) {
+                       if ((wp & MMU_DES_WP) || (!super && (desc & MMU_DES_SUPER))) {
+                               // write protect or supervisor violation: MMU_DES_USED only
+                               if ((desc & MMU_DES_USED) == 0) {
+                                       desc |= MMU_DES_USED;
+                                       phys_put_long(desc_addr, desc);
+                               }
+                       } else {
+                               // write: MMU_DES_USED and MMU_DES_MODIFIED
+                               if (((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) != (MMU_DES_USED|MMU_DES_MODIFIED))) {
+                                       desc |= MMU_DES_USED|MMU_DES_MODIFIED;
+                                       phys_put_long(desc_addr, desc);
+                               }
+                       }
+               } else {
+                       // read: MMU_DES_USED only
                        if ((desc & MMU_DES_USED) == 0) {
                                desc |= MMU_DES_USED;
                                phys_put_long(desc_addr, desc);
                        }
-               } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
-                                  (MMU_DES_USED|MMU_DES_MODIFIED)) {
-                       desc |= MMU_DES_USED|MMU_DES_MODIFIED;
-                       phys_put_long(desc_addr, desc);
                }
+
+               desc |= wp & MMU_DES_WP;
+               
+               /* this will cause a bus error exception */
+               if (!super && (desc & MMU_DES_SUPER)) {
+                       *status |= MMU_FSLW_SP;
+               } else if (write && (desc & MMU_DES_WP)) {
+                       *status |= MMU_FSLW_WP;
+               }
+       fail:
+               RESTORE_EXCEPTION;
+       } CATCH(prb) {
+               RESTORE_EXCEPTION;
+               /* bus error during table search */
+               desc = 0;
+               *status = MMU_FSLW_TWE;
+#if MMUDEBUG > 0
+               write_log(_T("MMU: bus error during table search.\n"));
+#endif
+       } ENDTRY
+
+       return desc;
+}
+
+/*
+ * Update the atc line for a given address by doing a mmu lookup.
+ */
+static bool mmu_fill_atc(uaecptr addr, bool super, uae_u32 tag, bool write, struct mmu_atc_line *l, uae_u32 *status)
+{
+       uae_u32 desc;
+
+       *status = 0;
+
+       desc = mmu_lookup_pagetable(addr, super, write, status);
+
+#if MMUDEBUG > 2
+       write_log(_T("translate: %x,%u,%u -> %x\n"), addr, super, write, desc);
+#endif
+
+       l->valid = 1;
+       l->tag = tag;
+       if (desc & MMU_MMUSR_R) {
+               l->status = desc & (MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W|MMU_MMUSR_R);
+               l->phys = desc & mmu_pagemaski;
        } else {
-               if ((desc & MMU_DES_USED) == 0) {
-                       desc |= MMU_DES_USED;
-                       phys_put_long(desc_addr, desc);
+               // Fault while looking page table:
+               // 68040: = Create resident ATC entry
+               // 68060: = Do not create ATC entry
+               if (currprefs.cpu_model == 68060)
+                       l->valid = 0;
+               l->status = 0;
+               l->phys = 0;
+       }
+        
+       return (*status != MMU_FSLW_TWE); // FIXME: find a better way to report bus error during table search
+}
+
+uaecptr mmu_translate(uaecptr addr, uae_u32 val, bool super, bool data, bool write, int size, bool rmw)
+{
+       int way, i, index, way_invalid;
+       struct mmu_atc_line *l;
+       uae_u32 status = 0;
+       uae_u32 tag = ((super ? 0x80000000 : 0x00000000) | (addr >> 1)) & mmu_tagmask;
+
+       if (mmu_pagesize_8k)
+               index=(addr & 0x0001E000)>>13;
+       else
+               index=(addr & 0x0000F000)>>12;
+       way_invalid = ATC_WAYS;
+       way_random++;
+
+       for (i = 0; i < ATC_WAYS; i++) {
+               way = mmu_atc_ways;
+               // if we have this
+               l = &mmu_atc_array[data][index][way];
+               if (l->valid && tag == l->tag) {
+atc_retry:
+                       // check if we need to cause a page fault
+                       if (((l->status&(MMU_MMUSR_W|MMU_MMUSR_S|MMU_MMUSR_R))!=MMU_MMUSR_R)) {
+                               if (((l->status&MMU_MMUSR_W) && write) ||
+                                       ((l->status&MMU_MMUSR_S) && !super) ||
+                                       !(l->status&MMU_MMUSR_R)) {
+
+                                       if ((l->status&MMU_MMUSR_S) && !super)
+                                               status |= MMU_FSLW_SP;
+                                       if ((l->status&MMU_MMUSR_W) && write)
+                                               status |= MMU_FSLW_WP;
+
+                                       mmu_bus_error(addr, val, mmu_get_fc(super, data), write, size, rmw, status, false);
+                                       return 0; // never reach, bus error longjumps out of the function
+                               }
+                       }
+                       // if first write to this page initiate table search to set M bit (but modify this slot)
+                       if (!(l->status&MMU_MMUSR_M) && write) {
+                               way_invalid = way;
+                               break;
+                       }
+#if MMU_DPAGECACHE
+                       uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | regs.s;
+                       uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+#endif
+                       if (!data) {
+#if MMU_IPAGECACHE
+                               uae_u32 laddr = (addr & mmu_pagemaski) | (super ? 1 : 0);
+                               atc_last_ins_laddr = laddr;
+                               atc_last_ins_paddr = l->phys;
+#else
+                               ;
+#endif
+#if MMU_DPAGECACHE
+                       } else if (write) {
+                               if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
+                                       atc_data_cache_write[idx2].log = idx1;
+                                       atc_data_cache_write[idx2].phys = l->phys;
+                               }
+                       } else {
+                               if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
+                                       atc_data_cache_read[idx2].log = idx1;
+                                       atc_data_cache_read[idx2].phys = l->phys;
+                               }
+#endif
+                       }
+                       // return translated addr
+                       return l->phys | (addr & mmu_pagemask);
+               } else {
+                       way_invalid = way;
                }
+               mmu_atc_ways++;
+               mmu_atc_ways %= ATC_WAYS;
        }
-       return desc;
+       // no entry found, we need to create a new one, first find an atc line to replace
+       way_random %= ATC_WAYS;
+       mmu_atc_ways = (way_invalid < ATC_WAYS) ? way_invalid : way_random;
+       way = mmu_atc_ways;
+       
+       // then initiate table search and create a new entry
+       l = &mmu_atc_array[data][index][way];
+       mmu_fill_atc(addr, super, tag, write, l, &status);
+       
+       // and retry the ATC search
+       way_random++;
+       goto atc_retry;
+       
+       // never reach
+       return 0;
 }
 
 static void misalignednotfirst(uaecptr addr)
@@ -752,10 +916,10 @@ static uae_u16 REGPARAM2 mmu_get_lrmw_word_unaligned(uaecptr addr)
 {
        uae_u16 res;
 
-       res = (uae_u16)mmu_get_user_byte(addr, regs.s != 0, true, true, sz_word) << 8;
+       res = (uae_u16)mmu_get_user_byte(addr, regs.s != 0, true, sz_word) << 8;
        SAVE_EXCEPTION;
        TRY(prb) {
-               res |= mmu_get_user_byte(addr + 1, regs.s != 0, true, true, sz_word);
+               res |= mmu_get_user_byte(addr + 1, regs.s != 0, true, sz_word);
                RESTORE_EXCEPTION;
        }
        CATCH(prb) {
@@ -771,10 +935,10 @@ static uae_u32 REGPARAM2 mmu_get_lrmw_long_unaligned(uaecptr addr)
        uae_u32 res;
 
        if (likely(!(addr & 1))) {
-               res = (uae_u32)mmu_get_user_word(addr, regs.s != 0, true, true, sz_long) << 16;
+               res = (uae_u32)mmu_get_user_word(addr, regs.s != 0, true, sz_long) << 16;
                SAVE_EXCEPTION;
                TRY(prb) {
-                       res |= mmu_get_user_word(addr + 2, regs.s != 0, true, true, sz_long);
+                       res |= mmu_get_user_word(addr + 2, regs.s != 0, true, sz_long);
                        RESTORE_EXCEPTION;
                }
                CATCH(prb) {
@@ -783,12 +947,12 @@ static uae_u32 REGPARAM2 mmu_get_lrmw_long_unaligned(uaecptr addr)
                        THROW_AGAIN(prb);
                } ENDTRY
        } else {
-               res = (uae_u32)mmu_get_user_byte(addr, regs.s != 0, true, true, sz_long) << 8;
+               res = (uae_u32)mmu_get_user_byte(addr, regs.s != 0, true, sz_long) << 8;
                SAVE_EXCEPTION;
                TRY(prb) {
-                       res = (res | mmu_get_user_byte(addr + 1, regs.s != 0, true, true, sz_long)) << 8;
-                       res = (res | mmu_get_user_byte(addr + 2, regs.s != 0, true, true, sz_long)) << 8;
-                       res |= mmu_get_user_byte(addr + 3, regs.s != 0, true, true, sz_long);
+                       res = (res | mmu_get_user_byte(addr + 1, regs.s != 0, true, sz_long)) << 8;
+                       res = (res | mmu_get_user_byte(addr + 2, regs.s != 0, true, sz_long)) << 8;
+                       res |= mmu_get_user_byte(addr + 3, regs.s != 0, true, sz_long);
                        RESTORE_EXCEPTION;
                }
                CATCH(prb) {
@@ -799,58 +963,6 @@ static uae_u32 REGPARAM2 mmu_get_lrmw_long_unaligned(uaecptr addr)
        }
        return res;
 }
-uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
-                                                int size, bool rmw, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
-               mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
-               return 0;
-       }
-       return x_phys_get_byte(mmu_get_real_address(addr, cl));
-}
-
-uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
-                                                 int size, bool rmw, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
-               mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
-               return 0;
-       }
-       return x_phys_get_word(mmu_get_real_address(addr, cl));
-}
-uae_u16 REGPARAM2 mmu_get_iword_slow(uaecptr addr, bool super,
-       int size, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, false, 0, cl, &status)) {
-               mmu_bus_error(addr, mmu_get_fc(super, false), 0, size, false, status, false);
-               return 0;
-       }
-       return x_phys_get_iword(mmu_get_real_address(addr, cl));
-}
-
-uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
-                                                 int size, bool rmw, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
-               mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
-               return 0;
-       }
-       return x_phys_get_long(mmu_get_real_address(addr, cl));
-}
-uae_u32 REGPARAM2 mmu_get_ilong_slow(uaecptr addr, bool super,
-       int size, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, false, 0, cl, &status)) {
-               mmu_bus_error(addr, mmu_get_fc(super, false), 0, size, false, status, false);
-               return 0;
-       }
-       return x_phys_get_ilong(mmu_get_real_address(addr, cl));
-}
 
 void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data, bool rmw)
 {
@@ -891,57 +1003,20 @@ void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data, bool
        } ENDTRY
 }
 
-void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
-                                                                int size, bool rmw, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
-               regs.wb3_data = val;
-               mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
-               return;
-       }
-       x_phys_put_byte(mmu_get_real_address(addr, cl), val);
-}
-
-void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
-                                                                int size, bool rmw, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
-               regs.wb3_data = val;
-               mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
-               return;
-       }
-       x_phys_put_word(mmu_get_real_address(addr, cl), val);
-}
-
-void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
-                                                                int size, bool rmw, struct mmu_atc_line *cl)
-{
-       uae_u32 status;
-       if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
-               regs.wb3_data = val;
-               mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
-               return;
-       }
-       x_phys_put_long(mmu_get_real_address(addr, cl), val);
-}
-
 uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
 {
        bool super = (regs.sfc & 4) != 0;
-       bool data = true;
        uae_u32 res;
 
        ismoves = true;
        if (likely(!is_unaligned(addr, 4))) {
-               res = mmu_get_user_long(addr, super, data, false, sz_long);
+               res = mmu_get_user_long(addr, super, false, sz_long);
        } else {
                if (likely(!(addr & 1))) {
-                       res = (uae_u32)mmu_get_user_word(addr, super, data, false, sz_long) << 16;
+                       res = (uae_u32)mmu_get_user_word(addr, super, false, sz_long) << 16;
                        SAVE_EXCEPTION;
                        TRY(prb) {
-                               res |= mmu_get_user_word(addr + 2, super, data, false, sz_long);
+                               res |= mmu_get_user_word(addr + 2, super, false, sz_long);
                                RESTORE_EXCEPTION;
                        }
                        CATCH(prb) {
@@ -950,12 +1025,12 @@ uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
                                THROW_AGAIN(prb);
                        } ENDTRY
                } else {
-                       res = (uae_u32)mmu_get_user_byte(addr, super, data, false, sz_long) << 8;
+                       res = (uae_u32)mmu_get_user_byte(addr, super, false, sz_long) << 8;
                        SAVE_EXCEPTION;
                        TRY(prb) {
-                               res = (res | mmu_get_user_byte(addr + 1, super, data, false, sz_long)) << 8;
-                               res = (res | mmu_get_user_byte(addr + 2, super, data, false, sz_long)) << 8;
-                               res |= mmu_get_user_byte(addr + 3, super, data, false, sz_long);
+                               res = (res | mmu_get_user_byte(addr + 1, super, false, sz_long)) << 8;
+                               res = (res | mmu_get_user_byte(addr + 2, super, false, sz_long)) << 8;
+                               res |= mmu_get_user_byte(addr + 3, super, false, sz_long);
                                RESTORE_EXCEPTION;
                        }
                        CATCH(prb) {
@@ -973,17 +1048,16 @@ uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
 uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
 {
        bool super = (regs.sfc & 4) != 0;
-       bool data = true;
        uae_u16 res;
 
        ismoves = true;
        if (likely(!is_unaligned(addr, 2))) {
-               res = mmu_get_user_word(addr, super, data, false, sz_word);
+               res = mmu_get_user_word(addr, super, false, sz_word);
        } else {
-               res = (uae_u16)mmu_get_user_byte(addr, super, data, false, sz_word) << 8;
+               res = (uae_u16)mmu_get_user_byte(addr, super, false, sz_word) << 8;
                SAVE_EXCEPTION;
                TRY(prb) {
-                       res |= mmu_get_user_byte(addr + 1, super, data, false, sz_word);
+                       res |= mmu_get_user_byte(addr + 1, super, false, sz_word);
                        RESTORE_EXCEPTION;
                }
                CATCH(prb) {
@@ -999,11 +1073,10 @@ uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
 uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
 {
        bool super = (regs.sfc & 4) != 0;
-       bool data = true;
        uae_u8 res;
        
        ismoves = true;
-       res = mmu_get_user_byte(addr, super, data, false, sz_byte);
+       res = mmu_get_user_byte(addr, super, false, sz_byte);
        ismoves = false;
        return res;
 }
@@ -1011,21 +1084,20 @@ uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
 void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
 {
        bool super = (regs.dfc & 4) != 0;
-       bool data = true;
 
        ismoves = true;
        SAVE_EXCEPTION;
        TRY(prb) {
-               if (likely(!is_unaligned(addr, 4)))
-                       mmu_put_user_long(addr, val, super, data, sz_long);
-               else if (likely(!(addr & 1))) {
-                       mmu_put_user_word(addr, val >> 16, super, data, sz_long);
-                       mmu_put_user_word(addr + 2, val, super, data, sz_long);
+               if (likely(!is_unaligned(addr, 4))) {
+                       mmu_put_user_long(addr, val, super, sz_long);
+               else if (likely(!(addr & 1))) {
+                       mmu_put_user_word(addr, val >> 16, super, sz_long);
+                       mmu_put_user_word(addr + 2, val, super, sz_long);
                } else {
-                       mmu_put_user_byte(addr, val >> 24, super, data, sz_long);
-                       mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long);
-                       mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long);
-                       mmu_put_user_byte(addr + 3, val, super, data, sz_long);
+                       mmu_put_user_byte(addr, val >> 24, super, sz_long);
+                       mmu_put_user_byte(addr + 1, val >> 16, super, sz_long);
+                       mmu_put_user_byte(addr + 2, val >> 8, super, sz_long);
+                       mmu_put_user_byte(addr + 3, val, super, sz_long);
                }
                RESTORE_EXCEPTION;
        }
@@ -1041,16 +1113,15 @@ void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
 void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
 {
        bool super = (regs.dfc & 4) != 0;
-       bool data = true;
 
        ismoves = true;
        SAVE_EXCEPTION;
        TRY(prb) {
-               if (likely(!is_unaligned(addr, 2)))
-                       mmu_put_user_word(addr, val, super, data, sz_word);
-               else {
-                       mmu_put_user_byte(addr, val >> 8, super, data, sz_word);
-                       mmu_put_user_byte(addr + 1, val, super, data, sz_word);
+               if (likely(!is_unaligned(addr, 2))) {
+                       mmu_put_user_word(addr, val, super, sz_word);
+               else {
+                       mmu_put_user_byte(addr, val >> 8, super, sz_word);
+                       mmu_put_user_byte(addr + 1, val, super, sz_word);
                }
                RESTORE_EXCEPTION;
        }
@@ -1066,12 +1137,11 @@ void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
 void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
 {
        bool super = (regs.dfc & 4) != 0;
-       bool data = true;
 
        ismoves = true;
        SAVE_EXCEPTION;
        TRY(prb) {
-               mmu_put_user_byte(addr, val, super, data, sz_byte);
+               mmu_put_user_byte(addr, val, super, sz_byte);
                RESTORE_EXCEPTION;
        }
        CATCH(prb) {
@@ -1084,33 +1154,27 @@ void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
 
 void mmu_get_move16(uaecptr addr, uae_u32 *v, bool data, int size)
 {
-       struct mmu_atc_line *cl;
+       bool super = regs.s != 0;
+
        addr &= ~15;
+       if ((!mmu_ttr_enabled || mmu_match_ttr(addr,super,data) == TTR_NO_MATCH) && regs.mmu_enabled) {
+               addr = mmu_translate(addr, 0, super, data, false, size, false);
+       }
        for (int i = 0; i < 4; i++) {
-               uaecptr addr2 = addr + i * 4;
-               //                                       addr,super,data
-               if ((!regs.mmu_enabled) || (mmu_match_ttr(addr2,regs.s != 0,data,false)!=TTR_NO_MATCH))
-                       v[i] = x_phys_get_long(addr2);
-               else if (likely(mmu_lookup(addr2, data, false, &cl)))
-                       v[i] = x_phys_get_long(mmu_get_real_address(addr2, cl));
-               else
-                       v[i] = mmu_get_long_slow(addr2, regs.s != 0, data, size, false, cl);
+               v[i] = phys_get_long(addr + i * 4);
        }
 }
 
 void mmu_put_move16(uaecptr addr, uae_u32 *val, bool data, int size)
 {
-       struct mmu_atc_line *cl;
+       bool super = regs.s != 0;
+
        addr &= ~15;
+       if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,super,data,val[0],size,false) == TTR_NO_MATCH) && regs.mmu_enabled) {
+               addr = mmu_translate(addr, val[0], super, data, true, size, false);
+       }
        for (int i = 0; i < 4; i++) {
-               uaecptr addr2 = addr + i * 4;
-               //                                        addr,super,data
-               if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr2,regs.s != 0,data,val[i],size,false)==TTR_OK_MATCH))
-                       x_phys_put_long(addr2,val[i]);
-               else if (likely(mmu_lookup(addr2, data, true, &cl)))
-                       x_phys_put_long(mmu_get_real_address(addr2, cl), val[i]);
-               else
-                       mmu_put_long_slow(addr2, val[i], regs.s != 0, data, size, false, cl);
+               phys_put_long(addr + i * 4, val[i]);
        }
 }
 
@@ -1155,46 +1219,67 @@ void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
 #if MMUINSDEBUG > 0
                write_log(_T("PTEST%c (A%d) %08x DFC=%d\n"), write ? 'W' : 'R', regno, addr, regs.dfc);
 #endif
-               mmu_flush_atc(addr, super, true);
-               SAVE_EXCEPTION;
-               TRY(prb) {
-                       struct mmu_atc_line *l;
-                       uae_u32 desc;
-                       bool data = (regs.dfc & 3) != 2;
+               if (!currprefs.mmu_ec) {
+                       mmu_flush_atc(addr, super, true);
+                       SAVE_EXCEPTION;
+                       TRY(prb) {
+                               struct mmu_atc_line *l;
+                               bool data = (regs.dfc & 3) != 2;
 
-                       if (mmu_match_ttr(addr,super,data, false)!=TTR_NO_MATCH) {
-                               regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
-                       } else {
-                               uae_u32 status;
-                               mmu_user_lookup(addr, super, data, write, &l);
-                               desc = mmu_fill_atc(addr, super, data, write, l, &status);
-                               if (!(l->valid)) {
-                                       regs.mmusr = MMU_MMUSR_B;
+                               if (mmu_match_ttr(addr,super,data)!=TTR_NO_MATCH) {
+                                       regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
                                } else {
-                                       regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|
-                                                                                MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W);
-                                       regs.mmusr |= MMU_MMUSR_R;
+                                       int way;
+                                       uae_u32 index;
+                                       uae_u32 status;
+                                       uae_u32 tag = ((super ? 0x80000000 : 0x00000000) | (addr >> 1)) & mmu_tagmask;
+                                       if (mmu_pagesize_8k)
+                                               index=(addr & 0x0001E000)>>13;
+                                       else
+                                               index=(addr & 0x0000F000)>>12;
+
+                                       for (way = 0; way < ATC_WAYS; way++) {
+                                               if (!mmu_atc_array[data][index][way].valid)
+                                                       break;
+                                       }
+                                       if (way >= ATC_WAYS) {
+                                               way = way_random % ATC_WAYS;
+                                       }
+                                       l=&mmu_atc_array[data][index][way];
+                               
+                                       if (mmu_fill_atc(addr, super, tag, write, l, &status)) {
+                                               regs.mmusr = l->phys | l->status;
+                                       } else {
+                                               regs.mmusr = MMU_MMUSR_B;
+                                       }
                                }
                        }
-               }
-               CATCH(prb) {
-                       regs.mmusr = MMU_MMUSR_B;
-               } ENDTRY
-               RESTORE_EXCEPTION;
+                       CATCH(prb) {
+                               regs.mmusr = MMU_MMUSR_B;
+                       } ENDTRY
+                       RESTORE_EXCEPTION;
 #if MMUINSDEBUG > 0
-               write_log(_T("PTEST result: mmusr %08x\n"), regs.mmusr);
+                       write_log(_T("PTEST result: mmusr %08x\n"), regs.mmusr);
 #endif
+               }
        } else if ((opcode & 0xFFB8) == 0xF588) { // PLPA (68060)
                int write = (opcode & 0x40) == 0;
                int regno = opcode & 7;
                uae_u32 addr = m68k_areg (regs, regno);
                bool data = (regs.dfc & 3) != 2;
+               int ttr;
 
 #if MMUINSDEBUG > 0
                write_log(_T("PLPA%c param: %08x\n"), write ? 'W' : 'R', addr);
 #endif
-               if (mmu_match_ttr(addr,super,data,false)==TTR_NO_MATCH) {
-                       m68k_areg (regs, regno) = mmu_translate (addr, super, data, write != 0);
+               if (write)
+                       ttr = mmu_match_ttr_write(addr, super, data, 0, 1, false);
+               else
+                       ttr = mmu_match_ttr(addr,super,data);
+               if (ttr == TTR_NO_MATCH) {
+                       if (!currprefs.mmu_ec) {
+                               m68k_areg (regs, regno) = mmu_translate(addr, 0, super, data, write, 1, false);
+                       }
                }
 #if MMUINSDEBUG > 0
                write_log(_T("PLPA%c result: %08x\n"), write ? 'W' : 'R', m68k_areg (regs, regno));
@@ -1216,28 +1301,34 @@ void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
                index=(addr & 0x0000F000)>>12;
        for (type=0;type<ATC_TYPE;type++) {
                for (way=0;way<ATC_WAYS;way++) {
-                       if (!global && mmu_atc_array[type][way][index].global)
+                       struct mmu_atc_line *l = &mmu_atc_array[type][index][way];
+                       if (!global && (l->status & MMU_MMUSR_G))
                                continue;
                        // if we have this 
-                       if ((tag == mmu_atc_array[type][way][index].tag) && (mmu_atc_array[type][way][index].valid)) {
-                               mmu_atc_array[type][way][index].valid=false;
+                       if (tag == l->tag && l->valid) {
+                               l->valid=false;
                        }
                }
        }       
+       flush_shortcut_cache();
+       mmu_flush_cache();
 }
 
 void REGPARAM2 mmu_flush_atc_all(bool global)
 {
-       unsigned int way,slot,type;
+       int way,slot,type;
        for (type=0;type<ATC_TYPE;type++) {
-               for (way=0;way<ATC_WAYS;way++) {
-                       for (slot=0;slot<ATC_SLOTS;slot++) {
-                               if (!global && mmu_atc_array[type][way][slot].global)
+               for (slot=0;slot<ATC_SLOTS;slot++) {
+                       for (way=0;way<ATC_WAYS;way++) {
+                               struct mmu_atc_line *l = &mmu_atc_array[type][slot][way];
+                               if (!global && (l->status&MMU_MMUSR_G))
                                        continue;
-                               mmu_atc_array[type][way][slot].valid=false;
+                               l->valid=false;
                        }
                }
        }
+       flush_shortcut_cache();
+       mmu_flush_cache();
 }
 
 void REGPARAM2 mmu_set_funcs(void)
@@ -1273,12 +1364,18 @@ void REGPARAM2 mmu_reset(void)
 
 void REGPARAM2 mmu_set_tc(uae_u16 tc)
 {
+       if (currprefs.mmu_ec)
+               tc &= ~(0x8000 | 0x4000);
+
        regs.mmu_enabled = (tc & 0x8000) != 0;
        mmu_pagesize_8k = (tc & 0x4000) != 0;
+
        mmu_tagmask  = mmu_pagesize_8k ? 0xFFFF0000 : 0xFFFF8000;
        mmu_pagemask = mmu_pagesize_8k ? 0x00001FFF : 0x00000FFF;
        mmu_pagemaski = ~mmu_pagemask;
        regs.mmu_page_size = mmu_pagesize_8k ? 8192 : 4096;
+       mmu_pageshift = mmu_pagesize_8k ? 13 : 12;
+       mmu_pageshift1m = mmu_pageshift - 1;
 
        mmu_flush_atc_all(true);
 
@@ -1294,6 +1391,14 @@ void REGPARAM2 mmu_set_super(bool super)
        mmu_is_super = super ? 0x80000000 : 0;
 }
 
+void REGPARAM2 mmu_flush_cache(void)
+{
+#if MMU_ICACHE
+       int len = sizeof(mmu_icache_data);
+       memset(&mmu_icache_data, 0xff, sizeof(mmu_icache_data));
+#endif
+}
+
 void m68k_do_rte_mmu040 (uaecptr a7)
 {
        uae_u16 ssr = get_word_mmu040 (a7 + 8 + 4);
@@ -1323,7 +1428,9 @@ void m68k_do_rte_mmu060 (uaecptr a7)
 
 void flush_mmu040 (uaecptr addr, int n)
 {
+       mmu_flush_cache();
 }
+
 void m68k_do_rts_mmu040 (void)
 {
        uaecptr stack = m68k_areg (regs, 7);
@@ -1341,7 +1448,9 @@ void m68k_do_bsr_mmu040 (uaecptr oldpc, uae_s32 offset)
 
 void flush_mmu060 (uaecptr addr, int n)
 {
+       mmu_flush_cache();
 }
+
 void m68k_do_rts_mmu060 (void)
 {
        uaecptr stack = m68k_areg (regs, 7);
@@ -1381,18 +1490,18 @@ uae_u32 uae_mmu_get_lrmw (uaecptr addr, int size, int type)
        uae_u32 v;
        locked_rmw_cycle = true;
        if (size == sz_byte) {
-               v = mmu_get_user_byte(addr, regs.s != 0, true, true, sz_byte);
+               v = mmu_get_user_byte(addr, regs.s != 0, true, sz_byte);
        } else if (size == sz_word) {
                if (unlikely(is_unaligned(addr, 2))) {
                        v = mmu_get_lrmw_word_unaligned(addr);
                } else {
-                       v = mmu_get_user_word(addr, regs.s != 0, true, true, sz_word);
+                       v = mmu_get_user_word(addr, regs.s != 0, true, sz_word);
                }
        } else {
                if (unlikely(is_unaligned(addr, 4)))
                        v = mmu_get_lrmw_long_unaligned(addr);
                else
-                       v = mmu_get_user_long(addr, regs.s != 0, true, true, sz_long);
+                       v = mmu_get_user_long(addr, regs.s != 0, true, sz_long);
        }
        locked_rmw_cycle = false;
        return v;
@@ -1481,16 +1590,16 @@ static int s_try_stack_size=0;
 static jmp_buf s_try_stack[MAX_TRY_STACK];
 jmp_buf* __poptry(void) {
        if (s_try_stack_size>0) {
-        s_try_stack_size--;
-        if (s_try_stack_size == 0)
-            return NULL;
-        memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
-        // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
-        return &s_try_stack[s_try_stack_size-1];
-    }
+               s_try_stack_size--;
+               if (s_try_stack_size == 0)
+                       return NULL;
+               memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
+               // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
+               return &s_try_stack[s_try_stack_size-1];
+       }
        else {
                fprintf(stderr,"try stack underflow...\n");
-           // return (NULL);
+               // return (NULL);
                abort();
        }
 }
index 06a36e1c7fec01654fbe4c435109af31dbad27c2..aeeeddb71dc722c4b1d8d9b6864aa9f58a483542 100644 (file)
@@ -70,6 +70,17 @@ uae_u32 mmu030_disp_store[2];
 uae_u32 mmu030_fmovem_store[2];
 struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS];
 
+#if MMU_DPAGECACHE030
+#define MMUFASTCACHE_ENTRIES 256
+struct mmufastcache
+{
+       uae_u32 log;
+       uae_u32 phys;
+};
+extern struct mmufastcache atc_data_cache_read[MMUFASTCACHE_ENTRIES];
+extern struct mmufastcache atc_data_cache_write[MMUFASTCACHE_ENTRIES];
+#endif
+
 /* for debugging messages */
 char table_letter[4] = {'A','B','C','D'};
 
@@ -112,7 +123,8 @@ static struct {
         struct {
             uae_u32 mask;
                        uae_u32 imask;
-            uae_u8 size;
+            uae_u32 size;
+                       uae_u32 size1m;
         } page;
         
         uae_u8 init_shift;
@@ -132,15 +144,17 @@ static struct {
     bool enabled;
     uae_u16 status;
 
-       /* Last access cache */
-       uae_u32 mmu030_last_fc;
+#if MMU_IPAGECACHE030
+#if MMU_DIRECT_ACCESS
+       uae_u8 *mmu030_last_physical_address_real;
+#else
        uae_u32 mmu030_last_physical_address;
+#endif
        uae_u32 mmu030_last_logical_address;
+#endif
 
 } mmu030;
 
-
-
 /* MMU Status Register
  *
  * ---x ---x x-xx x---
@@ -181,7 +195,79 @@ static struct {
 #define MMUSR_TRANSP_ACCESS     0x0040
 #define MMUSR_NUM_LEVELS_MASK   0x0007
 
+/* -- ATC flushing functions -- */
+
+static void mmu030_flush_cache(void)
+{
+#if MMU_IPAGECACHE030
+       mmu030.mmu030_last_logical_address = 0xffffffff;
+#endif
+#if MMU_DPAGECACHE030
+       memset(&atc_data_cache_read, 0xff, sizeof atc_data_cache_read);
+       memset(&atc_data_cache_write, 0xff, sizeof atc_data_cache_write);
+#endif
+}
+
+/* This function flushes ATC entries depending on their function code */
+static void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask) {
+    int i;
+    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
+        if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
+            mmu030.atc[i].logical.valid) {
+            mmu030.atc[i].logical.valid = false;
+#if MMU030_OP_DBG_MSG
+            write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
+#endif
+               }
+    }
+       mmu030_flush_cache();
+}
+
+/* This function flushes ATC entries depending on their logical address
+ * and their function code */
+static void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask) {
+    int i;
+       logical_addr &= mmu030.translation.page.imask;
+    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
+        if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
+            (mmu030.atc[i].logical.addr == logical_addr) &&
+            mmu030.atc[i].logical.valid) {
+            mmu030.atc[i].logical.valid = false;
+#if MMU030_OP_DBG_MSG
+            write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
+#endif
+               }
+    }
+       mmu030_flush_cache();
+}
+
+/* This function flushes ATC entries depending on their logical address */
+static void mmu030_flush_atc_page(uaecptr logical_addr) {
+    int i;
+       logical_addr &= mmu030.translation.page.imask;
+    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
+        if ((mmu030.atc[i].logical.addr == logical_addr) &&
+            mmu030.atc[i].logical.valid) {
+            mmu030.atc[i].logical.valid = false;
+#if MMU030_OP_DBG_MSG
+            write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
+#endif
+               }
+    }
+       mmu030_flush_cache();
+}
 
+/* This function flushes all ATC entries */
+void mmu030_flush_atc_all(void) {
+#if MMU030_OP_DBG_MSG
+       write_log(_T("ATC: Flushing all entries\n"));
+#endif
+       int i;
+    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
+        mmu030.atc[i].logical.valid = false;
+    }
+       mmu030_flush_cache();
+}
 
 /* -- MMU instructions -- */
 
@@ -428,71 +514,6 @@ uae_u32 mmu_op30_helper_get_fc(uae_u16 next) {
     }
 }
 
-
-/* -- ATC flushing functions -- */
-
-/* This function flushes ATC entries depending on their function code */
-void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask) {
-    int i;
-    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
-        if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
-            mmu030.atc[i].logical.valid) {
-            mmu030.atc[i].logical.valid = false;
-#if MMU030_OP_DBG_MSG
-            write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
-#endif
-               }
-    }
-       mmu030.mmu030_last_fc = 0xffffffff;
-}
-
-/* This function flushes ATC entries depending on their logical address
- * and their function code */
-void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask) {
-    int i;
-       logical_addr &= mmu030.translation.page.imask;
-    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
-        if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
-            (mmu030.atc[i].logical.addr == logical_addr) &&
-            mmu030.atc[i].logical.valid) {
-            mmu030.atc[i].logical.valid = false;
-#if MMU030_OP_DBG_MSG
-            write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
-#endif
-               }
-    }
-       mmu030.mmu030_last_fc = 0xffffffff;
-}
-
-/* This function flushes ATC entries depending on their logical address */
-void mmu030_flush_atc_page(uaecptr logical_addr) {
-    int i;
-       logical_addr &= mmu030.translation.page.imask;
-    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
-        if ((mmu030.atc[i].logical.addr == logical_addr) &&
-            mmu030.atc[i].logical.valid) {
-            mmu030.atc[i].logical.valid = false;
-#if MMU030_OP_DBG_MSG
-            write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
-#endif
-               }
-    }
-       mmu030.mmu030_last_fc = 0xffffffff;
-}
-
-/* This function flushes all ATC entries */
-void mmu030_flush_atc_all(void) {
-#if MMU030_OP_DBG_MSG
-       write_log(_T("ATC: Flushing all entries\n"));
-#endif
-       int i;
-    for (i=0; i<ATC030_NUM_ENTRIES; i++) {
-        mmu030.atc[i].logical.valid = false;
-    }
-       mmu030.mmu030_last_fc = 0xffffffff;
-}
-
-
 /* Transparent Translation Registers (TT0 and TT1)
  *
  * ---- ---- ---- ---- -xxx x--- x--- x---
@@ -577,49 +598,6 @@ TT_info mmu030_decode_tt(uae_u32 TT) {
     return ret;
 }
 
-/* This function compares the address with both transparent
- * translation registers and returns the result */
-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;
-    }
-    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;
-        }
-    }
-    
-    return (tt0|tt1);
-}
-int mmu030_match_ttr_access(uaecptr addr, uae_u32 fc, bool write)
-{
-    int tt0, tt1;
-       if (!tt_enabled)
-               return 0;
-    tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
-    tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
-    return (tt0|tt1) & TT_OK_MATCH;
-}
-
-/* Locked Read-Modify-Write */
-int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc)
-{
-    int tt0, tt1;
-
-       if (!tt_enabled)
-               return 0;
-    tt0 = mmu030_do_match_lrmw_ttr(tt0_030, mmu030.transparent.tt0, addr, fc);
-    tt1 = mmu030_do_match_lrmw_ttr(tt1_030, mmu030.transparent.tt1, addr, fc);
-    return (tt0|tt1) & TT_OK_MATCH;
-}
-
 /* This function checks if an address matches a transparent
  * translation register */
 
@@ -627,7 +605,7 @@ int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc)
  * If !(tt&TT_RMW) neither the read nor the write portion
  * of a read-modify-write cycle is transparently translated! */
 
-int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write)
+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 */
         
@@ -652,7 +630,7 @@ int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool
        return TT_NO_MATCH;
 }
 
-int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc)
+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 */
         
@@ -669,7 +647,50 @@ int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc)
        return TT_NO_MATCH;
 }
 
+/* This function compares the address with both transparent
+ * translation registers and returns the result */
+
+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;
+    }
+    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;
+        }
+    }
+    
+    return (tt0|tt1);
+}
+
+static int mmu030_match_ttr_access(uaecptr addr, uae_u32 fc, bool write)
+{
+    int tt0, tt1;
+       if (!tt_enabled)
+               return 0;
+    tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
+    tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
+    return (tt0|tt1) & TT_OK_MATCH;
+}
+
+/* Locked Read-Modify-Write */
+static int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc)
+{
+    int tt0, tt1;
 
+       if (!tt_enabled)
+               return 0;
+    tt0 = mmu030_do_match_lrmw_ttr(tt0_030, mmu030.transparent.tt0, addr, fc);
+    tt1 = mmu030_do_match_lrmw_ttr(tt1_030, mmu030.transparent.tt1, addr, fc);
+    return (tt0|tt1) & TT_OK_MATCH;
+}
 
 /* Translation Control Register:
  *
@@ -748,7 +769,12 @@ static void mmu030_do_fake_prefetch(void)
 
 bool mmu030_decode_tc(uae_u32 TC, bool check)
 {
-       mmu030.mmu030_last_fc = 0xffffffff;
+#if MMU_IPAGECACHE030
+       mmu030.mmu030_last_logical_address = 0xffffffff;
+#endif
+
+       if (currprefs.mmu_ec)
+               TC &= ~TC_ENABLE_TRANSLATION;
     /* Set MMU condition */    
     if (TC & TC_ENABLE_TRANSLATION) {
                if (!mmu030.enabled && check)
@@ -776,6 +802,7 @@ bool mmu030_decode_tc(uae_u32 TC, bool check)
     
     /* Extract initial shift and page size values from TC register */
     mmu030.translation.page.size = (TC & TC_PS_MASK) >> 20;
+    mmu030.translation.page.size1m =  mmu030.translation.page.size - 3;
     mmu030.translation.init_shift = (TC & TC_IS_MASK) >> 16;
        regs.mmu_page_size = 1 << mmu030.translation.page.size;
 
@@ -934,7 +961,24 @@ bool mmu030_decode_rp(uae_u64 RP) {
 #endif
 }
 
-
+static void mmu030_atc_handle_history_bit(int entry_num) {
+    int j;
+    mmu030.atc[entry_num].mru = 1;
+    for (j=0; j<ATC030_NUM_ENTRIES; j++) {
+        if (!mmu030.atc[j].mru)
+            break;
+    }
+    /* If there are no more zero-bits, reset all */
+    if (j==ATC030_NUM_ENTRIES) {
+        for (j=0; j<ATC030_NUM_ENTRIES; j++) {
+            mmu030.atc[j].mru = 0;
+        }
+        mmu030.atc[entry_num].mru = 1;
+#if MMU030_ATC_DBG_MSG
+        write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
+#endif
+       }
+}
 
 /* Descriptors */
 
@@ -1636,205 +1680,136 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) {
        THROW(2);
 }
 
-void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l, uae_u32 fc) {
-    uae_u32 page_index = addr & mmu030.translation.page.mask;
-    uae_u32 addr_mask = mmu030.translation.page.imask;
-    
-    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 (lput %08X)\n"),
-              l, physical_addr, page_index, val);
+static void mmu030_add_data_read_cache(uaecptr addr, uaecptr phys, uae_u32 fc)
+{
+#if MMU_DPAGECACHE030
+       uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >>  mmu030.translation.page.size1m) | fc;
+       uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+       if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
+               atc_data_cache_read[idx2].log = idx1;
+               atc_data_cache_read[idx2].phys = phys;
+       }
 #endif
-    physical_addr += page_index;
-    
-    if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
-        mmu030_page_fault(addr, false, MMU030_SSW_SIZE_L, fc);
-        return;
-    }
-
-    x_phys_put_long(physical_addr, val);
 }
 
-void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l, uae_u32 fc) {
-    uae_u32 page_index = addr & mmu030.translation.page.mask;
-    uae_u32 addr_mask = mmu030.translation.page.imask;
-    
-    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 (wput %04X)\n"),
-              l, physical_addr, page_index, val);
+static void mmu030_add_data_write_cache(uaecptr addr, uaecptr phys, uae_u32 fc)
+{
+#if MMU_DPAGECACHE030
+       uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >>  mmu030.translation.page.size1m) | fc;
+       uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+       if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
+               atc_data_cache_write[idx2].log = idx1;
+               atc_data_cache_write[idx2].phys = phys;
+       }
 #endif
-    physical_addr += page_index;
-    
-    if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
-        mmu030_page_fault(addr, false, MMU030_SSW_SIZE_W, fc);
-        return;
-    }
-
-    x_phys_put_word(physical_addr, val);
 }
 
-void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l, uae_u32 fc) {
+static uaecptr mmu030_put_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
     uae_u32 page_index = addr & mmu030.translation.page.mask;
     uae_u32 addr_mask = mmu030.translation.page.imask;
-    
     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
-    physical_addr += page_index;
     
     if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
         mmu030_page_fault(addr, false, MMU030_SSW_SIZE_B, fc);
-        return;
-    }
-
-    x_phys_put_byte(physical_addr, val);
-}
-
-uae_u32 mmu030_get_long_atc(uaecptr addr, int l, uae_u32 fc) {
-    uae_u32 page_index = addr & mmu030.translation.page.mask;
-    uae_u32 addr_mask = mmu030.translation.page.imask;
-    
-    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 (lget %08X)\n"), l,
-              physical_addr, page_index, phys_get_long(physical_addr+page_index));
-#endif
-    physical_addr += page_index;
-    
-    if (mmu030.atc[l].physical.bus_error) {
-        mmu030_page_fault(addr, true, MMU030_SSW_SIZE_L, fc);
         return 0;
     }
 
-    return x_phys_get_long(physical_addr);
-}
-
-static uae_u32 mmu030_get_ilong_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 *phys) {
-       uae_u32 page_index = addr & mmu030.translation.page.mask;
-       uae_u32 addr_mask = mmu030.translation.page.imask;
-
-       uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
-       *phys = physical_addr;
-#if MMU030_ATC_DBG_MSG
-       write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n"), l,
-               physical_addr, page_index, phys_get_long(physical_addr + page_index));
-#endif
-       physical_addr += page_index;
-
-       if (mmu030.atc[l].physical.bus_error) {
-               mmu030_page_fault(addr, true, MMU030_SSW_SIZE_L, fc);
-               return 0;
-       }
+       mmu030_add_data_write_cache(addr, physical_addr, fc);
 
-       return x_phys_get_ilong(physical_addr);
+       return physical_addr + page_index;
 }
 
-uae_u16 mmu030_get_word_atc(uaecptr addr, int l, uae_u32 fc) {
+static uaecptr mmu030_get_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
     uae_u32 page_index = addr & mmu030.translation.page.mask;
     uae_u32 addr_mask = mmu030.translation.page.imask;
-    
     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 (wget %04X)\n"), l,
-              physical_addr, page_index, phys_get_word(physical_addr+page_index));
+    write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
+              physical_addr, page_index);
 #endif
-    physical_addr += page_index;
-    
+   
     if (mmu030.atc[l].physical.bus_error) {
-        mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
+        mmu030_page_fault(addr, true, size, fc);
         return 0;
     }
-    
-    return x_phys_get_word(physical_addr);
+
+       mmu030_add_data_read_cache(addr, physical_addr, fc);
+
+       return physical_addr + page_index;
 }
 
-static uae_u16 mmu030_get_iword_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 *phys) {
+static uaecptr mmu030_get_i_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
        uae_u32 page_index = addr & mmu030.translation.page.mask;
        uae_u32 addr_mask = mmu030.translation.page.imask;
-
        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 (wget %04X)\n"), l,
-               physical_addr, page_index, phys_get_word(physical_addr + page_index));
+       write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
+               physical_addr, page_index);
 #endif
-       *phys = physical_addr;
-       physical_addr += page_index;
 
        if (mmu030.atc[l].physical.bus_error) {
-               mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
+               mmu030_page_fault(addr, true, size, fc);
                return 0;
        }
 
-       return x_phys_get_iword(physical_addr);
-}
-
-uae_u8 mmu030_get_byte_atc(uaecptr addr, int l, uae_u32 fc) {
-    uae_u32 page_index = addr & mmu030.translation.page.mask;
-    uae_u32 addr_mask = mmu030.translation.page.imask;
-    
-    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 (bget %02X)\n"), l,
-              physical_addr, page_index, phys_get_byte(physical_addr+page_index));
+#if MMU_IPAGECACHE030
+#if MMU_DIRECT_ACCESS
+       mmu030.mmu030_last_physical_address_real = get_real_address(physical_addr);
+#else
+       mmu030.mmu030_last_physical_address = physical_addr;
+#endif
+       mmu030.mmu030_last_logical_address = (addr & mmu030.translation.page.imask) | fc;
 #endif
-    physical_addr += page_index;
-    
-    if (mmu030.atc[l].physical.bus_error) {
-        mmu030_page_fault(addr, true, MMU030_SSW_SIZE_B, fc);
-        return 0;
-    }
 
-    return x_phys_get_byte(physical_addr);
+       return physical_addr + page_index;
 }
 
 /* Generic versions of above */
-void mmu030_put_atc_generic(uaecptr addr, uae_u32 val, int l, uae_u32 fc, int size, int flags) {
+static uaecptr mmu030_put_atc_generic(uaecptr addr, int l, uae_u32 fc, int flags) {
     uae_u32 page_index = addr & mmu030.translation.page.mask;
     uae_u32 addr_mask = mmu030.translation.page.imask;
-    
     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);
 #endif
-    physical_addr += page_index;
     
     if (mmu030.atc[l].physical.write_protect || mmu030.atc[l].physical.bus_error) {
                mmu030_page_fault(addr, false, flags, fc);
-        return;
+        return 0;
     }
-       if (size == sz_byte)
-           x_phys_put_byte(physical_addr, val);
-       else if (size == sz_word)
-           x_phys_put_word(physical_addr, val);
-       else
-           x_phys_put_long(physical_addr, val);
 
+       mmu030_add_data_write_cache(addr, physical_addr, fc);
+
+       return physical_addr + page_index;
 }
 
-uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int flags, bool checkwrite) {
+uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int flags, bool checkwrite) {
     uae_u32 page_index = addr & mmu030.translation.page.mask;
     uae_u32 addr_mask = mmu030.translation.page.imask;
-    
     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 (bget %02X)\n"), l,
-              physical_addr, page_index, phys_get_byte(physical_addr+page_index));
+    write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
+              physical_addr, page_index);
 #endif
-    physical_addr += page_index;
     
        if (mmu030.atc[l].physical.bus_error || (checkwrite && mmu030.atc[l].physical.write_protect)) {
         mmu030_page_fault(addr, true, flags, fc);
         return 0;
     }
-       if (size == sz_byte)
-               return x_phys_get_byte(physical_addr);
-       else if (size == sz_word)
-               return x_phys_get_word(physical_addr);
-       return x_phys_get_long(physical_addr);
+
+       mmu030_add_data_read_cache(addr, physical_addr, fc);
+
+       return physical_addr + page_index;
 }
 
 
@@ -1842,7 +1817,7 @@ uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int fl
  * by comparing the logical address and function code to the values
  * stored in the ATC entries. If a matching entry is found it sets
  * the history bit and returns the cache index of the entry. */
-int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
+static int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
     uaecptr logical_addr = 0;
     uae_u32 addr_mask = mmu030.translation.page.imask;
        uae_u32 maddr = addr & addr_mask;
@@ -1876,26 +1851,6 @@ int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
     return -1;
 }
 
-void mmu030_atc_handle_history_bit(int entry_num) {
-    int j;
-    mmu030.atc[entry_num].mru = 1;
-    for (j=0; j<ATC030_NUM_ENTRIES; j++) {
-        if (!mmu030.atc[j].mru)
-            break;
-    }
-    /* If there are no more zero-bits, reset all */
-    if (j==ATC030_NUM_ENTRIES) {
-        for (j=0; j<ATC030_NUM_ENTRIES; j++) {
-            mmu030.atc[j].mru = 0;
-        }
-        mmu030.atc[entry_num].mru = 1;
-#if MMU030_ATC_DBG_MSG
-        write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
-#endif
-       }
-}
-
-
 /* Memory access functions:
  * If the address matches one of the transparent translation registers
  * use it directly as physical address, else check ATC for the
@@ -1906,168 +1861,200 @@ void mmu030_atc_handle_history_bit(int entry_num) {
 void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,true)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
                x_phys_put_long(addr,val);
                return;
     }
 
     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
-
     if (atc_line_num>=0) {
-        mmu030_put_long_atc(addr, val, atc_line_num, fc);
+        addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
     } else {
         mmu030_table_search(addr,fc,true,0);
-        mmu030_put_long_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
+        addr = mmu030_put_atc(addr, mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_L);
     }
+       x_phys_put_long(addr,val);
 }
 
 void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,true)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
                x_phys_put_word(addr,val);
                return;
     }
     
     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
-    
     if (atc_line_num>=0) {
-        mmu030_put_word_atc(addr, val, atc_line_num, fc);
+        addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
     } else {
         mmu030_table_search(addr, fc, true, 0);
-        mmu030_put_word_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
+        addr = mmu030_put_atc(addr,  mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_W);
     }
+       x_phys_put_word(addr,val);
 }
 
 void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, true)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
                x_phys_put_byte(addr,val);
                return;
     }
     
     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
-
     if (atc_line_num>=0) {
-        mmu030_put_byte_atc(addr, val, atc_line_num, fc);
+        addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_B);
     } else {
         mmu030_table_search(addr, fc, true, 0);
-        mmu030_put_byte_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
+        addr = mmu030_put_atc(addr, mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_B);
     }
+       x_phys_put_byte(addr,val);
 }
 
-uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc) {
-
-       if (mmu030.mmu030_last_fc == fc && (addr & mmu030.translation.page.imask) == mmu030.mmu030_last_logical_address) {
-               return x_phys_get_ilong(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
-       }
-
-       mmu030.mmu030_last_fc = 0xffffffff;
-       //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, false)) || (fc == 7)) {
-               return x_phys_get_ilong(addr);
-       }
-
-       int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
 
-       if (atc_line_num >= 0) {
-               uae_u32 v = mmu030_get_ilong_atc(addr, atc_line_num, fc, &mmu030.mmu030_last_physical_address);
-               mmu030.mmu030_last_logical_address = addr & mmu030.translation.page.imask;
-               mmu030.mmu030_last_fc = fc;
-               return v;
-       }
-       else {
-               mmu030_table_search(addr, fc, false, 0);
-               uae_u32 v = mmu030_get_ilong_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, &mmu030.mmu030_last_physical_address);
-               mmu030.mmu030_last_logical_address = addr & mmu030.translation.page.imask;
-               mmu030.mmu030_last_fc = fc;
-               return v;
-       }
-}
 uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
                return x_phys_get_long(addr);
     }
     
-    int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
-
+#if MMU_DPAGECACHE030
+       uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size1m) | fc;
+       uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+       if (atc_data_cache_read[idx2].log == idx1) {
+               addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
+               return x_phys_get_long(addr);
+       }
+#endif
+       
+       int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
     if (atc_line_num>=0) {
-        return mmu030_get_long_atc(addr, atc_line_num, fc);
+        addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
     } else {
         mmu030_table_search(addr, fc, false, 0);
-        return mmu030_get_long_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
+        addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_L);
     }
+       return x_phys_get_long(addr);
 }
 
-uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
-
-       if (mmu030.mmu030_last_fc == fc && (addr & mmu030.translation.page.imask) == mmu030.mmu030_last_logical_address) {
-               return x_phys_get_iword(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
-       }
-
-       mmu030.mmu030_last_fc = 0xffffffff;
-       //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, false)) || (fc == 7)) {
-               return x_phys_get_iword(addr);
-       }
-
-       int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
-
-       if (atc_line_num >= 0) {
-               uae_u16 v = mmu030_get_iword_atc(addr, atc_line_num, fc, &mmu030.mmu030_last_physical_address);
-               mmu030.mmu030_last_logical_address = addr & mmu030.translation.page.imask;
-               mmu030.mmu030_last_fc = fc;
-               return v;
-       } else {
-               mmu030_table_search(addr, fc, false, 0);
-               uae_u16 v = mmu030_get_iword_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, &mmu030.mmu030_last_physical_address);
-               mmu030.mmu030_last_logical_address = addr & mmu030.translation.page.imask;
-               mmu030.mmu030_last_fc = fc;
-               return v;
-       }
-}
 uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
                return x_phys_get_word(addr);
     }
     
-    int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
-
+#if MMU_DPAGECACHE030
+       uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size1m) | fc;
+       uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+       if (atc_data_cache_read[idx2].log == idx1) {
+               addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
+               return x_phys_get_word(addr);
+       }
+#endif
+       
+       int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
     if (atc_line_num>=0) {
-        return mmu030_get_word_atc(addr, atc_line_num, fc);
+        addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
     } else {
         mmu030_table_search(addr, fc, false, 0);
-        return mmu030_get_word_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
+        addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_W);
     }
+       return x_phys_get_word(addr);
 }
 
 uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
                return x_phys_get_byte(addr);
     }
     
-    int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
-
+#if MMU_DPAGECACHE030
+       uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size1m) | fc;
+       uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+       if (atc_data_cache_read[idx2].log == idx1) {
+               addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
+               return x_phys_get_byte(addr);
+       }
+#endif
+       
+       int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
     if (atc_line_num>=0) {
-        return mmu030_get_byte_atc(addr, atc_line_num, fc);
+        addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_B);
     } else {
         mmu030_table_search(addr, fc, false, 0);
-        return mmu030_get_byte_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
+        addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_B);
     }
+       return x_phys_get_byte(addr);
+}
+
+
+uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc) {
+
+#if MMU_IPAGECACHE030
+       if (((addr & mmu030.translation.page.imask) | fc) == mmu030.mmu030_last_logical_address) {
+#if MMU_DIRECT_ACCESS
+               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
+               return x_phys_get_ilong(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
+#endif
+       }
+       mmu030.mmu030_last_logical_address = 0xffffffff;
+#endif
+
+       //                                        addr,super,write
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
+               return x_phys_get_ilong(addr);
+       }
+
+       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);
+       } else {
+               mmu030_table_search(addr, fc, false, 0);
+               addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_L);
+       }
+       return x_phys_get_ilong(addr);
+}
+
+uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
+
+#if MMU_IPAGECACHE030
+       if (((addr & mmu030.translation.page.imask) | fc) == mmu030.mmu030_last_logical_address) {
+#if MMU_DIRECT_ACCESS
+               uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask];
+               return (p[0] << 8) | p[1];
+#else
+               return x_phys_get_iword(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
+#endif
+       }
+       mmu030.mmu030_last_logical_address = 0xffffffff;
+#endif
+
+       //                                        addr,super,write
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
+               return x_phys_get_iword(addr);
+       }
+
+       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);
+       } else {
+               mmu030_table_search(addr, fc, false, 0);
+               addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_W);
+       }
+       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 accesssize, int flags) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, true)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
                if (size == sz_byte)
                        x_phys_put_byte(addr, val);
                else if (size == sz_word)
@@ -2077,23 +2064,30 @@ void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int acc
                return;
     }
     
+       if (accesssize == sz_byte)
+               flags |= MMU030_SSW_SIZE_B;
+       else if (accesssize == sz_word)
+               flags |= MMU030_SSW_SIZE_W;
     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
     if (atc_line_num>=0) {
-        mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
+        addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
     } else {
         mmu030_table_search(addr, fc, true, 0);
                atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
-               if (accesssize == sz_byte)
-                       flags |= MMU030_SSW_SIZE_B;
-               else if (accesssize == sz_word)
-                       flags |= MMU030_SSW_SIZE_W;
-        mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
+        addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
     }
+       if (size == sz_byte)
+               x_phys_put_byte(addr, val);
+       else if (size == sz_word)
+               x_phys_put_word(addr, val);
+       else
+               x_phys_put_long(addr, val);
 }
+
 static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
     
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_lrmw_ttr_access(addr,fc)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
                if (size == sz_byte)
                        return x_phys_get_byte(addr);
                else if (size == sz_word)
@@ -2101,25 +2095,32 @@ static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int a
                return x_phys_get_long(addr);
     }
     
+       if (accesssize == sz_byte)
+               flags |= MMU030_SSW_SIZE_B;
+       else if (accesssize == sz_word)
+               flags |= MMU030_SSW_SIZE_W;
     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
     if (atc_line_num>=0) {
-        return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
+        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true);
     } else {
         mmu030_table_search(addr, fc, true, 0);
                atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
-               if (accesssize == sz_byte)
-                       flags |= MMU030_SSW_SIZE_B;
-               else if (accesssize == sz_word)
-                       flags |= MMU030_SSW_SIZE_W;
-        return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
+        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true);
     }
+
+       if (size == sz_byte)
+               return x_phys_get_byte(addr);
+       else if (size == sz_word)
+               return x_phys_get_word(addr);
+       return x_phys_get_long(addr);
 }
+
 uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
        if (flags & MMU030_SSW_RM) {
                return mmu030_get_generic_lrmw(addr, fc, size, accesssize, flags);
        }
        //                                        addr,super,write
-       if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
+       if ((fc==7) || (tt_enabled && mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
                if (size == sz_byte)
                        return x_phys_get_byte(addr);
                else if (size == sz_word)
@@ -2127,18 +2128,24 @@ uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int accesssize, i
                return x_phys_get_long(addr);
     }
     
+       if (accesssize == sz_byte)
+               flags |= MMU030_SSW_SIZE_B;
+       else if (accesssize == sz_word)
+               flags |= MMU030_SSW_SIZE_W;
     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
     if (atc_line_num>=0) {
-        return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
+        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
     } else {
         mmu030_table_search(addr, fc, false, 0);
                atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
-               if (accesssize == sz_byte)
-                       flags |= MMU030_SSW_SIZE_B;
-               else if (accesssize == sz_word)
-                       flags |= MMU030_SSW_SIZE_W;
-        return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
+        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
     }
+
+       if (size == sz_byte)
+               return x_phys_get_byte(addr);
+       else if (size == sz_word)
+               return x_phys_get_word(addr);
+       return x_phys_get_long(addr);
 }
 
 
@@ -2300,7 +2307,7 @@ static uaecptr mmu030_get_addr_atc(uaecptr addr, int l, uae_u32 fc, bool write)
 uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write)
 {
        int fc = (super ? 4 : 0) | (data ? 1 : 2);
-       if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,write)&TT_OK_MATCH) || (fc==7)) {
+       if ((fc==7) || (mmu030_match_ttr(addr,fc,write)&TT_OK_MATCH) || (!mmu030.enabled)) {
                return addr;
     }
     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
@@ -2343,7 +2350,9 @@ void mmu030_reset(int hardreset)
 {
     /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
     mmu030.enabled = false;
-       mmu030.mmu030_last_fc = 0xffffffff;
+#if MMU_IPAGECACHE030
+       mmu030.mmu030_last_logical_address = 0xffffffff;
+#endif
        regs.mmu_page_size = 0;
        if (hardreset >= 0) {
                tc_030 &= ~TC_ENABLE_TRANSLATION;
index 79372c50150c52ed0b347fc59138eb63bd785fba..ac9688bf44f08a788413f0c92b197e3b900f531c 100644 (file)
 
 #include "uae/types.h"
 
+#define MMU_ICACHE 0
+#define MMU_IPAGECACHE 1
+#define MMU_DPAGECACHE 1
+
+#define CACHE_HIT_COUNT 0
+
 #include "mmu_common.h"
 
 #ifndef FULLMMU
@@ -52,62 +58,10 @@ extern uaecptr mmu040_movem_ea;
 extern uae_u32 mmu040_move16[4];
 
 extern bool mmu_pagesize_8k;
+extern int mmu_pageshift, mmu_pageshift1m;
 extern uae_u16 mmu_opcode;
 extern bool mmu_restart;
-extern bool mmu_ttr_enabled;
-
-//typedef uae_u8 flagtype;
-
-//static m68k_exception except;
-
-struct xttrx {
-    uae_u32 log_addr_base : 8;
-    uae_u32 log_addr_mask : 8;
-    uae_u32 enable : 1;
-    uae_u32 s_field : 2;
-    uae_u32 : 3;
-    uae_u32 usr1 : 1;
-    uae_u32 usr0 : 1;
-    uae_u32 : 1;
-    uae_u32 cmode : 2;
-    uae_u32 : 2;
-    uae_u32 write : 1;
-    uae_u32 : 2;
-};
-
-struct mmusr_t {
-   uae_u32 phys_addr : 20;
-   uae_u32 bus_err : 1;
-   uae_u32 global : 1;
-   uae_u32 usr1 : 1;
-   uae_u32 usr0 : 1;
-   uae_u32 super : 1;
-   uae_u32 cmode : 2;
-   uae_u32 modif : 1;
-   uae_u32 : 1;
-   uae_u32 write : 1;
-   uae_u32 ttrhit : 1;
-   uae_u32 resident : 1;
-};
-
-struct log_addr4 {
-   uae_u32 rif : 7;
-   uae_u32 pif : 7;
-   uae_u32 paif : 6;
-   uae_u32 poff : 12;
-};
-
-struct log_addr8 {
-  uae_u32 rif : 7;
-  uae_u32 pif : 7;
-  uae_u32 paif : 5;
-  uae_u32 poff : 13;
-};
-
-#define MMU_TEST_PTEST                                 1
-#define MMU_TEST_VERBOSE                               2
-#define MMU_TEST_FORCE_TABLE_SEARCH            4
-#define MMU_TEST_NO_BUSERR                             8
+extern bool mmu_ttr_enabled, mmu_ttr_enabled_ins, mmu_ttr_enabled_data;
 
 extern void mmu_dump_tables(void);
 
@@ -158,6 +112,24 @@ extern void mmu_dump_tables(void);
 #define MMU_MMUSR_T                                            (1 << 1)
 #define MMU_MMUSR_R                                            (1 << 0)
 
+// 68040 and 68060
+#define MMU_TCR_E                                              0x8000
+#define MMU_TCR_P                                              0x4000
+// 68060 only
+#define MMU_TCR_NAD                                            0x2000
+#define MMU_TCR_NAI                                            0x1000
+#define MMU_TCR_FOTC                                   0x0800
+#define MMU_TCR_FITC                                   0x0400
+#define MMU_TCR_DCO1                                   0x0200
+#define MMU_TCR_DCO0                                   0x0100
+#define MMU_TCR_DUO1                                   0x0080
+#define MMU_TCR_DUO0                                   0x0040
+#define MMU_TCR_DWO                                            0x0020
+#define MMU_TCR_DCI1                                   0x0010
+#define MMU_TCR_DCI0                                   0x0008
+#define MMU_TCR_DUI1                                   0x0004
+#define MMU_TCR_DUI0                                   0x0002
+
 #define TTR_I0 4
 #define TTR_I1 5
 #define TTR_D0 6
@@ -169,10 +141,8 @@ extern void mmu_dump_tables(void);
 
 struct mmu_atc_line {
        uaecptr tag; // tag is 16 or 17 bits S+logical
-       unsigned valid : 1;
-       unsigned global : 1;
-       unsigned modified : 1;
-       unsigned write_protect : 1;
+       uae_u32 valid;
+       uae_u32 status;
        uaecptr phys; // phys base address
 };
 
@@ -189,135 +159,15 @@ struct mmu_atc_line {
 #define ATC_TYPE 2
 
 extern uae_u32 mmu_is_super;
-extern uae_u32 mmu_tagmask, mmu_pagemask;
-extern struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_WAYS][ATC_SLOTS];
-
-/* Last matched ATC index, next lookup starts from this index as an optimization */
-extern int mmu_atc_ways;
+extern uae_u32 mmu_tagmask, mmu_pagemask, mmu_pagemaski;
+extern struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_SLOTS][ATC_WAYS];
 
-/*
- * mmu access is a 4 step process:
- * if mmu is not enabled just read physical
- * check transparent region, if transparent, read physical
- * check ATC (address translation cache), read immediatly if HIT
- * read from mmu with the long path (and allocate ATC entry if needed)
- */
-static ALWAYS_INLINE bool mmu_lookup(uaecptr addr, bool data, bool write,
-                                                                         struct mmu_atc_line **cl)
-{
-       int way, i, index;
-       static int way_miss=0;
-
-       uae_u32 tag = (mmu_is_super | (addr >> 1)) & mmu_tagmask;
-       if (mmu_pagesize_8k)
-               index=(addr & 0x0001E000)>>13;
-       else
-               index=(addr & 0x0000F000)>>12;
-       for (i = 0; i < ATC_WAYS; i++) {
-               way = mmu_atc_ways;
-               // if we have this 
-               if ((tag == mmu_atc_array[data][way][index].tag) && (mmu_atc_array[data][way][index].valid)) {
-                       *cl=&mmu_atc_array[data][way][index];
-                       // if first write to this take slow path (but modify this slot)
-                       if ((!mmu_atc_array[data][way][index].modified & write) || (mmu_atc_array[data][way][index].write_protect & write))
-                               return false; 
-                       return true;
-               }
-               mmu_atc_ways++;
-               mmu_atc_ways %= ATC_WAYS;
-       }
-       // we select a random way to void
-       *cl=&mmu_atc_array[data][way_miss%ATC_WAYS][index];
-       (*cl)->tag = tag;
-       way_miss++;
-       return false;
-}
-
-/*
- */
-static ALWAYS_INLINE bool mmu_user_lookup(uaecptr addr, bool super, bool data,
-                                                                                  bool write, struct mmu_atc_line **cl)
-{
-       int way, i, index;
-       static int way_miss=0;
-
-       uae_u32 tag = ((super ? 0x80000000 : 0x00000000) | (addr >> 1)) & mmu_tagmask;
-       if (mmu_pagesize_8k)
-               index=(addr & 0x0001E000)>>13;
-       else
-               index=(addr & 0x0000F000)>>12;
-       for (i = 0; i < ATC_WAYS; i++) {
-               way = mmu_atc_ways;
-               // if we have this 
-               if ((tag == mmu_atc_array[data][way][index].tag) && (mmu_atc_array[data][way][index].valid)) {
-                       *cl=&mmu_atc_array[data][way][index];
-                       // if first write to this take slow path (but modify this slot)
-                       if ((!mmu_atc_array[data][way][index].modified & write) || (mmu_atc_array[data][way][index].write_protect & write))
-                               return false; 
-                       return true;
-               }
-               mmu_atc_ways++;
-               mmu_atc_ways %= ATC_WAYS;
-       }
-       // we select a random way to void
-       *cl=&mmu_atc_array[data][way_miss%ATC_WAYS][index];
-       (*cl)->tag = tag;
-       way_miss++;
-       return false;
-}
-
-/* check if an address matches a ttr */
-STATIC_INLINE int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
-{
-       if (ttr & MMU_TTR_BIT_ENABLED)  {       /* TTR enabled */
-               uae_u8 msb, mask;
-
-               msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
-               mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
-
-               if (!(msb & ~mask)) {
-
-                       if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
-                               if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
-                                       return TTR_NO_MATCH;
-                               }
-                       }
-
-                       return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
-               }
-       }
-       return TTR_NO_MATCH;
-}
-
-STATIC_INLINE int mmu_match_ttr(uaecptr addr, bool super, bool data, bool rmw)
-{
-       int res;
-
-       if (!mmu_ttr_enabled)
-               return TTR_NO_MATCH;
-       if (data) {
-               res = mmu_do_match_ttr(regs.dtt0, addr, super);
-               if (res == TTR_NO_MATCH)
-                       res = mmu_do_match_ttr(regs.dtt1, addr, super);
-       } else {
-               res = mmu_do_match_ttr(regs.itt0, addr, super);
-               if (res == TTR_NO_MATCH)
-                       res = mmu_do_match_ttr(regs.itt1, addr, super);
-       }
-       return res;
-}
+extern void mmu_tt_modified(void);
+extern int mmu_match_ttr_ins(uaecptr addr, bool super);
+extern int mmu_match_ttr(uaecptr addr, bool super, bool data);
 extern void mmu_bus_error_ttr_write_fault(uaecptr addr, bool super, bool data, uae_u32 val, int size, bool rmw);
-STATIC_INLINE int mmu_match_ttr_write(uaecptr addr, bool super, bool data,  uae_u32 val, int size, bool rmw)
-{
-       if (!mmu_ttr_enabled)
-               return TTR_NO_MATCH;
-       int res = mmu_match_ttr(addr, super, data, rmw);
-       if (res == TTR_NO_WRITE)
-               mmu_bus_error_ttr_write_fault(addr, super, data, val, size, rmw);
-       return res;
-}
-
-extern void mmu_tt_modified (void);
+extern int mmu_match_ttr_write(uaecptr addr, bool super, bool data, uae_u32 val, int size, bool rmw);
+extern uaecptr mmu_translate(uaecptr addr, uae_u32 val, bool super, bool data, bool write, int size, bool rmw);
 
 extern uae_u32 REGPARAM3 mmu060_get_rmw_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) REGPARAM;
 extern void REGPARAM3 mmu060_put_rmw_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) REGPARAM;
@@ -327,35 +177,15 @@ extern uae_u32 REGPARAM3 mmu_get_long_unaligned(uaecptr addr, bool data, bool rm
 
 extern uae_u32 REGPARAM3 mmu_get_ilong_unaligned(uaecptr addr) REGPARAM;
 
-extern uae_u8 REGPARAM3 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
-                                                                                 int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
-extern uae_u16 REGPARAM3 mmu_get_word_slow(uaecptr addr, bool super, bool data,
-                                                                                  int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
-extern uae_u32 REGPARAM3 mmu_get_long_slow(uaecptr addr, bool super, bool data,
-                                                                                  int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
-
-extern uae_u16 REGPARAM3 mmu_get_iword_slow(uaecptr addr, bool super,
-                                                                                  int size, struct mmu_atc_line *cl) REGPARAM;
-extern uae_u32 REGPARAM3 mmu_get_ilong_slow(uaecptr addr, bool super,
-                                                                                  int size, struct mmu_atc_line *cl) REGPARAM;
-
 extern void REGPARAM3 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data, bool rmw) REGPARAM;
 extern void REGPARAM3 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data, bool rmw) REGPARAM;
 
-extern void REGPARAM3 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
-                                                                               int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
-extern void REGPARAM3 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
-                                                                               int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
-extern void REGPARAM3 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
-                                                                               int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
-
 extern void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode);
 
 #define FC_DATA                (regs.s ? 5 : 1)
 #define FC_INST                (regs.s ? 6 : 2)
 
-extern uaecptr REGPARAM3 mmu_translate(uaecptr addr, bool super, bool data, bool write) REGPARAM;
-extern void mmu_bus_error(uaecptr addr, int fc, bool write, int size, bool rmw, uae_u32 status, bool nonmmu);
+extern void mmu_bus_error(uaecptr addr, uae_u32 val, int fc, bool write, int size, bool rmw, uae_u32 status, bool nonmmu);
 
 extern uae_u32 REGPARAM3 sfc_get_long(uaecptr addr) REGPARAM;
 extern uae_u16 REGPARAM3 sfc_get_word(uaecptr addr) REGPARAM;
@@ -389,240 +219,448 @@ extern void REGPARAM3 mmu_reset(void) REGPARAM;
 extern void REGPARAM3 mmu_set_funcs(void) REGPARAM;
 extern void REGPARAM3 mmu_set_tc(uae_u16 tc) REGPARAM;
 extern void REGPARAM3 mmu_set_super(bool super) REGPARAM;
+extern void REGPARAM3 mmu_flush_cache(void) REGPARAM;
 
 static ALWAYS_INLINE uaecptr mmu_get_real_address(uaecptr addr, struct mmu_atc_line *cl)
 {
-    return cl->phys | (addr & mmu_pagemask);
+       return cl->phys | (addr & mmu_pagemask);
 }
 
 extern void mmu_get_move16(uaecptr addr, uae_u32 *v, bool data, int size);
 extern void mmu_put_move16(uaecptr addr, uae_u32 *val, bool data, int size);
 
-static ALWAYS_INLINE uae_u32 mmu_get_long(uaecptr addr, bool data, int size, bool rmw)
+#if MMU_IPAGECACHE
+extern uae_u32 atc_last_ins_laddr, atc_last_ins_paddr;
+#endif
+
+#if MMU_DPAGECACHE
+#define MMUFASTCACHE_ENTRIES 256
+struct mmufastcache
 {
-       struct mmu_atc_line *cl;
+       uae_u32 log;
+       uae_u32 phys;
+};
+extern struct mmufastcache atc_data_cache_read[MMUFASTCACHE_ENTRIES];
+extern struct mmufastcache atc_data_cache_write[MMUFASTCACHE_ENTRIES];
+#endif
 
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,regs.s != 0,data,rmw)!=TTR_NO_MATCH))
-               return x_phys_get_long(addr);
-       if (likely(mmu_lookup(addr, data, false, &cl)))
-               return x_phys_get_long(mmu_get_real_address(addr, cl));
-       return mmu_get_long_slow(addr, regs.s != 0, data, size, rmw, cl);
-}
+#if CACHE_HIT_COUNT
+extern int mmu_ins_hit, mmu_ins_miss;
+extern int mmu_data_read_hit, mmu_data_read_miss;
+extern int mmu_data_write_hit, mmu_data_write_miss;
+#endif
 
 static ALWAYS_INLINE uae_u32 mmu_get_ilong(uaecptr addr, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr, regs.s != 0, false, false) != TTR_NO_MATCH))
-               return x_phys_get_ilong(addr);
-       if (likely(mmu_lookup(addr, false, false, &cl)))
-               return x_phys_get_ilong(mmu_get_real_address(addr, cl));
-       return mmu_get_ilong_slow(addr, regs.s != 0, size, cl);
+       if ((!mmu_ttr_enabled_ins || mmu_match_ttr_ins(addr,regs.s!=0) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_IPAGECACHE
+               if (((addr & mmu_pagemaski) | regs.s) == atc_last_ins_laddr) {
+#if CACHE_HIT_COUNT
+                       mmu_ins_hit++;
+#endif
+                       addr = atc_last_ins_paddr | (addr & mmu_pagemask);
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_ins_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, regs.s!=0, false, false, size, false);
+#if MMU_IPAGECACHE
+               }
+#endif
+       }
+       return phys_get_long(addr);
 }
 
-static ALWAYS_INLINE uae_u16 mmu_get_word(uaecptr addr, bool data, int size, bool rmw)
+static ALWAYS_INLINE uae_u16 mmu_get_iword(uaecptr addr, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,regs.s != 0,data,rmw)!=TTR_NO_MATCH))
-               return x_phys_get_word(addr);
-       if (likely(mmu_lookup(addr, data, false, &cl)))
-               return x_phys_get_word(mmu_get_real_address(addr, cl));
-       return mmu_get_word_slow(addr, regs.s != 0, data, size, rmw, cl);
+       if ((!mmu_ttr_enabled_ins || mmu_match_ttr_ins(addr,regs.s!=0) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_IPAGECACHE
+               if (((addr & mmu_pagemaski) | regs.s) == atc_last_ins_laddr) {
+#if CACHE_HIT_COUNT
+                       mmu_ins_hit++;
+#endif
+                       addr = atc_last_ins_paddr | (addr & mmu_pagemask);
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_ins_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, regs.s!=0, false, false, size, false);
+#if MMU_IPAGECACHE
+               }
+#endif
+       }
+       return phys_get_word(addr);
 }
 
-static ALWAYS_INLINE uae_u16 mmu_get_iword(uaecptr addr, int size)
+
+static ALWAYS_INLINE uae_u32 mmu_get_long(uaecptr addr, bool data, int size, bool rmw)
 {
-       struct mmu_atc_line *cl;
+       if ((!mmu_ttr_enabled || mmu_match_ttr(addr,regs.s!=0,data) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | regs.s;
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_read[idx2].log == idx1) {
+                       addr = atc_data_cache_read[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_read_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_read_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, regs.s!=0, data, false, size, rmw);
+#if MMU_DPAGECACHE
+               }
+#endif
+       }
+       return phys_get_long(addr);
+}
 
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr, regs.s != 0, false, false) != TTR_NO_MATCH))
-               return x_phys_get_iword(addr);
-       if (likely(mmu_lookup(addr, false, false, &cl)))
-               return x_phys_get_iword(mmu_get_real_address(addr, cl));
-       return mmu_get_iword_slow(addr, regs.s != 0, size, cl);
+static ALWAYS_INLINE uae_u16 mmu_get_word(uaecptr addr, bool data, int size, bool rmw)
+{
+       if ((!mmu_ttr_enabled || mmu_match_ttr(addr,regs.s!=0,data) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | regs.s;
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_read[idx2].log == idx1) {
+                       addr = atc_data_cache_read[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_read_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_read_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, regs.s!=0, data, false, size, rmw);
+#if MMU_DPAGECACHE
+               }
+#endif
+       }
+       return phys_get_word(addr);
 }
 
 static ALWAYS_INLINE uae_u8 mmu_get_byte(uaecptr addr, bool data, int size, bool rmw)
 {
-       struct mmu_atc_line *cl;
-
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,regs.s != 0,data,rmw)!=TTR_NO_MATCH))
-               return x_phys_get_byte(addr);
-       if (likely(mmu_lookup(addr, data, false, &cl)))
-               return x_phys_get_byte(mmu_get_real_address(addr, cl));
-       return mmu_get_byte_slow(addr, regs.s != 0, data, size, rmw, cl);
+       if ((!mmu_ttr_enabled || mmu_match_ttr(addr,regs.s!=0,data) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | regs.s;
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_read[idx2].log == idx1) {
+                       addr = atc_data_cache_read[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_read_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_read_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, regs.s!=0, data, false, size, rmw);
+#if MMU_DPAGECACHE
+               }
+#endif
+}
+       return phys_get_byte(addr);
 }
 
 static ALWAYS_INLINE void mmu_put_long(uaecptr addr, uae_u32 val, bool data, int size, bool rmw)
 {
-       struct mmu_atc_line *cl;
-
-       //                                        addr,super,data
-       if ((!regs.mmu_enabled) || mmu_match_ttr_write(addr,regs.s != 0,data,val,size,rmw)==TTR_OK_MATCH) {
-               x_phys_put_long(addr,val);
-               return;
+       if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,regs.s!=0,data,val,size,rmw) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | regs.s;
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_write[idx2].log == idx1) {
+                       addr = atc_data_cache_write[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_write_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_write_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, val, regs.s!=0, data, true, size, rmw);
+#if MMU_DPAGECACHE
+               }
+#endif
        }
-       if (likely(mmu_lookup(addr, data, true, &cl)))
-               x_phys_put_long(mmu_get_real_address(addr, cl), val);
-       else
-               mmu_put_long_slow(addr, val, regs.s != 0, data, size, rmw, cl);
+       phys_put_long(addr, val);
 }
 
 static ALWAYS_INLINE void mmu_put_word(uaecptr addr, uae_u16 val, bool data, int size, bool rmw)
 {
-       struct mmu_atc_line *cl;
-
-       //                                        addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr,regs.s != 0,data,val,size,rmw)==TTR_OK_MATCH)) {
-               x_phys_put_word(addr,val);
-               return;
+       if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,regs.s!=0,data,val,size,rmw) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | regs.s;
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_write[idx2].log == idx1) {
+                       addr = atc_data_cache_write[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_write_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_write_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, val, regs.s!=0, data, true, size, rmw);
+#if MMU_DPAGECACHE
+               }
+#endif
        }
-       if (likely(mmu_lookup(addr, data, true, &cl)))
-               x_phys_put_word(mmu_get_real_address(addr, cl), val);
-       else
-               mmu_put_word_slow(addr, val, regs.s != 0, data, size, rmw, cl);
+       phys_put_word(addr, val);
 }
 
 static ALWAYS_INLINE void mmu_put_byte(uaecptr addr, uae_u8 val, bool data, int size, bool rmw)
 {
-       struct mmu_atc_line *cl;
-
-       //                                        addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr,regs.s != 0,data,val,size,rmw)==TTR_OK_MATCH)) {
-               x_phys_put_byte(addr,val);
-               return;
+       if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,regs.s!=0,data,val,size,rmw) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | regs.s;
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_write[idx2].log == idx1) {
+                       addr = atc_data_cache_write[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_write_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_write_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, val, regs.s!=0, data, true, size, rmw);
+#if MMU_DPAGECACHE
+               }
+#endif
        }
-       if (likely(mmu_lookup(addr, data, true, &cl)))
-               x_phys_put_byte(mmu_get_real_address(addr, cl), val);
-       else
-               mmu_put_byte_slow(addr, val, regs.s != 0, data, size, rmw, cl);
+       phys_put_byte(addr, val);
 }
 
-static ALWAYS_INLINE uae_u32 mmu_get_user_long(uaecptr addr, bool super, bool data, bool write, int size)
+static ALWAYS_INLINE uae_u32 mmu_get_user_long(uaecptr addr, bool super, bool write, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)!=TTR_NO_MATCH))
-               return x_phys_get_long(addr);
-       if (likely(mmu_user_lookup(addr, super, data, write, &cl)))
-               return x_phys_get_long(mmu_get_real_address(addr, cl));
-       return mmu_get_long_slow(addr, super, data, size, false, cl);
+       if ((!mmu_ttr_enabled || mmu_match_ttr(addr,super,true) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_read[idx2].log == idx1) {
+                       addr = atc_data_cache_read[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_read_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_read_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, super, true, write, size, false);
+#if MMU_DPAGECACHE
+               }
+#endif
+       }
+       return phys_get_long(addr);
 }
 
-static ALWAYS_INLINE uae_u16 mmu_get_user_word(uaecptr addr, bool super, bool data, bool write, int size)
+static ALWAYS_INLINE uae_u16 mmu_get_user_word(uaecptr addr, bool super, bool write, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)!=TTR_NO_MATCH))
-               return x_phys_get_word(addr);
-       if (likely(mmu_user_lookup(addr, super, data, write, &cl)))
-               return x_phys_get_word(mmu_get_real_address(addr, cl));
-       return mmu_get_word_slow(addr, super, data, size, false, cl);
+       if ((!mmu_ttr_enabled || mmu_match_ttr(addr,super,true) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_read[idx2].log == idx1) {
+                       addr = atc_data_cache_read[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_read_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_read_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, super, true, write, size, false);
+#if MMU_DPAGECACHE
+               }
+#endif
+       }
+       return phys_get_word(addr);
 }
 
-static ALWAYS_INLINE uae_u8 mmu_get_user_byte(uaecptr addr, bool super, bool data, bool write, int size)
+static ALWAYS_INLINE uae_u8 mmu_get_user_byte(uaecptr addr, bool super, bool write, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                       addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)!=TTR_NO_MATCH))
-               return x_phys_get_byte(addr);
-       if (likely(mmu_user_lookup(addr, super, data, write, &cl)))
-               return x_phys_get_byte(mmu_get_real_address(addr, cl));
-       return mmu_get_byte_slow(addr, super, data, size, false, cl);
+       if ((!mmu_ttr_enabled || mmu_match_ttr(addr,super,true) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_read[idx2].log == idx1) {
+                       addr = atc_data_cache_read[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_read_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_read_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, 0, super, true, write, size, false);
+#if MMU_DPAGECACHE
+               }
+#endif
+       }
+       return phys_get_byte(addr);
 }
 
-static ALWAYS_INLINE void mmu_put_user_long(uaecptr addr, uae_u32 val, bool super, bool data, int size)
+static ALWAYS_INLINE void mmu_put_user_long(uaecptr addr, uae_u32 val, bool super, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                        addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)==TTR_OK_MATCH)) {
-               x_phys_put_long(addr,val);
-               return;
+       if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,super,true,val,size,false) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_write[idx2].log == idx1) {
+                       addr = atc_data_cache_write[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_write_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_write_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, val, super, true, true, size, false);
+#if MMU_DPAGECACHE
+               }
+#endif
        }
-       if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
-               x_phys_put_long(mmu_get_real_address(addr, cl), val);
-       else
-               mmu_put_long_slow(addr, val, super, data, size, false, cl);
+       phys_put_long(addr, val);
 }
 
-static ALWAYS_INLINE void mmu_put_user_word(uaecptr addr, uae_u16 val, bool super, bool data, int size)
+static ALWAYS_INLINE void mmu_put_user_word(uaecptr addr, uae_u16 val, bool super, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                        addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)==TTR_OK_MATCH)) {
-               x_phys_put_word(addr,val);
-               return;
+       if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,super,true,val,size,false) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_write[idx2].log == idx1) {
+                       addr = atc_data_cache_write[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_write_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_write_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, val, super, true, true, size, false);
+#if MMU_DPAGECACHE
+               }
+#endif
        }
-       if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
-               x_phys_put_word(mmu_get_real_address(addr, cl), val);
-       else
-               mmu_put_word_slow(addr, val, super, data, size, false, cl);
+       phys_put_word(addr, val);
 }
 
-static ALWAYS_INLINE void mmu_put_user_byte(uaecptr addr, uae_u8 val, bool super, bool data, int size)
+static ALWAYS_INLINE void mmu_put_user_byte(uaecptr addr, uae_u8 val, bool super, int size)
 {
-       struct mmu_atc_line *cl;
-
-       //                                        addr,super,data
-       if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)==TTR_OK_MATCH)) {
-               x_phys_put_byte(addr,val);
-               return;
+       if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,super,true,val,size,false) == TTR_NO_MATCH) && regs.mmu_enabled) {
+#if MMU_DPAGECACHE
+               uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
+               uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
+               if (atc_data_cache_write[idx2].log == idx1) {
+                       addr = atc_data_cache_write[idx2].phys | (addr & mmu_pagemask);
+#if CACHE_HIT_COUNT
+                       mmu_data_write_hit++;
+#endif
+               } else {
+#if CACHE_HIT_COUNT
+                       mmu_data_write_miss++;
+#endif
+#endif
+                       addr = mmu_translate(addr, val, super, true, true, size, false);
+#if MMU_DPAGECACHE
+               }
+#endif
        }
-       if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
-               x_phys_put_byte(mmu_get_real_address(addr, cl), val);
-       else
-               mmu_put_byte_slow(addr, val, super, data, size, false, cl);
+       phys_put_byte(addr, val);
 }
 
 
 static ALWAYS_INLINE void HWput_l(uaecptr addr, uae_u32 l)
 {
-    put_long (addr, l);
+       put_long (addr, l);
 }
 static ALWAYS_INLINE void HWput_w(uaecptr addr, uae_u32 w)
 {
-    put_word (addr, w);
+       put_word (addr, w);
 }
 static ALWAYS_INLINE void HWput_b(uaecptr addr, uae_u32 b)
 {
-    put_byte (addr, b);
+       put_byte (addr, b);
 }
 static ALWAYS_INLINE uae_u32 HWget_l(uaecptr addr)
 {
-    return get_long (addr);
+       return get_long (addr);
 }
 static ALWAYS_INLINE uae_u32 HWget_w(uaecptr addr)
 {
-    return get_word (addr);
+       return get_word (addr);
 }
 static ALWAYS_INLINE uae_u32 HWget_b(uaecptr addr)
 {
-    return get_byte (addr);
+       return get_byte (addr);
 }
 
-static ALWAYS_INLINE uae_u32 uae_mmu040_get_ilong(uaecptr addr)
+#if MMU_ICACHE
+#define MMU_ICACHE_SZ 4096
+struct mmu_icache
 {
-       if (unlikely(is_unaligned(addr, 4)))
-               return mmu_get_ilong_unaligned(addr);
-       return mmu_get_ilong(addr, sz_long);
+       uae_u16 data;
+       uae_u32 addr;
+};
+
+extern struct mmu_icache mmu_icache_data[MMU_ICACHE_SZ];
+
+static ALWAYS_INLINE uae_u16 uae_mmu040_getc_iword(uaecptr addr)
+{
+       int icidx = (addr & (MMU_ICACHE_SZ - 1)) | regs.s;
+       if (addr != mmu_icache_data[icidx].addr || !(regs.cacr & 0x8000)) {
+               mmu_icache_data[icidx].data = mmu_get_iword(addr, sz_word);
+               mmu_icache_data[icidx].addr = addr;
+               return mmu_icache_data[icidx].data;
+       } else {
+               return mmu_icache_data[icidx].data;
+       }
 }
+#endif
+
 static ALWAYS_INLINE uae_u16 uae_mmu040_get_iword(uaecptr addr)
 {
+#if MMU_ICACHE
+       return uae_mmu040_getc_iword(addr);
+#else
        return mmu_get_iword(addr, sz_word);
+#endif
+}
+static ALWAYS_INLINE uae_u32 uae_mmu040_get_ilong(uaecptr addr)
+{
+#if MMU_ICACHE
+       uae_u32 result = uae_mmu040_getc_iword(addr);
+       result <<= 16;
+       result |= uae_mmu040_getc_iword(addr + 2);
+       return result;
+#else
+       if (unlikely(is_unaligned(addr, 4)))
+               return mmu_get_ilong_unaligned(addr);
+       return mmu_get_ilong(addr, sz_long);
+#endif
 }
 static ALWAYS_INLINE uae_u16 uae_mmu040_get_ibyte(uaecptr addr)
 {
+#if MMU_ICACHE
+       uae_u16 result = uae_mmu040_getc_iword(addr & ~1);
+       return (addr & 1) ? result & 0xFF : result >> 8;
+#else
        return mmu_get_byte(addr, false, sz_byte, false);
+#endif
 }
 static ALWAYS_INLINE uae_u32 uae_mmu040_get_long(uaecptr addr)
 {
@@ -724,193 +762,193 @@ static ALWAYS_INLINE void uae_mmu_put_move16(uaecptr addr, uae_u32 *val)
 // normal 040
 STATIC_INLINE void put_byte_mmu040 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu040_put_byte (addr, v);
+       uae_mmu040_put_byte (addr, v);
 }
 STATIC_INLINE void put_word_mmu040 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu040_put_word (addr, v);
+       uae_mmu040_put_word (addr, v);
 }
 STATIC_INLINE void put_long_mmu040 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu040_put_long (addr, v);
+       uae_mmu040_put_long (addr, v);
 }
 STATIC_INLINE uae_u32 get_byte_mmu040 (uaecptr addr)
 {
-    return uae_mmu040_get_byte (addr);
+       return uae_mmu040_get_byte (addr);
 }
 STATIC_INLINE uae_u32 get_word_mmu040 (uaecptr addr)
 {
-    return uae_mmu040_get_word (addr);
+       return uae_mmu040_get_word (addr);
 }
 STATIC_INLINE uae_u32 get_long_mmu040 (uaecptr addr)
 {
-    return uae_mmu040_get_long (addr);
+       return uae_mmu040_get_long (addr);
 }
 // normal 060
 STATIC_INLINE void put_byte_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu060_put_byte (addr, v, false);
+       uae_mmu060_put_byte (addr, v, false);
 }
 STATIC_INLINE void put_word_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu060_put_word (addr, v, false);
+       uae_mmu060_put_word (addr, v, false);
 }
 STATIC_INLINE void put_long_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu060_put_long (addr, v, false);
+       uae_mmu060_put_long (addr, v, false);
 }
 STATIC_INLINE uae_u32 get_byte_mmu060 (uaecptr addr)
 {
-    return uae_mmu060_get_byte (addr, false);
+       return uae_mmu060_get_byte (addr, false);
 }
 STATIC_INLINE uae_u32 get_word_mmu060 (uaecptr addr)
 {
-    return uae_mmu060_get_word (addr, false);
+       return uae_mmu060_get_word (addr, false);
 }
 STATIC_INLINE uae_u32 get_long_mmu060 (uaecptr addr)
 {
-    return uae_mmu060_get_long (addr, false);
+       return uae_mmu060_get_long (addr, false);
 }
 
 STATIC_INLINE void get_move16_mmu (uaecptr addr, uae_u32 *v)
 {
-    uae_mmu_get_move16 (addr, v);
+       uae_mmu_get_move16 (addr, v);
 }
 STATIC_INLINE void put_move16_mmu (uaecptr addr, uae_u32 *v)
 {
-    uae_mmu_put_move16 (addr, v);
+       uae_mmu_put_move16 (addr, v);
 }
 
 // locked rmw 060
 STATIC_INLINE void put_lrmw_byte_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu_put_lrmw (addr, v, sz_byte, 1);
+       uae_mmu_put_lrmw (addr, v, sz_byte, 1);
 }
 STATIC_INLINE void put_lrmw_word_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu_put_lrmw (addr, v, sz_word, 1);
+       uae_mmu_put_lrmw (addr, v, sz_word, 1);
 }
 STATIC_INLINE void put_lrmw_long_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu_put_lrmw (addr, v, sz_long, 1);
+       uae_mmu_put_lrmw (addr, v, sz_long, 1);
 }
 STATIC_INLINE uae_u32 get_lrmw_byte_mmu060 (uaecptr addr)
 {
-    return uae_mmu_get_lrmw (addr, sz_byte, 1);
+       return uae_mmu_get_lrmw (addr, sz_byte, 1);
 }
 STATIC_INLINE uae_u32 get_lrmw_word_mmu060 (uaecptr addr)
 {
-    return uae_mmu_get_lrmw (addr, sz_word, 1);
+       return uae_mmu_get_lrmw (addr, sz_word, 1);
 }
 STATIC_INLINE uae_u32 get_lrmw_long_mmu060 (uaecptr addr)
 {
-    return uae_mmu_get_lrmw (addr, sz_long, 1);
+       return uae_mmu_get_lrmw (addr, sz_long, 1);
 }
 // normal rmw 060
 STATIC_INLINE void put_rmw_byte_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu060_put_byte (addr, v, true);
+       uae_mmu060_put_byte (addr, v, true);
 }
 STATIC_INLINE void put_rmw_word_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu060_put_word (addr, v, true);
+       uae_mmu060_put_word (addr, v, true);
 }
 STATIC_INLINE void put_rmw_long_mmu060 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu060_put_long (addr, v, true);
+       uae_mmu060_put_long (addr, v, true);
 }
 STATIC_INLINE uae_u32 get_rmw_byte_mmu060 (uaecptr addr)
 {
-    return uae_mmu060_get_byte (addr, true);
+       return uae_mmu060_get_byte (addr, true);
 }
 STATIC_INLINE uae_u32 get_rmw_word_mmu060 (uaecptr addr)
 {
-    return uae_mmu060_get_word (addr, true);
+       return uae_mmu060_get_word (addr, true);
 }
 STATIC_INLINE uae_u32 get_rmw_long_mmu060 (uaecptr addr)
 {
-    return uae_mmu060_get_long (addr, true);
+       return uae_mmu060_get_long (addr, true);
 }
 // locked rmw 040
 STATIC_INLINE void put_lrmw_byte_mmu040 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu_put_lrmw (addr, v, sz_byte, 0);
+       uae_mmu_put_lrmw (addr, v, sz_byte, 0);
 }
 STATIC_INLINE void put_lrmw_word_mmu040 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu_put_lrmw (addr, v, sz_word, 0);
+       uae_mmu_put_lrmw (addr, v, sz_word, 0);
 }
 STATIC_INLINE void put_lrmw_long_mmu040 (uaecptr addr, uae_u32 v)
 {
-    uae_mmu_put_lrmw (addr, v, sz_long, 0);
+       uae_mmu_put_lrmw (addr, v, sz_long, 0);
 }
 STATIC_INLINE uae_u32 get_lrmw_byte_mmu040 (uaecptr addr)
 {
-    return uae_mmu_get_lrmw (addr, sz_byte, 0);
+       return uae_mmu_get_lrmw (addr, sz_byte, 0);
 }
 STATIC_INLINE uae_u32 get_lrmw_word_mmu040 (uaecptr addr)
 {
-    return uae_mmu_get_lrmw (addr, sz_word, 0);
+       return uae_mmu_get_lrmw (addr, sz_word, 0);
 }
 STATIC_INLINE uae_u32 get_lrmw_long_mmu040 (uaecptr addr)
 {
-    return uae_mmu_get_lrmw (addr, sz_long, 0);
+       return uae_mmu_get_lrmw (addr, sz_long, 0);
 }
 
 STATIC_INLINE uae_u32 get_ibyte_mmu040 (int o)
 {
-    uae_u32 pc = m68k_getpci () + o;
-    return uae_mmu040_get_iword (pc);
+       uae_u32 pc = m68k_getpci () + o;
+       return uae_mmu040_get_iword (pc);
 }
 STATIC_INLINE uae_u32 get_iword_mmu040 (int o)
 {
-    uae_u32 pc = m68k_getpci () + o;
-    return uae_mmu040_get_iword (pc);
+       uae_u32 pc = m68k_getpci () + o;
+       return uae_mmu040_get_iword (pc);
 }
 STATIC_INLINE uae_u32 get_ilong_mmu040 (int o)
 {
-    uae_u32 pc = m68k_getpci () + o;
-    return uae_mmu040_get_ilong (pc);
+       uae_u32 pc = m68k_getpci () + o;
+       return uae_mmu040_get_ilong (pc);
 }
 STATIC_INLINE uae_u32 next_iword_mmu040 (void)
 {
-    uae_u32 pc = m68k_getpci ();
-    m68k_incpci (2);
-    return uae_mmu040_get_iword (pc);
+       uae_u32 pc = m68k_getpci ();
+       m68k_incpci (2);
+       return uae_mmu040_get_iword (pc);
 }
 STATIC_INLINE uae_u32 next_ilong_mmu040 (void)
 {
-    uae_u32 pc = m68k_getpci ();
-    m68k_incpci (4);
-    return uae_mmu040_get_ilong (pc);
+       uae_u32 pc = m68k_getpci ();
+       m68k_incpci (4);
+       return uae_mmu040_get_ilong (pc);
 }
 
 STATIC_INLINE uae_u32 get_ibyte_mmu060 (int o)
 {
-    uae_u32 pc = m68k_getpci () + o;
-    return uae_mmu060_get_iword (pc);
+       uae_u32 pc = m68k_getpci () + o;
+       return uae_mmu060_get_iword (pc);
 }
 STATIC_INLINE uae_u32 get_iword_mmu060 (int o)
 {
-    uae_u32 pc = m68k_getpci () + o;
-    return uae_mmu060_get_iword (pc);
+       uae_u32 pc = m68k_getpci () + o;
+       return uae_mmu060_get_iword (pc);
 }
 STATIC_INLINE uae_u32 get_ilong_mmu060 (int o)
 {
-    uae_u32 pc = m68k_getpci () + o;
-    return uae_mmu060_get_ilong (pc);
+       uae_u32 pc = m68k_getpci () + o;
+       return uae_mmu060_get_ilong (pc);
 }
 STATIC_INLINE uae_u32 next_iword_mmu060 (void)
 {
-    uae_u32 pc = m68k_getpci ();
-    m68k_incpci (2);
-    return uae_mmu060_get_iword (pc);
+       uae_u32 pc = m68k_getpci ();
+       m68k_incpci (2);
+       return uae_mmu060_get_iword (pc);
 }
 STATIC_INLINE uae_u32 next_ilong_mmu060 (void)
 {
-    uae_u32 pc = m68k_getpci ();
-    m68k_incpci (4);
-    return uae_mmu060_get_ilong (pc);
+       uae_u32 pc = m68k_getpci ();
+       m68k_incpci (4);
+       return uae_mmu060_get_ilong (pc);
 }
 
 extern void flush_mmu040 (uaecptr, int);
index 81ec935e762512074a29cefe8b55c0684f4426e4..c72b8140f6893ee8f555d1822f5bb469d6658d98 100644 (file)
@@ -5,6 +5,9 @@
 
 #include "mmu_common.h"
 
+#define MMU_DPAGECACHE030 1
+#define MMU_IPAGECACHE030 1
+
 extern uae_u64 srp_030, crp_030;
 extern uae_u32 tt0_030, tt1_030, tc_030;
 extern uae_u16 mmusr_030;
@@ -60,33 +63,11 @@ TT_info mmu030_decode_tt(uae_u32 TT);
 bool mmu030_decode_tc(uae_u32 TC, bool);
 bool mmu030_decode_rp(uae_u64 RP);
 
-int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write);
-void mmu030_atc_handle_history_bit(int entry_num);
-
-void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l, uae_u32 fc);
-void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l, uae_u32 fc);
-void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l, uae_u32 fc);
-uae_u32 mmu030_get_long_atc(uaecptr addr, int l, uae_u32 fc);
-uae_u16 mmu030_get_word_atc(uaecptr addr, int l, uae_u32 fc);
-uae_u8 mmu030_get_byte_atc(uaecptr addr, int l, uae_u32 fc);
-
-void mmu030_put_atc_generic(uaecptr addr, uae_u32 val, int l, uae_u32 fc, int size, int flags);
-uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int flags, bool checkwrite);
-
-void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask);
-void mmu030_flush_atc_page(uaecptr logical_addr);
-void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask);
 void mmu030_flush_atc_all(void);
 void mmu030_reset(int hardreset);
 void mmu030_set_funcs(void);
 uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write);
 
-int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write);
-int mmu030_match_ttr_access(uaecptr addr, uae_u32 fc, bool write);
-int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc);
-int mmu030_do_match_ttr(uae_u32 tt, TT_info masks, uaecptr addr, uae_u32 fc, bool write);
-int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info masks, uaecptr addr, uae_u32 fc);
-
 void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc);
 void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc);
 void mmu030_put_byte(uaecptr addr, uae_u8  val, uae_u32 fc);
index 8635057fb996dd7ac60c1f8fd0f56d55a57c7dcd..0995c2128fb9e1ac1986a16e078923132a1b1fa0 100644 (file)
@@ -1232,6 +1232,7 @@ void flush_cpu_caches(bool force)
                        regs.cacr &= ~0x400;
                }
        } else if (currprefs.cpu_model >= 68040) {
+               mmu_flush_cache();
                icachelinecnt = 0;
                dcachelinecnt = 0;
                if (doflush) {
@@ -1249,7 +1250,7 @@ void flush_cpu_caches_040(uae_u16 opcode)
 {
        int cache = (opcode >> 6) & 3;
        if (!(cache & 2))
-                       return;
+               return;
        flush_cpu_caches(true);
 }
 
@@ -2449,7 +2450,7 @@ static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32
     }
 #endif
 
-    switch (format) {
+       switch (format) {
         case 0x0: // four word stack frame
         case 0x1: // throwaway four word stack frame
             break;
@@ -4806,7 +4807,7 @@ static void opcodedebug (uae_u32 pc, uae_u16 opcode, bool full)
                ;
        fault = 0;
        TRY(prb) {
-               addr = mmu_translate (pc, (regs.mmu_ssw & 4) ? 1 : 0, 0, 0);
+               addr = mmu_translate (pc, 0, (regs.mmu_ssw & 4) ? 1 : 0, 0, 0, sz_word, false);
        } CATCH (prb) {
                fault = 1;
        } ENDTRY
@@ -7698,7 +7699,7 @@ void exception2 (uaecptr addr, bool read, int size, uae_u32 fc)
                        uae_u32 flags = size == 1 ? MMU030_SSW_SIZE_B : (size == 2 ? MMU030_SSW_SIZE_W : MMU030_SSW_SIZE_L);
                        mmu030_page_fault (addr, read, flags, fc);
                } else {
-                       mmu_bus_error (addr, fc, read == false, size, false, 0, true);
+                       mmu_bus_error (addr, 0, fc, read == false, size, false, 0, true);
                }
        } else {
                last_addr_for_exception_3 = m68k_getpc() + bus_error_offset;