#include "cpummu030.h"
#include "cputbl.h"
+// Prefetch mode and prefetch bus error: always flush and refill prefetch pipeline
+#define MMU030_ALWAYS_FULL_PREFETCH 1
+ // if CPU is 68030 and faulted access' addressing mode was -(an) or (an)+
+// register content is not restored when exception starts.
+#define MMU030_REG_FIXUP 1
+
#define MMU030_OP_DBG_MSG 0
#define MMU030_ATC_DBG_MSG 0
#define MMU030_REG_DBG_MSG 0
#endif
/* for debugging messages */
-char table_letter[4] = {'A','B','C','D'};
+static char table_letter[4] = {'A','B','C','D'};
static const uae_u32 mmu030_size[3] = { MMU030_SSW_SIZE_B, MMU030_SSW_SIZE_W, MMU030_SSW_SIZE_L };
if (!mmu_op30_helper_get_fc(next, &fc))
return true;
-#if 0
+#if MMU030_OP_DBG_MSG
write_log (_T("PLOAD%c: Create ATC entry for %08X, FC = %i\n"), write?'W':'R', extra, fc);
#endif
uae_u32 fc_base;
uae_u32 fc_bits = next & 0x7f;
-#if 0
+#if MMU030_OP_DBG_MSG
switch (mode) {
case 0x1:
write_log(_T("PFLUSH: Flush all entries\n"));
ret.fc_base = (TT&TT_FC_BASE)>>4;
ret.addr_base = TT & TT_ADDR_BASE;
ret.addr_mask = ~(((TT&TT_ADDR_MASK)<<8)|0x00FFFFFF);
-
-#if 0
+
+#if MMU030_OP_DBG_MSG
if ((TT&TT_ENABLE) && !(TT&TT_RWM)) {
write_log(_T("MMU Warning: Transparent translation of read-modify-write cycle is not correctly handled!\n"));
}
mmu030.atc[j].mru = 0;
}
mmu030.atc[entry_num].mru = 1;
-#if MMU030_ATC_DBG_MSG
+#if MMU030_ATC_DBG_MSG > 1
write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
#endif
}
if ((tc_030&TC_ENABLE_SUPERVISOR) && super) {
descr[0] = (srp_030>>32)&0xFFFFFFFF;
descr[1] = srp_030&0xFFFFFFFF;
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Supervisor Root Pointer: %08X%08X\n"),descr[0],descr[1]);
#endif // MMU030_REG_DBG_MSG
} else {
descr[0] = (crp_030>>32)&0xFFFFFFFF;
descr[1] = crp_030&0xFFFFFFFF;
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("CPU Root Pointer: %08X%08X\n"),descr[0],descr[1]);
#endif
}
if (next_size==4) {
descr[0] = desc_get_long(descr_addr[descr_num]);
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Next descriptor: %08X\n"),descr[0]);
#endif
} else {
desc_get_quad(descr_addr[descr_num], descr);
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
#endif
}
mmu030.status |= MMUSR_INVALID;
goto stop_search;
case DESCR_TYPE_EARLY_TERM:
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Early termination page descriptor!\n"));
#endif
early_termination = true;
addr_position = (descr_size==4) ? 0 : 1;
table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Table %c at %08X: index = %i, "),table_letter[t],table_addr,table_index);
#endif // MMU030_REG_DBG_MSG
t++; /* Proceed to the next table */
if (next_size==4) {
descr[0] = desc_get_long(descr_addr[descr_num]);
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Next descriptor: %08X\n"),descr[0]);
#endif
} else {
desc_get_quad(descr_addr[descr_num], descr);
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
#endif
}
case DESCR_TYPE_EARLY_TERM:
/* go to last level table handling code */
if (t<=mmu030.translation.last_table) {
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Early termination page descriptor!\n"));
#endif
early_termination = true;
addr_position = (descr_size==4) ? 0 : 1;
indirect_addr = descr[addr_position]&DESCR_ID_ADDR_MASK;
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Page indirect descriptor at %08X: "),indirect_addr);
#endif
if (next_size==4) {
descr[0] = desc_get_long(descr_addr[descr_num]);
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("descr = %08X\n"),descr[0]);
#endif
} else {
desc_get_quad(descr_addr[descr_num], descr);
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("descr = %08X%08X"),descr[0],descr[1]);
#endif
}
t++;
} while (t<=mmu030.translation.last_table);
page_addr = addr&unused_fields_mask;
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 1
write_log(_T("Logical address unused bits: %08X (mask = %08X)\n"),
page_addr,unused_fields_mask);
#endif
/* Get page address */
addr_position = (descr_size==4) ? 0 : 1;
page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("Page at %08X\n"),page_addr);
#endif // MMU030_REG_DBG_MSG
break;
}
}
-#if MMU030_REG_DBG_MSG
+#if MMU030_REG_DBG_MSG > 2
write_log(_T("ATC is full. Replacing entry %i\n"), i);
#endif
}
mmu030_flush_cache(mmu030.atc[i].logical.addr);
-#if MMU030_ATC_DBG_MSG
+#if MMU030_ATC_DBG_MSG > 1
write_log(_T("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n"), i,
mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
mmu030.atc[i].logical.fc);
break;
}
}
- write_log(_T("%04x %s.%c"), opcode, lookup->name, size);
+ write_log(_T(" %04x %s.%c"), opcode, lookup->name, size);
}
#endif
-// if CPU is 68030 and faulted access' addressing mode was -(an) or (an)+
-// register content is not restored when exception starts.
static uae_u8 mmu030fixupreg(int i)
{
- struct mmufixup *m = &mmufixup[i];
uae_u8 v = 0;
+#if MMU030_REG_FIXUP
+ struct mmufixup *m = &mmufixup[i];
if (m->reg < 0)
return v;
if (!(m->reg & 0x300))
if (m->reg & 0x200) // -(an)?
v |= 1 << 5;
v |= 1 << 6;
+#endif
return v;
}
static void mmu030fixupmod(uae_u8 data, int dir, int idx)
{
+#if MMU030_REG_FIXUP
if (!data)
return;
int reg = data & 7;
struct mmufixup *m = &mmufixup[idx];
m->value += adj;
}
+ write_log("fixup %04x %d %d\n", mmu030_opcode & 0xffff, reg, adj);
+#endif
}
void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
}
regs.wb3_status = 0;
regs.wb2_status = 0;
- regs.mmu_fault_addr = addr;
if (fc & 1) {
regs.mmu_ssw = MMU030_SSW_DF | (MMU030_SSW_DF << 1);
if (!(mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE)) {
mmu030fixupmod(regs.wb3_status, 0, 1);
}
} else {
+ // only used by data fault but word sounds nice
+ flags = MMU030_SSW_SIZE_W;
if (currprefs.cpu_compatible) {
regs.wb2_status = mmu030fixupreg(0);
mmu030fixupmod(regs.wb2_status, 0, 0);
regs.wb3_status = mmu030fixupreg(1);
mmu030fixupmod(regs.wb3_status, 0, 1);
- if (regs.prefetch020_valid[1] != 1 && regs.prefetch020_valid[2] == 1) {
- regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
- } else if (regs.prefetch020_valid[2] != 1) {
- regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
- } else {
- // This happens when CPU prefetches from page
- // end - 4 and both pages are originally invalid.
- regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
- }
+ regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
} else {
regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
}
regs.mmu_ssw |= flags;
regs.mmu_ssw |= fc;
regs.mmu_ssw |= islrmw030 ? MMU030_SSW_RM : 0;
+ regs.mmu_fault_addr = addr;
// temporary store in 68040+ variables because stack frame creation may modify them.
regs.wb3_data = mmu030_data_buffer_out;
regs.wb2_address = mmu030_state[1];
mm030_stageb_address = addr;
#if MMUDEBUG
- write_log(_T("MMU: %02x la=%08X SSW=%04x read=%d size=%d fc=%d pc=%08x ob=%08x "),
+ write_log(_T("MMU: %02x la=%08X SSW=%04x read=%d size=%d fc=%d pc=%08x ob=%08x"),
(mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) ? 0xa : 0xb,
addr, regs.mmu_ssw, read, (flags & MMU030_SSW_SIZE_B) ? 1 : (flags & MMU030_SSW_SIZE_W) ? 2 : 4, fc,
- regs.instruction_pc, mmu030_data_buffer_out, mmu030_opcode & 0xffff);
+ regs.instruction_pc, mmu030_data_buffer_out);
dump_opcode(mmu030_opcode & 0xffff);
+ if (regs.opcode != mmu030_opcode)
+ dump_opcode(regs.opcode & 0xffff);
write_log(_T("\n"));
#endif
ismoves030 = false;
islrmw030 = false;
-#if 0
- if (addr == 0xc1026ea0)
- write_log("!");
-#endif
#if 0
if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0)
write_log("!");
uae_u32 addr_mask = mmu030.translation.page.imask;
uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
-#if MMU030_ATC_DBG_MSG
+#if MMU030_ATC_DBG_MSG > 1
write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"),
l, physical_addr, page_index);
#endif
uae_u32 addr_mask = mmu030.translation.page.imask;
uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
-#if MMU030_ATC_DBG_MSG
+#if MMU030_ATC_DBG_MSG > 1
write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
physical_addr, page_index);
#endif
uae_u32 addr_mask = mmu030.translation.page.imask;
uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
-#if MMU030_ATC_DBG_MSG
+#if MMU030_ATC_DBG_MSG > 1
write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
physical_addr, page_index);
#endif
uae_u32 addr_mask = mmu030.translation.page.imask;
uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
-#if MMU030_ATC_DBG_MSG
+#if MMU030_ATC_DBG_MSG > 1
write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"),
l, physical_addr, page_index);
#endif
uae_u32 addr_mask = mmu030.translation.page.imask;
uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
-#if MMU030_ATC_DBG_MSG
+#if MMU030_ATC_DBG_MSG > 1
write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
physical_addr, page_index);
#endif
mmu030.mmu030_last_logical_address = 0xffffffff;
#endif
- mmu030_cache_state = CACHE_ENABLE_ALL;
- if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
+ mmu030_cache_state = CACHE_ENABLE_ALL;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr, fc, false)) && mmu030.enabled) {
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
if (atc_line_num >= 0) {
addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
return v;
}
-uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
-
+uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc)
+{
uae_u16 v;
#if MMU_IPAGECACHE030
if (((addr & mmu030.translation.page.imask) | fc) == mmu030.mmu030_last_logical_address) {
mmu030.mmu030_last_logical_address = 0xffffffff;
#endif
- mmu030_cache_state = CACHE_ENABLE_ALL;
- if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
+ mmu030_cache_state = CACHE_ENABLE_ALL;
+ if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr, fc, false)) && mmu030.enabled) {
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
if (atc_line_num >= 0) {
addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
// + whatever the instruction itself does.
if (mmu030_state[1] & (1 << idx)) {
- m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
+ m68k_incpci(((mmu030_state[2] >> (idx * 4)) & 15) * 2);
return mmu030_disp_store[idx];
}
oldidx = mmu030_idx;
- dp = next_iword_mmu030c_state ();
+ dp = next_iword_mmu030c_state();
pcadd += 1;
reg = (dp >> 12) & 15;
regd = 0;
if ((dp & 0x30) == 0x20) {
- base += (uae_s32)(uae_s16) next_iword_mmu030c_state ();
+ base += (uae_s32)(uae_s16) next_iword_mmu030c_state();
pcadd += 1;
}
if ((dp & 0x30) == 0x30) {
- base += next_ilong_mmu030c_state ();
+ base += next_ilong_mmu030c_state();
pcadd += 2;
}
if ((dp & 0x3) == 0x2) {
- outer = (uae_s32)(uae_s16) next_iword_mmu030c_state ();
+ outer = (uae_s32)(uae_s16) next_iword_mmu030c_state();
pcadd += 1;
}
if ((dp & 0x3) == 0x3) {
- outer = next_ilong_mmu030c_state ();
+ outer = next_ilong_mmu030c_state();
pcadd += 2;
}
base += regd;
}
if (dp & 0x3) {
- base = get_long_mmu030c_state (base);
+ base = get_long_mmu030c_state(base);
}
if (dp & 0x4) {
base += regd;
uae_u16 sr = get_word_mmu030c(a7);
uae_u32 pc = get_long_mmu030c(a7 + 2);
- uae_u16 format = get_word_mmu030c (a7 + 6);
+ uae_u16 format = get_word_mmu030c(a7 + 6);
uae_u16 frame = format >> 12;
- uae_u16 ssw = get_word_mmu030c (a7 + 10);
+ uae_u16 ssw = get_word_mmu030c(a7 + 10);
uae_u32 fault_addr = get_long_mmu030c(a7 + 16);
// Data output buffer
uae_u32 mmu030_data_buffer_out_v = get_long_mmu030c(a7 + 0x18);
if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
regs.prefetch020_valid[2] = 1;
write_log(_T("Software fixed stage B! opcode = %04x\n"), regs.prefetch020[2]);
+#if 0
+ if (!regs.prefetch020_valid[0]) {
+ regs.prefetch020[0] = regs.prefetch020[1];
+ regs.prefetch020[1] = regs.prefetch020[2];
+ regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
+ regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
+ regs.prefetch020_valid[2] = 0;
+ }
+#endif
}
if ((ssw & MMU030_SSW_FC) && !(ssw & MMU030_SSW_RC)) {
regs.prefetch020_valid[1] = 1;
m68k_setpci (pc);
if (!(ssw & (MMU030_SSW_DF << 1))) {
- if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) {
- // Prefetch was software fixed, continue pipeline refill
- fill_prefetch_030_ntx_continue();
- } else if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1]) {
- // Finished?
+ // software fixed?
+ if (((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) || ((ssw & MMU030_SSW_FC) && !(ssw & MMU030_SSW_RC))) {
fill_prefetch_030_ntx_continue();
- } else if (mmu030_opcode == -1) {
- // Previous branch instruction finished successfully but its pipeline refill
- // step caused the exception, retry the refill, do not retry branch instruction.
- fill_prefetch_030_ntx();
+ } else {
+ // pipeline refill in progress?
+ if (mmu030_opcode == -1) {
+#if MMU030_ALWAYS_FULL_PREFETCH
+ fill_prefetch_030_ntx();
+#else
+ fill_prefetch_030_ntx_continue();
+#endif
+ }
}
}
if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) {
mmu030_retry = false;
if (doprefetch) {
+ mmu030_opcode = -1;
fill_prefetch_030_ntx();
}
}