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);
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;
}
}
/* }}} */
-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;
}
regs.wb3_status = write ? 0x80 | (ssw & 0x7f) : 0;
+ regs.wb3_data = val;
regs.wb2_status = 0;
if (!write)
ssw |= MMU_SSW_RW;
}
regs.mmu_fault_addr = addr;
+ flush_shortcut_cache();
#if 0
if (m68k_getpc () == 0x0004B0AC) {
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;
}
/*
{
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)
{
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) {
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) {
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) {
}
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)
{
} 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) {
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) {
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) {
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;
}
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;
}
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;
}
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) {
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]);
}
}
#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));
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)
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);
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);
void flush_mmu040 (uaecptr addr, int n)
{
+ mmu_flush_cache();
}
+
void m68k_do_rts_mmu040 (void)
{
uaecptr stack = m68k_areg (regs, 7);
void flush_mmu060 (uaecptr addr, int n)
{
+ mmu_flush_cache();
}
+
void m68k_do_rts_mmu060 (void)
{
uaecptr stack = m68k_areg (regs, 7);
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;
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();
}
}
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'};
struct {
uae_u32 mask;
uae_u32 imask;
- uae_u8 size;
+ uae_u32 size;
+ uae_u32 size1m;
} page;
uae_u8 init_shift;
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---
#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 -- */
}
}
-
-/* -- 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---
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 */
* 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 */
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 */
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:
*
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)
/* 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;
#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 */
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;
}
* 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;
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
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)
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)
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)
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);
}
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);
{
/* 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;
#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
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);
#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
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
};
#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;
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;
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)
{
// 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);
#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;
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);
regs.cacr &= ~0x400;
}
} else if (currprefs.cpu_model >= 68040) {
+ mmu_flush_cache();
icachelinecnt = 0;
dcachelinecnt = 0;
if (doflush) {
{
int cache = (opcode >> 6) & 3;
if (!(cache & 2))
- return;
+ return;
flush_cpu_caches(true);
}
}
#endif
- switch (format) {
+ switch (format) {
case 0x0: // four word stack frame
case 0x1: // throwaway four word stack frame
break;
;
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
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;