From 903e83f115141b955f7fab64214e197d115c671c Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Fri, 22 Feb 2019 16:36:15 +0200 Subject: [PATCH] 68030 MMU: generate also short bus error stack frames when possible. --- cpummu30.cpp | 517 +++++++++++++++++++++++++++++---------------------- newcpu.cpp | 54 ++++-- 2 files changed, 324 insertions(+), 247 deletions(-) diff --git a/cpummu30.cpp b/cpummu30.cpp index e8a7f505..2317dc9a 100644 --- a/cpummu30.cpp +++ b/cpummu30.cpp @@ -1784,7 +1784,8 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) mm030_stageb_address = addr; #if MMUDEBUG - write_log(_T("MMU: 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); dump_opcode(mmu030_opcode & 0xffff); @@ -2734,6 +2735,11 @@ void m68k_do_rte_mmu030 (uaecptr a7) uae_u16 frame = format >> 12; uae_u16 ssw = get_word_mmu030(a7 + 10); uae_u32 fault_addr = get_long_mmu030(a7 + 16); + // Data output buffer + uae_u32 mmu030_data_buffer_out_v = get_long_mmu030(a7 + 0x18); + // Internal register, our opcode storage area + uae_u32 oc = get_long_mmu030(a7 + 0x14); + int idxsize = -1; // Fetch last word, real CPU does it to allow OS bus handler to map // the page if frame crosses pages and following page is not resident. @@ -2746,26 +2752,36 @@ void m68k_do_rte_mmu030 (uaecptr a7) mmu030_retry = true; if (frame == 0xa) { + // this is always last write data write fault - // A-frame only in non-prefetch mode and only when - // instruction's first word fetch caused access fault. - // mmu030_opcode_v is always -1 here. - if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) { - uae_u16 stageb = get_word_mmu030(a7 + 0x0e); - mmu030_opcode_stageb = stageb; - write_log(_T("Software fixed stage B! opcode = %04x\n"), stageb); + uae_u32 mmu030_state_1 = get_word_mmu030(a7 + 0x8); + +#if MMU030_DEBUG + if (!(mmu030_state_1 & MMU030_STATEFLAG1_LASTWRITE)) { + write_log(_T("68030 MMU short bus fault but no lastwrite set!?\n")); + } + if (ssw & (MMU030_SSW_FB | MMU030_SSW_FC | MMU030_SSW_FB | MMU030_SSW_RC | MMU030_SSW_RB)) { + write_log(_T("68030 MMU short bus fault and pipeline fault?\n")); + } + if (ssw & MMU030_SSW_RW) { + write_log(_T("68030 MMU short bus fault but read fault!?\n")); } - mmu030_opcode = -1; +#endif - m68k_areg(regs, 7) += 32; - regs.sr = sr; - MakeFromSR_T0(); - if (pc & 1) { - exception3i(0x4E73, pc); - return; + // did we have data fault but DF bit cleared? + if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) { + // DF not set: mark access as done + unalign_clear(); } - m68k_setpci(pc); + mmu030_data_buffer_out = mmu030_data_buffer_out_v; + mmu030_state[0] = 0; + mmu030_state[1] = mmu030_state_1; + mmu030_state[2] = 0; + mmu030_opcode = oc; + mmu030_idx = 0; + + m68k_areg(regs, 7) += 32; } else if (frame == 0xb) { @@ -2775,17 +2791,12 @@ void m68k_do_rte_mmu030 (uaecptr a7) // Internal register, misc flags uae_u32 ps = get_long_mmu030(a7 + 0x28); // Data buffer - uae_u32 mmu030_data_buffer_in_v = get_long_mmu030(a7 + 0x2c);; + uae_u32 mmu030_data_buffer_in_v = get_long_mmu030(a7 + 0x2c); // Misc state data uae_u32 mmu030_state_0 = get_word_mmu030(a7 + 0x30); uae_u32 mmu030_state_1 = get_word_mmu030(a7 + 0x32); uae_u32 mmu030_state_2 = get_word_mmu030(a7 + 0x34); - // Internal register, our opcode storage area - uae_u32 oc = get_long_mmu030(a7 + 0x14); - // Data output buffer - uae_u32 mmu030_data_buffer_out_v = get_long_mmu030(a7 + 0x18); - uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1U : (oc & 0xffff); uae_u32 mmu030_fmovem_store_0 = 0; @@ -2795,10 +2806,10 @@ void m68k_do_rte_mmu030 (uaecptr a7) mmu030_fmovem_store_1 = get_long_mmu030(a7 + 0x5c - (8 + 1) * 4); } - uae_u16 idxsize = get_word_mmu030 (a7 + 0x36); + idxsize = get_word_mmu030(a7 + 0x36); for (int i = 0; i < idxsize + 1; i++) { mmu030_ad_v[i].done = i < idxsize; - mmu030_ad_v[i].val = get_long_mmu030 (a7 + 0x5c - (i + 1) * 4); + mmu030_ad_v[i].val = get_long_mmu030(a7 + 0x5c - (i + 1) * 4); } mmu030_ad_v[idxsize + 1].done = false; @@ -2808,7 +2819,7 @@ void m68k_do_rte_mmu030 (uaecptr a7) mmu030_data_buffer_out_v = mmu030_data_buffer_in_v; if (ssw & MMU030_SSW_RM) { // Read-Modify-Write: whole instruction is considered done - write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc); + write_log(_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc); mmu030_retry = false; } else if (mmu030_state_1 & MMU030_STATEFLAG1_MOVEM1) { // if movem, skip next move @@ -2824,17 +2835,22 @@ void m68k_do_rte_mmu030 (uaecptr a7) } // did we have ins fault and RB bit cleared? if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) { - uae_u16 stageb = get_word_mmu030 (a7 + 0x0e); + uae_u16 stageb = get_word_mmu030(a7 + 0x0e); if (mmu030_opcode_v == -1U) { mmu030_opcode_stageb = stageb; - write_log (_T("Software fixed stage B! opcode = %04x\n"), stageb); + write_log(_T("Software fixed stage B! opcode = %04x\n"), stageb); } else { mmu030_ad_v[idxsize].done = true; mmu030_ad_v[idxsize].val = stageb; - write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode_v, stageb); + write_log(_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode_v, stageb); } } +#if MMU030_DEBUG + if (mmu030_state_1 & MMU030_STATEFLAG1_LASTWRITE) { + write_log(_T("68030 MMU long bus fault but lastwrite set!?\n")); + } +#endif // Retried data access is the only memory access that can be done after this. // restore global state variables @@ -2854,95 +2870,92 @@ void m68k_do_rte_mmu030 (uaecptr a7) } m68k_areg(regs, 7) += 92; - regs.sr = sr; - MakeFromSR_T0(); - if (pc & 1) { - exception3i(0x4E73, pc); - return; - } - m68k_setpci(pc); - if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) { + } + + regs.sr = sr; + MakeFromSR_T0(); + if (pc & 1) { + exception3i(0x4E73, pc); + return; + } + m68k_setpci(pc); + + if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) { - // Locked-Read-Modify-Write restarts whole instruction. - mmu030_ad[0].done = false; + // Locked-Read-Modify-Write restarts whole instruction. + mmu030_ad[0].done = false; - } else if (ssw & MMU030_SSW_DF) { + } else if (ssw & MMU030_SSW_DF) { - // retry faulted access - uaecptr addr = fault_addr; - bool read = (ssw & MMU030_SSW_RW) != 0; - int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long); - int fc = ssw & MMU030_SSW_FC_MASK; + // retry faulted access + uaecptr addr = fault_addr; + bool read = (ssw & MMU030_SSW_RW) != 0; + int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long); + int fc = ssw & MMU030_SSW_FC_MASK; #if MMU030_DEBUG - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { - write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode); - } - } - if (mmu030_ad[idxsize].done) { - write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode); + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { + write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode); } + } + if (idxsize >= 0 && mmu030_ad[idxsize].done) { + write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode); + } #endif #if MMU030_DEBUG - write_log(_T("%08x %08x %08x %08x %08x %d %d %d %08x %08x %04x\n"), - mmu030_state[1], mmu030_state[2], mmu030_disp_store[0], mmu030_disp_store[1], - addr, read, size, fc, mmu030_data_buffer_out, mmu030_ad[idxsize].val, ssw); + write_log(_T("%08x %08x %08x %08x %08x %d %d %d %08x %08x %04x\n"), + mmu030_state[1], mmu030_state[2], mmu030_disp_store[0], mmu030_disp_store[1], + addr, read, size, fc, mmu030_data_buffer_out, idxsize < 0 ? -1 : mmu030_ad[idxsize].val, ssw); #endif - if (read) { - if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { - mmu030_unaligned_read_continue(addr, fc, mmu030_get_generic); - } else { - switch (size) - { - case sz_byte: - mmu030_data_buffer_out = uae_mmu030_get_byte_fcx(addr, fc); - break; - case sz_word: - mmu030_data_buffer_out = uae_mmu030_get_word_fcx(addr, fc); - break; - case sz_long: - mmu030_data_buffer_out = uae_mmu030_get_long_fcx(addr, fc); - break; - } - } - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { - mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; - } else { - mmu030_ad[idxsize].val = mmu030_data_buffer_out; - mmu030_ad[idxsize].done = true; - } + if (read) { + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_read_continue(addr, fc, mmu030_get_generic); } else { - if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { - mmu030_unaligned_write_continue(addr, fc, mmu030_put_generic); - } else { - switch (size) - { - case sz_byte: - uae_mmu030_put_byte_fcx(addr, mmu030_data_buffer_out, fc); - break; - case sz_word: - uae_mmu030_put_word_fcx(addr, mmu030_data_buffer_out, fc); - break; - case sz_long: - uae_mmu030_put_long_fcx(addr, mmu030_data_buffer_out, fc); - break; - } + switch (size) + { + case sz_byte: + mmu030_data_buffer_out = uae_mmu030_get_byte_fcx(addr, fc); + break; + case sz_word: + mmu030_data_buffer_out = uae_mmu030_get_word_fcx(addr, fc); + break; + case sz_long: + mmu030_data_buffer_out = uae_mmu030_get_long_fcx(addr, fc); + break; } - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { - mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; - } else { - mmu030_ad[idxsize].done = true; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (idxsize >= 0) { + mmu030_ad[idxsize].val = mmu030_data_buffer_out; + mmu030_ad[idxsize].done = true; + } + } else { + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_write_continue(addr, fc, mmu030_put_generic); + } else { + switch (size) + { + case sz_byte: + uae_mmu030_put_byte_fcx(addr, mmu030_data_buffer_out, fc); + break; + case sz_word: + uae_mmu030_put_word_fcx(addr, mmu030_data_buffer_out, fc); + break; + case sz_long: + uae_mmu030_put_long_fcx(addr, mmu030_data_buffer_out, fc); + break; } } - - } - - if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) { - mmu030_retry = false; + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (idxsize >= 0) { + mmu030_ad[idxsize].done = true; + } } #if MMU030_DEBUG @@ -2950,7 +2963,10 @@ void m68k_do_rte_mmu030 (uaecptr a7) write_log(_T("mmu030_idx (RTE) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS); } #endif + } + if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) { + mmu030_retry = false; } } @@ -3146,8 +3162,15 @@ void m68k_do_rte_mmu030c (uaecptr a7) uae_u16 format = get_word_mmu030c (a7 + 6); uae_u16 frame = format >> 12; uae_u16 ssw = get_word_mmu030c (a7 + 10); - uae_u32 stagesbc = get_long_mmu030c(a7 + 12); uae_u32 fault_addr = get_long_mmu030c(a7 + 16); + // Data output buffer + uae_u32 mmu030_data_buffer_out_v = get_long_mmu030c(a7 + 0x18); + // Internal register, our opcode storage area + uae_u32 oc = get_long_mmu030c(a7 + 0x14); + uae_u32 stagesbc = get_long_mmu030c(a7 + 12); + + int idxsize = -1; + bool doprefetch = true; // Fetch last word, real CPU does it to allow OS bus handler to map // the page if frame crosses pages and following page is not resident. @@ -3156,36 +3179,80 @@ void m68k_do_rte_mmu030c (uaecptr a7) else get_word_mmu030c(a7 + 32 - 2); - // Internal register, our opcode storage area - uae_u32 oc = get_long_mmu030c(a7 + 0x14); - // Data output buffer - uae_u32 mmu030_data_buffer_out_v = get_long_mmu030c(a7 + 0x18); - // get_disp_ea_020 - uae_u32 mmu030_disp_store_0 = get_long_mmu030c(a7 + 0x1c); - uae_u32 mmu030_disp_store_1 = get_long_mmu030c(a7 + 0x1c + 4); - // Internal register, misc flags - uae_u32 ps = get_long_mmu030c(a7 + 0x28); - // Data buffer - uae_u32 mmu030_data_buffer_in_v = get_long_mmu030c(a7 + 0x2c);; - - uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1U : (oc & 0xffff); - // Misc state data - uae_u32 mmu030_state_0 = get_word_mmu030c(a7 + 0x30); - uae_u32 mmu030_state_1 = get_word_mmu030c(a7 + 0x32); - uae_u32 mmu030_state_2 = get_word_mmu030c(a7 + 0x34); - - uae_u32 mmu030_fmovem_store_0 = 0; - uae_u32 mmu030_fmovem_store_1 = 0; - if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) { - mmu030_fmovem_store_0 = get_long_mmu030c(a7 + 0x5c - (7 + 1) * 4); - mmu030_fmovem_store_1 = get_long_mmu030c(a7 + 0x5c - (8 + 1) * 4); - } - // Rerun "mmu030_opcode" using restored state. mmu030_retry = true; - if (frame == 0xb) { - uae_u16 idxsize = get_word_mmu030c(a7 + 0x36); + if (frame == 0xa) { + // this is always last write data write fault + + uae_u32 mmu030_state_1 = get_word_mmu030c(a7 + 0x8); + uae_u32 ps = get_long_mmu030c(a7 + 0x1c); + +#if MMU030_DEBUG + if (!(mmu030_state_1 & MMU030_STATEFLAG1_LASTWRITE)) { + write_log(_T("68030 MMU short bus fault but no lastwrite set!?\n")); + } + if (ssw & (MMU030_SSW_FB | MMU030_SSW_FC | MMU030_SSW_FB | MMU030_SSW_RC | MMU030_SSW_RB)) { + write_log(_T("68030 MMU short bus fault and pipeline fault?\n")); + } + if (ssw & MMU030_SSW_RW) { + write_log(_T("68030 MMU short bus fault but read fault!?\n")); + } +#endif + // did we have data fault but DF bit cleared? + if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) { + // DF not set: mark access as done + unalign_clear(); + } + + regs.prefetch020_valid[0] = (ps & 1) ? 1 : 0; + regs.prefetch020_valid[1] = (ps & 2) ? 1 : 0; + regs.prefetch020_valid[2] = (ps & 4) ? 1 : 0; + + regs.pipeline_r8[0] = (ps >> 8) & 7; + regs.pipeline_r8[1] = (ps >> 11) & 7; + regs.pipeline_pos = (ps >> 16) & 15; + regs.pipeline_stop = ((ps >> 20) & 15) == 15 ? -1 : (int)(ps >> 20) & 15; + + regs.prefetch020[2] = stagesbc; + regs.prefetch020[1] = stagesbc >> 16; + regs.prefetch020[0] = oc >> 16; + mmu030_opcode_stageb = (uae_u16)oc; + + mmu030_data_buffer_out = mmu030_data_buffer_out_v; + mmu030_state[0] = 0; + mmu030_state[1] = mmu030_state_1; + mmu030_state[2] = 0; + mmu030_idx = 0; + + doprefetch = false; + + m68k_areg(regs, 7) += 32; + + } else if (frame == 0xb) { + + // get_disp_ea_020 + uae_u32 mmu030_disp_store_0 = get_long_mmu030c(a7 + 0x1c); + uae_u32 mmu030_disp_store_1 = get_long_mmu030c(a7 + 0x1c + 4); + // Internal register, misc flags + uae_u32 ps = get_long_mmu030c(a7 + 0x28); + // Data buffer + uae_u32 mmu030_data_buffer_in_v = get_long_mmu030c(a7 + 0x2c);; + // Misc state data + uae_u32 mmu030_state_0 = get_word_mmu030c(a7 + 0x30); + uae_u32 mmu030_state_1 = get_word_mmu030c(a7 + 0x32); + uae_u32 mmu030_state_2 = get_word_mmu030c(a7 + 0x34); + + uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1U : (oc & 0xffff); + + uae_u32 mmu030_fmovem_store_0 = 0; + uae_u32 mmu030_fmovem_store_1 = 0; + if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) { + mmu030_fmovem_store_0 = get_long_mmu030c(a7 + 0x5c - (7 + 1) * 4); + mmu030_fmovem_store_1 = get_long_mmu030c(a7 + 0x5c - (8 + 1) * 4); + } + + idxsize = get_word_mmu030c(a7 + 0x36); for (int i = 0; i < idxsize + 1; i++) { mmu030_ad_v[i].done = i < idxsize; mmu030_ad_v[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4); @@ -3198,7 +3265,7 @@ void m68k_do_rte_mmu030c (uaecptr a7) mmu030_data_buffer_out_v = mmu030_data_buffer_in_v; if (ssw & MMU030_SSW_RM) { // Read-Modify-Write: whole instruction is considered done - write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc); + write_log(_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc); mmu030_retry = false; } else if (mmu030_state_1 & MMU030_STATEFLAG1_MOVEM1) { // if movem, skip next move @@ -3213,6 +3280,11 @@ void m68k_do_rte_mmu030c (uaecptr a7) unalign_clear(); } +#if MMU030_DEBUG + if (mmu030_state_1 & MMU030_STATEFLAG1_LASTWRITE) { + write_log(_T("68030 MMU long bus fault but lastwrite set!?\n")); + } +#endif // Retried data access is the only memory access that can be done after this. regs.prefetch020_valid[0] = (ps & 1) ? 1 : 0; @@ -3229,11 +3301,11 @@ void m68k_do_rte_mmu030c (uaecptr a7) 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]); + write_log(_T("Software fixed stage B! opcode = %04x\n"), regs.prefetch020[2]); } if ((ssw & MMU030_SSW_FC) && !(ssw & MMU030_SSW_RC)) { regs.prefetch020_valid[1] = 1; - write_log (_T("Software fixed stage C! opcode = %04x\n"), regs.prefetch020[1]); + write_log(_T("Software fixed stage C! opcode = %04x\n"), regs.prefetch020[1]); } // restore global state variables @@ -3252,116 +3324,107 @@ void m68k_do_rte_mmu030c (uaecptr a7) mmu030_ad[i].val = mmu030_ad_v[i].val; } - m68k_areg (regs, 7) += 92; - regs.sr = sr; - MakeFromSR_T0(); - if (pc & 1) { - exception3i (0x4E73, pc); - return; - } - m68k_setpci (pc); - - if (!(ssw & (MMU030_SSW_DF << 1))) { - if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) { - // Prefetch was software fixed, continue pipeline refill - fill_prefetch_030_ntx_continue(); - } else if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1]) { - // Finished? - fill_prefetch_030_ntx_continue(); - } else if (mmu030_opcode == -1) { - // Previous branch instruction finished successfully but its pipeline refill - // step caused the exception, retry the refill, do not retry branch instruction. - fill_prefetch_030_ntx(); - } + m68k_areg(regs, 7) += 92; + + } + + regs.sr = sr; + MakeFromSR_T0(); + if (pc & 1) { + exception3i (0x4E73, pc); + return; + } + m68k_setpci (pc); + + if (!(ssw & (MMU030_SSW_DF << 1))) { + if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) { + // Prefetch was software fixed, continue pipeline refill + fill_prefetch_030_ntx_continue(); + } else if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1]) { + // Finished? + fill_prefetch_030_ntx_continue(); + } else if (mmu030_opcode == -1) { + // Previous branch instruction finished successfully but its pipeline refill + // step caused the exception, retry the refill, do not retry branch instruction. + fill_prefetch_030_ntx(); } + } - if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) { + if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) { - // Locked-Read-Modify-Write restarts whole instruction. - mmu030_ad[0].done = false; + // Locked-Read-Modify-Write restarts whole instruction. + mmu030_ad[0].done = false; - } else if (ssw & MMU030_SSW_DF) { - // retry faulted access - uaecptr addr = fault_addr; - bool read = (ssw & MMU030_SSW_RW) != 0; - int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long); - int fc = ssw & 7; + } else if (ssw & MMU030_SSW_DF) { + // retry faulted access + uaecptr addr = fault_addr; + bool read = (ssw & MMU030_SSW_RW) != 0; + int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long); + int fc = ssw & 7; #if MMU030_DEBUG - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { - write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode); - } - } else { - if (mmu030_ad[idxsize].done) { - write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode); - } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { + write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode); } + } else { + if (idxsize >= 0 && mmu030_ad[idxsize].done) { + write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode); + } + } #endif - if (read) { - if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { - mmu030_unaligned_read_continue(addr, fc, read_dcache030_retry); - } else { - switch (size) - { - case sz_byte: - mmu030_data_buffer_out = read_data_030_fc_bget(addr, fc); - break; - case sz_word: - mmu030_data_buffer_out = read_data_030_fc_wget(addr, fc); - break; - case sz_long: - mmu030_data_buffer_out = read_data_030_fc_lget(addr, fc); - break; - } - } - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { - mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; - } else { - mmu030_ad[idxsize].val = mmu030_data_buffer_out; - mmu030_ad[idxsize].done = true; - } + if (read) { + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_read_continue(addr, fc, read_dcache030_retry); } else { - if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { - mmu030_unaligned_write_continue(addr, fc, write_dcache030_retry); - } else { - switch (size) - { - case sz_byte: - write_data_030_fc_bput(addr, mmu030_data_buffer_out, fc); - break; - case sz_word: - write_data_030_fc_wput(addr, mmu030_data_buffer_out, fc); - break; - case sz_long: - write_data_030_fc_lput(addr, mmu030_data_buffer_out, fc); - break; - } + switch (size) + { + case sz_byte: + mmu030_data_buffer_out = read_data_030_fc_bget(addr, fc); + break; + case sz_word: + mmu030_data_buffer_out = read_data_030_fc_wget(addr, fc); + break; + case sz_long: + mmu030_data_buffer_out = read_data_030_fc_lget(addr, fc); + break; } - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { - mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; - } else { - mmu030_ad[idxsize].done = true; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (idxsize >= 0) { + mmu030_ad[idxsize].val = mmu030_data_buffer_out; + mmu030_ad[idxsize].done = true; + } + } else { + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_write_continue(addr, fc, write_dcache030_retry); + } else { + switch (size) + { + case sz_byte: + write_data_030_fc_bput(addr, mmu030_data_buffer_out, fc); + break; + case sz_word: + write_data_030_fc_wput(addr, mmu030_data_buffer_out, fc); + break; + case sz_long: + write_data_030_fc_lput(addr, mmu030_data_buffer_out, fc); + break; } } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (idxsize >= 0) { + mmu030_ad[idxsize].done = true; + } } + } - if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) { - mmu030_retry = false; + if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) { + mmu030_retry = false; + if (doprefetch) { fill_prefetch_030_ntx(); } - - } else { - - m68k_areg (regs, 7) += 32; - - regs.sr = sr; - MakeFromSR_T0(); - if (pc & 1) { - exception3i(0x4E73, pc); - return; - } - m68k_setpci(pc); - } } diff --git a/newcpu.cpp b/newcpu.cpp index ff94ed94..37971ccc 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -2309,14 +2309,14 @@ static uaecptr ShowEA_disp(uaecptr *pcp, uaecptr base, TCHAR *buffer, const TCHA } if ((dp & 0x04) == 0x00 && name) { - _stprintf(p, _T("%s,"), name); - p += _tcslen(p); - } + _stprintf(p, _T("%s,"), name); + p += _tcslen(p); + } if (dr[0] && (dp & 0x04) == 0) { - _stprintf(p, _T("%s%s,"), dr, mult); - p += _tcslen(p); - } + _stprintf(p, _T("%s%s,"), dr, mult); + p += _tcslen(p); + } if (dp & 3) { if (p[-1] == ',') @@ -2326,9 +2326,9 @@ static uaecptr ShowEA_disp(uaecptr *pcp, uaecptr base, TCHAR *buffer, const TCHA } if (dr[0] && (dp & 0x04) != 0) { - _stprintf(p, _T("%s%s,"), dr, mult); - p += _tcslen(p); - } + _stprintf(p, _T("%s%s,"), dr, mult); + p += _tcslen(p); + } if ((dp & 0x03) == 0x02) { outer = (uae_s32)(uae_s16)get_iword_debug(pc); @@ -3193,9 +3193,6 @@ static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 x_put_long (m68k_areg (regs, 7), oldpc); break; case 0xB: // long bus cycle fault stack frame (68020, 68030) - // We always use B frame because it is easier to emulate, - // our PC always points at start of instruction but A frame assumes - // it is + 2 and handling this properly is not easy. // Store state information to internal register space #if MMU030_DEBUG if (mmu030_idx >= MAX_MMU030_ACCESS) { @@ -3259,14 +3256,29 @@ static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 m68k_areg (regs, 7) -= 4; x_put_long (m68k_areg (regs, 7), mmu030_disp_store[1]); /* fall through */ - case 0xA: // short bus cycle fault stack frame (68020, 68030) + case 0xA: + // short bus cycle fault stack frame (68020, 68030) + // used when instruction's last write causes bus fault m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), mmu030_disp_store[0]); + if (format == 0xb) { + x_put_long(m68k_areg(regs, 7), mmu030_disp_store[0]); + } else { + uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0); + ps |= ((regs.pipeline_r8[0] & 7) << 8); + ps |= ((regs.pipeline_r8[1] & 7) << 11); + ps |= ((regs.pipeline_pos & 15) << 16); + ps |= ((regs.pipeline_stop & 15) << 20); + x_put_long(m68k_areg(regs, 7), ps); + } m68k_areg (regs, 7) -= 4; // Data output buffer = value that was going to be written x_put_long (m68k_areg (regs, 7), regs.wb3_data); m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage) + if (format == 0xb) { + x_put_long(m68k_areg(regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage) + } else { + x_put_long(m68k_areg(regs, 7), regs.irc | (regs.prefetch020[0] << 16)); // Internal register (opcode storage) + } m68k_areg (regs, 7) -= 4; x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address m68k_areg (regs, 7) -= 2; @@ -3276,7 +3288,7 @@ static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 m68k_areg (regs, 7) -= 2; x_put_word (m68k_areg (regs, 7), ssw); m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); // Internal register + x_put_word (m68k_areg (regs, 7), regs.wb2_address); // = mmu030_state[1]); break; default: write_log(_T("Unknown exception stack frame format: %X\n"), format); @@ -3362,8 +3374,7 @@ static void Exception_mmu030 (int nr, uaecptr oldpc) m68k_areg (regs, 7) = regs.isp; Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1); } else if (nr == 2) { - if (0) { - // not that simple + if (1 && (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE)) { Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0xA); } else { Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0xB); @@ -6003,10 +6014,12 @@ insretry: if (mmu030_opcode == -1) { // full prefetch fill access fault - // TODO: this should create shorter A-frame mmufixup[0].reg = -1; mmufixup[1].reg = -1; - } else if (!(mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE)) { + } else if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) { + mmufixup[0].reg = -1; + mmufixup[1].reg = -1; + } else { regflags.cznv = f.cznv; regflags.x = f.x; @@ -9257,6 +9270,7 @@ static uae_u16 pipeline_opcode; static void pipeline_020(uaecptr pc) { uae_u16 w = regs.prefetch020[1]; + if (regs.prefetch020_valid[1] == 0) { regs.pipeline_stop = -1; return; -- 2.47.3