From: Toni Wilen Date: Fri, 23 Nov 2018 20:14:39 +0000 (+0200) Subject: 68030 MMU update. Unaligned accesses are now new exception handler emulation compatib... X-Git-Tag: 4100~25 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=393092b42493293256dd3e394f2c39db26b57ed1;p=francis%2Fwinuae.git 68030 MMU update. Unaligned accesses are now new exception handler emulation compatible and retry correctly. Use mmu030_data_buffer_out buffer everywhere instead of special casing MOVEM vs other instructions. --- diff --git a/cpummu.cpp b/cpummu.cpp index 6c9927c1..9d76d39b 100644 --- a/cpummu.cpp +++ b/cpummu.cpp @@ -1109,7 +1109,7 @@ uae_u32 REGPARAM2 sfc_get_long(uaecptr addr) uae_u32 res; ismoves = true; - if (likely(!is_unaligned(addr, 4))) { + if (likely(!is_unaligned_page(addr, 4))) { res = mmu_get_user_long(addr, super, false, sz_long, false); } else { if (likely(!(addr & 1))) { @@ -1151,7 +1151,7 @@ uae_u16 REGPARAM2 sfc_get_word(uaecptr addr) uae_u16 res; ismoves = true; - if (likely(!is_unaligned(addr, 2))) { + if (likely(!is_unaligned_page(addr, 2))) { res = mmu_get_user_word(addr, super, false, sz_word, false); } else { res = (uae_u16)mmu_get_user_byte(addr, super, false, sz_word, false) << 8; @@ -1188,7 +1188,7 @@ void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val) ismoves = true; SAVE_EXCEPTION; TRY(prb) { - if (likely(!is_unaligned(addr, 4))) { + if (likely(!is_unaligned_page(addr, 4))) { mmu_put_user_long(addr, val, super, sz_long, false); } else if (likely(!(addr & 1))) { mmu_put_user_word(addr, val >> 16, super, sz_long, false); @@ -1217,7 +1217,7 @@ void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val) ismoves = true; SAVE_EXCEPTION; TRY(prb) { - if (likely(!is_unaligned(addr, 2))) { + if (likely(!is_unaligned_page(addr, 2))) { mmu_put_user_word(addr, val, super, sz_word, false); } else { mmu_put_user_byte(addr, val >> 8, super, sz_word, false); @@ -1593,13 +1593,13 @@ void uae_mmu_put_lrmw (uaecptr addr, uae_u32 v, int size, int type) if (size == sz_byte) { mmu_put_user_byte(addr, v, regs.s, sz_byte, true); } else if (size == sz_word) { - if (unlikely(is_unaligned(addr, 2))) { + if (unlikely(is_unaligned_page(addr, 2))) { mmu_put_lrmw_word_unaligned(addr, v); } else { mmu_put_user_word(addr, v, regs.s != 0, sz_word, true); } } else { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) mmu_put_lrmw_long_unaligned(addr, v); else mmu_put_user_long(addr, v, regs.s, sz_long, true); @@ -1613,13 +1613,13 @@ uae_u32 uae_mmu_get_lrmw (uaecptr addr, int size, int type) if (size == sz_byte) { v = mmu_get_user_byte(addr, regs.s != 0, true, sz_byte, true); } else if (size == sz_word) { - if (unlikely(is_unaligned(addr, 2))) { + if (unlikely(is_unaligned_page(addr, 2))) { v = mmu_get_lrmw_word_unaligned(addr); } else { v = mmu_get_user_word(addr, regs.s != 0, true, sz_word, true); } } else { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) v = mmu_get_lrmw_long_unaligned(addr); else v = mmu_get_user_long(addr, regs.s != 0, true, sz_long, true); diff --git a/cpummu30.cpp b/cpummu30.cpp index e7d43989..326c6c5a 100644 --- a/cpummu30.cpp +++ b/cpummu30.cpp @@ -66,11 +66,11 @@ int mmu030_fake_prefetch; uaecptr mmu030_fake_prefetch_addr; uae_u16 mmu030_state[3]; -uae_u32 mmu030_data_buffer; +uae_u32 mmu030_data_buffer_out; uae_u32 mmu030_disp_store[2]; uae_u32 mmu030_fmovem_store[2]; uae_u8 mmu030_cache_state; -struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS]; +struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS + 1]; static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write); static uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level); @@ -1700,6 +1700,38 @@ static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write #define ATC030_PHYS_CI 0x04000000 #define ATC030_PHYS_BE 0x08000000 +#if MMUDEBUG +static void dump_opcode(uae_u16 opcode) +{ + struct mnemolookup *lookup; + struct instr *dp; + char size = '_'; + + dp = table68k + opcode; + if (dp->mnemo == i_ILLG) { + opcode = 0x4AFC; + dp = table68k + opcode; + } + for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++); + + if (!dp->unsized) { + switch (dp->size) + { + case sz_byte: + size = 'B'; + break; + case sz_word: + size = 'W'; + break; + case sz_long: + size = 'L'; + break; + } + } + write_log(_T("%04x %s.%c"), opcode, lookup->name, size); +} +#endif + void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) { if (flags < 0) { @@ -1728,10 +1760,22 @@ void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) regs.mmu_ssw |= fc; bBusErrorReadWrite = read; mm030_stageb_address = addr; + #if MMUDEBUG - write_log(_T("MMU: page fault (logical addr=%08X SSW=%04x read=%d size=%d fc=%d pc=%08x ob=%08x ins=%04X)\n"), + write_log(_T("MMU: la=%08X SSW=%04x read=%d size=%d fc=%d pc=%08x ob=%08x "), addr, regs.mmu_ssw, read, (flags & MMU030_SSW_SIZE_B) ? 1 : (flags & MMU030_SSW_SIZE_W) ? 2 : 4, fc, - regs.instruction_pc, (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val, mmu030_opcode & 0xffff); + regs.instruction_pc, mmu030_data_buffer_out, mmu030_opcode & 0xffff); + dump_opcode(mmu030_opcode & 0xffff); + write_log(_T("\n")); +#endif + +#if 0 + if (addr == 0xBFE201) + write_log("!"); + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) + write_log("!"); + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) + write_log("!"); #endif THROW(2); @@ -2277,12 +2321,12 @@ uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc) if (size == sz_byte) { return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B); } else if (size == sz_word) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) return mmu030_get_word_unaligned(addr, fc, MMU030_SSW_RM); else return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_W); } else { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) return mmu030_get_long_unaligned(addr, fc, MMU030_SSW_RM); else return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_L); @@ -2299,12 +2343,12 @@ void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc) if (size == sz_byte) { mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B); } else if (size == sz_word) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) mmu030_put_word_unaligned(addr, val, fc, MMU030_SSW_RM); else mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_W); } else { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) mmu030_put_long_unaligned(addr, val, fc, MMU030_SSW_RM); else mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_L); @@ -2316,29 +2360,10 @@ void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size) uae_mmu030_put_lrmw_fcx(addr, val, size, fc); } -uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags) -{ - uae_u16 res; - - flags |= MMU030_SSW_SIZE_W; - res = (uae_u16)mmu030_get_generic(addr, fc, sz_byte, flags) << 8; - SAVE_EXCEPTION; - TRY(prb) { - res |= mmu030_get_generic(addr + 1, fc, sz_byte, flags); - RESTORE_EXCEPTION; - } - CATCH(prb) { - RESTORE_EXCEPTION; - THROW_AGAIN(prb); - } ENDTRY - return res; -} - uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags) { uae_u32 res; - flags |= MMU030_SSW_SIZE_L; res = (uae_u32)mmu030_get_iword(addr, fc) << 16; SAVE_EXCEPTION; TRY(prb) { @@ -2352,77 +2377,79 @@ uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags return res; } +static void unalign_init(bool l, bool l2) +{ + if (l2) + mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESSX; + if (l) + mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESSL; + mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESS0; +} +static void unalign_set(int state) +{ + mmu030_state[1] |= (1 << state) << (MMU030_STATEFLAG1_SUBACCESS_SHIFT + 1); +} +static void unalign_clear(void) +{ + mmu030_state[1] &= ~(MMU030_STATEFLAG1_SUBACCESSL | MMU030_STATEFLAG1_SUBACCESSX | + MMU030_STATEFLAG1_SUBACCESS0 | MMU030_STATEFLAG1_SUBACCESS1 | MMU030_STATEFLAG1_SUBACCESS2 | MMU030_STATEFLAG1_SUBACCESS3); +} + +uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags) +{ + unalign_init(false, false); + mmu030_data_buffer_out = (uae_u16)mmu030_get_generic(addr, fc, sz_byte, flags | MMU030_SSW_SIZE_W) << 8; + unalign_set(0); + mmu030_data_buffer_out |= mmu030_get_generic(addr + 1, fc, sz_byte, flags | MMU030_SSW_SIZE_B); + unalign_clear(); + return mmu030_data_buffer_out; +} + uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags) { - uae_u32 res; - - flags |= MMU030_SSW_SIZE_L; if (likely(!(addr & 1))) { - res = (uae_u32)mmu030_get_generic(addr, fc, sz_word, flags) << 16; - SAVE_EXCEPTION; - TRY(prb) { - res |= mmu030_get_generic(addr + 2, fc, sz_word, flags); - RESTORE_EXCEPTION; - } - CATCH(prb) { - RESTORE_EXCEPTION; - THROW_AGAIN(prb); - } ENDTRY + unalign_init(true, false); + mmu030_data_buffer_out = (uae_u32)mmu030_get_generic(addr, fc, sz_word, flags | MMU030_SSW_SIZE_L) << 16; + unalign_set(0); + mmu030_data_buffer_out |= mmu030_get_generic(addr + 2, fc, sz_word, flags | MMU030_SSW_SIZE_W); } else { - res = (uae_u32)mmu030_get_generic(addr, fc, sz_byte, flags) << 8; - SAVE_EXCEPTION; - TRY(prb) { - res = (res | mmu030_get_generic(addr + 1, fc, sz_byte, flags)) << 8; - res = (res | mmu030_get_generic(addr + 2, fc, sz_byte, flags)) << 8; - res |= mmu030_get_generic(addr + 3, fc, sz_byte, flags); - RESTORE_EXCEPTION; - } - CATCH(prb) { - RESTORE_EXCEPTION; - THROW_AGAIN(prb); - } ENDTRY + unalign_init(true, true); + mmu030_data_buffer_out = (uae_u32)mmu030_get_generic(addr, fc, sz_byte, flags | MMU030_SSW_SIZE_L) << 24; + unalign_set(0); + mmu030_data_buffer_out |= mmu030_get_generic(addr + 1, fc, sz_word, flags | MMU030_SSW_SIZE_W) << 8; + unalign_set(1); + mmu030_data_buffer_out |= mmu030_get_generic(addr + 3, fc, sz_byte, flags | MMU030_SSW_SIZE_B); } - return res; + unalign_clear(); + return mmu030_data_buffer_out; } void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc, int flags) { - flags |= MMU030_SSW_SIZE_L; - SAVE_EXCEPTION; - TRY(prb) { - if (likely(!(addr & 1))) { - mmu030_put_generic(addr, val >> 16, fc, sz_word, flags); - mmu030_put_generic(addr + 2, val, fc, sz_word, flags); - } else { - mmu030_put_generic(addr, val >> 24, fc, sz_byte, flags); - mmu030_put_generic(addr + 1, val >> 16, fc, sz_byte, flags); - mmu030_put_generic(addr + 2, val >> 8, fc, sz_byte, flags); - mmu030_put_generic(addr + 3, val, fc, sz_byte, flags); - } - RESTORE_EXCEPTION; + if (likely(!(addr & 1))) { + unalign_init(true, false); + mmu030_put_generic(addr, val >> 16, fc, sz_word, flags | MMU030_SSW_SIZE_L); + unalign_set(0); + mmu030_put_generic(addr + 2, val, fc, sz_word, flags | MMU030_SSW_SIZE_W); + } else { + unalign_init(true, true); + mmu030_put_generic(addr, val >> 24, fc, sz_byte, flags | MMU030_SSW_SIZE_L); + unalign_set(0); + mmu030_put_generic(addr + 1, val >> 8, fc, sz_word, flags | MMU030_SSW_SIZE_W); + unalign_set(1); + mmu030_put_generic(addr + 3, val, fc, sz_byte, flags | MMU030_SSW_SIZE_B); } - CATCH(prb) { - RESTORE_EXCEPTION; - regs.wb3_data = val; - THROW_AGAIN(prb); - } ENDTRY + unalign_clear(); } void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags) { - flags |= MMU030_SSW_SIZE_W; - SAVE_EXCEPTION; - TRY(prb) { - mmu030_put_generic(addr, val >> 8, fc, sz_byte, flags); - mmu030_put_generic(addr + 1, val, fc, sz_byte, flags); - RESTORE_EXCEPTION; - } - CATCH(prb) { - RESTORE_EXCEPTION; - regs.wb3_data = val; - THROW_AGAIN(prb); - } ENDTRY + unalign_init(false, false); + mmu030_put_generic(addr, val >> 8, fc, sz_byte, flags | MMU030_SSW_SIZE_W); + unalign_set(0); + mmu030_put_generic(addr + 1, val, fc, sz_byte, flags | MMU030_SSW_SIZE_B); + unalign_clear(); } @@ -2530,39 +2557,130 @@ void mmu030_set_funcs(void) } } -static void dump_opcode(uae_u16 opcode) +#define unalign_done(f) \ + st |= f; \ + mmu030_state[1] = st; + +static void mmu030_unaligned_read_continue(uaecptr addr, int fc) { - struct mnemolookup *lookup; - struct instr *dp; - char size = '_'; + uae_u32 st = mmu030_state[1]; - dp = table68k + opcode; - if (dp->mnemo == i_ILLG) { - opcode = 0x4AFC; - dp = table68k + opcode; +#if MMUDEBUG + write_log(_T("unaligned_read_continue: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st); +#endif + + if (st & MMU030_STATEFLAG1_SUBACCESSL) { + if (st & MMU030_STATEFLAG1_SUBACCESSX) { + // odd long access: byte + word + byte + if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) { + mmu030_data_buffer_out &= 0x00ffffff; + mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_L) << 24; + unalign_done(MMU030_STATEFLAG1_SUBACCESS1); + addr++; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) { + mmu030_data_buffer_out &= 0xff0000ff; + mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 8; + unalign_done(MMU030_STATEFLAG1_SUBACCESS2); + addr += 2; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) { + mmu030_data_buffer_out &= 0xffffff00; + mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0; + unalign_done(MMU030_STATEFLAG1_SUBACCESS3); + } + } else { + // even but unaligned long access: word + word + if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) { + mmu030_data_buffer_out &= 0x0000ffff; + mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_L) << 16; + unalign_done(MMU030_STATEFLAG1_SUBACCESS1); + addr += 2; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) { + mmu030_data_buffer_out &= 0xffff0000; + mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 0; + unalign_done(MMU030_STATEFLAG1_SUBACCESS2); + } + } + } else { + // odd word access: byte + byte + if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) { + mmu030_data_buffer_out &= 0x00ff; + mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_W) << 8; + unalign_done(MMU030_STATEFLAG1_SUBACCESS1); + addr++; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) { + mmu030_data_buffer_out &= 0xff00; + mmu030_data_buffer_out |= mmu030_get_generic(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0; + unalign_done(MMU030_STATEFLAG1_SUBACCESS2); + } } - for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++); - if (!dp->unsized) { - switch (dp->size) - { - case sz_byte: - size = 'B'; - break; - case sz_word: - size = 'W'; - break; - case sz_long: - size = 'L'; - break; +#if MMUDEBUG + write_log(_T("unaligned_read_continue_end: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st); +#endif +} + +static void mmu030_unaligned_write_continue(uaecptr addr, int fc) +{ + uae_u32 st = mmu030_state[1]; + +#if MMUDEBUG + write_log(_T("unaligned_write_continue: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st); +#endif + + if (st & MMU030_STATEFLAG1_SUBACCESSL) { + // odd long access: byte + word + byte + if (st & MMU030_STATEFLAG1_SUBACCESSX) { + if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) { + mmu030_put_generic(addr, mmu030_data_buffer_out >> 24, fc, sz_byte, MMU030_SSW_SIZE_L); + unalign_done(MMU030_STATEFLAG1_SUBACCESS1); + addr++; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) { + mmu030_put_generic(addr, mmu030_data_buffer_out >> 8, fc, sz_word, MMU030_SSW_SIZE_W); + unalign_done(MMU030_STATEFLAG1_SUBACCESS2); + addr += 2; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) { + mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B); + unalign_done(MMU030_STATEFLAG1_SUBACCESS3); + } + } else { + // even but unaligned long access: word + word + if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) { + mmu030_put_generic(addr, mmu030_data_buffer_out >> 16, fc, sz_word, MMU030_SSW_SIZE_L); + unalign_done(MMU030_STATEFLAG1_SUBACCESS1); + addr += 2; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) { + mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_word, MMU030_SSW_SIZE_W); + unalign_done(MMU030_STATEFLAG1_SUBACCESS2); + } + } + } else { + // odd word access: byte + byte + if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) { + mmu030_put_generic(addr, mmu030_data_buffer_out >> 8, fc, sz_byte, MMU030_SSW_SIZE_W); + unalign_done(MMU030_STATEFLAG1_SUBACCESS1); + addr++; + } + if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) { + mmu030_put_generic(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B); + unalign_done(MMU030_STATEFLAG1_SUBACCESS2); } } - write_log(_T("%04x %s.%c\n"), opcode, lookup->name, size); + +#if MMUDEBUG + write_log(_T("unaligned_write_continue_end: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st); +#endif } void m68k_do_rte_mmu030 (uaecptr a7) { - struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS]; + struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS + 1]; // Restore access error exception state @@ -2583,14 +2701,14 @@ void m68k_do_rte_mmu030 (uaecptr a7) // Internal register, our opcode storage area uae_u32 oc = get_long_mmu030(a7 + 0x14); // Movem write data - uae_u32 mdata = get_long_mmu030(a7 + 0x18); + uae_u32 mmu030_data_buffer_out_v = get_long_mmu030(a7 + 0x18); // get_disp_ea_020 uae_u32 mmu030_disp_store_0 = get_long_mmu030(a7 + 0x1c); uae_u32 mmu030_disp_store_1 = get_long_mmu030(a7 + 0x1c + 4); // Internal register, misc flags uae_u32 ps = get_long_mmu030(a7 + 0x28); // Data buffer - uae_u32 mmu030_data_buffer_v = get_long_mmu030(a7 + 0x2c);; + uae_u32 mmu030_data_buffer_in_v = get_long_mmu030(a7 + 0x2c);; uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1 : (oc & 0xffff); // Misc state data @@ -2620,6 +2738,7 @@ void m68k_do_rte_mmu030 (uaecptr a7) // 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 + 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); @@ -2631,20 +2750,20 @@ void m68k_do_rte_mmu030 (uaecptr a7) mmu030_ad_v[idxsize].done = true; if (ssw & MMU030_SSW_RW) { // Read and no DF: use value in data input buffer - mmu030_ad_v[idxsize].val = mmu030_data_buffer_v; + mmu030_ad_v[idxsize].val = mmu030_data_buffer_in_v; } } } // 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); - if (mmu030_opcode == -1) { + if (mmu030_opcode_v == -1) { mmu030_opcode_stageb = 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, stageb); + write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode_v, stageb); } } @@ -2659,7 +2778,7 @@ void m68k_do_rte_mmu030 (uaecptr a7) mmu030_disp_store[1] = mmu030_disp_store_1; mmu030_fmovem_store[0] = mmu030_fmovem_store_0; mmu030_fmovem_store[1] = mmu030_fmovem_store_1; - mmu030_data_buffer = mmu030_data_buffer_v; + mmu030_data_buffer_out = mmu030_data_buffer_out_v; mmu030_idx = idxsize; for (int i = 0; i <= mmu030_idx + 1; i++) { mmu030_ad[i].done = mmu030_ad_v[i].done; @@ -2675,17 +2794,6 @@ void m68k_do_rte_mmu030 (uaecptr a7) } m68k_setpci(pc); -#if MMUDEBUG - 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")); - } - } else { - if (mmu030_ad[idxsize].done) { - write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n")); - } - } -#endif if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) { // Locked-Read-Modify-Write restarts whole instruction. @@ -2699,49 +2807,64 @@ void m68k_do_rte_mmu030 (uaecptr a7) 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")); + } + } + if (mmu030_ad[idxsize].done) { + write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n")); + } +#endif + #if 0 write_log(_T("%08x %08x %08x %08x %08x %d %d %d "), mmu030_state[1], mmu030_state[2], mmu030_disp_store[0], mmu030_disp_store[1], addr, read, size, fc); dump_opcode(mmu030_opcode); #endif if (read) { - uae_u32 val = 0; - switch (size) - { - case sz_byte: - val = uae_mmu030_get_byte_fcx(addr, fc); - break; - case sz_word: - val = uae_mmu030_get_word_fcx(addr, fc); - break; - case sz_long: - val = uae_mmu030_get_long_fcx(addr, fc); - break; + if (!(mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1)) { + mmu030_data_buffer_out = mmu030_ad[idxsize].val; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_read_continue(addr, fc); + } 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_data_buffer = val; mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; } else { - mmu030_ad[idxsize].val = val; + mmu030_ad[idxsize].val = mmu030_data_buffer_out; mmu030_ad[idxsize].done = true; } } else { - uae_u32 val; - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) - val = mdata; - else - val = mmu030_ad[idxsize].val; - switch (size) - { - case sz_byte: - uae_mmu030_put_byte_fcx(addr, val, fc); - break; - case sz_word: - uae_mmu030_put_word_fcx(addr, val, fc); - break; - case sz_long: - uae_mmu030_put_long_fcx(addr, val, fc); - break; + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_write_continue(addr, fc); + } 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_MOVEM1) { mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; @@ -2752,6 +2875,12 @@ void m68k_do_rte_mmu030 (uaecptr a7) } +#if MMU030_DEBUG + if (mmu030_idx >= MAX_MMU030_ACCESS) { + write_log(_T("mmu030_idx (RTE) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS); + } +#endif + } else { m68k_areg (regs, 7) += 32; } @@ -2940,7 +3069,7 @@ uae_u32 REGPARAM2 get_disp_ea_020_mmu030c (uae_u32 base, int idx) void m68k_do_rte_mmu030c (uaecptr a7) { - struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS]; + struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS + 1]; // Restore access error exception state @@ -2962,14 +3091,14 @@ void m68k_do_rte_mmu030c (uaecptr a7) // Internal register, our opcode storage area uae_u32 oc = get_long_mmu030c(a7 + 0x14); // Movem write data - uae_u32 mdata = get_long_mmu030c(a7 + 0x18); + 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_v = get_long_mmu030c(a7 + 0x2c);; + uae_u32 mmu030_data_buffer_in_v = get_long_mmu030c(a7 + 0x2c);; uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1 : (oc & 0xffff); // Misc state data @@ -2994,9 +3123,11 @@ void m68k_do_rte_mmu030c (uaecptr a7) mmu030_ad_v[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4); } mmu030_ad_v[idxsize + 1].done = false; + // 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 + 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); @@ -3005,10 +3136,10 @@ void m68k_do_rte_mmu030c (uaecptr a7) // if movem, skip next move mmu030_state_1 |= MMU030_STATEFLAG1_MOVEM2; } else { - mmu030_ad[idxsize].done = true; + mmu030_ad_v[idxsize].done = true; if (ssw & MMU030_SSW_RW) { // Read and no DF: use value in data input buffer - mmu030_ad[idxsize].val = mmu030_data_buffer; + mmu030_ad_v[idxsize].val = mmu030_data_buffer_in_v; } } } @@ -3036,6 +3167,7 @@ void m68k_do_rte_mmu030c (uaecptr a7) write_log (_T("Software fixed stage C! opcode = %04x\n"), regs.prefetch020[1]); } + // restore global state variables mmu030_opcode = mmu030_opcode_v; mmu030_state[0] = mmu030_state_0; mmu030_state[1] = mmu030_state_1; @@ -3044,13 +3176,12 @@ void m68k_do_rte_mmu030c (uaecptr a7) mmu030_disp_store[1] = mmu030_disp_store_1; mmu030_fmovem_store[0] = mmu030_fmovem_store_0; mmu030_fmovem_store[1] = mmu030_fmovem_store_1; - mmu030_data_buffer = mmu030_data_buffer_v; + mmu030_data_buffer_out = mmu030_data_buffer_out_v; mmu030_idx = idxsize; - for (int i = 0; i < mmu030_idx + 1; i++) { + for (int i = 0; i <= mmu030_idx + 1; i++) { mmu030_ad[i].done = mmu030_ad_v[i].done; mmu030_ad[i].val = mmu030_ad_v[i].val; } - mmu030_ad[mmu030_idx + 1].done = false; m68k_areg (regs, 7) += 92; regs.sr = sr; @@ -3061,6 +3192,17 @@ void m68k_do_rte_mmu030c (uaecptr a7) } m68k_setpci (pc); +#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")); + } + } else { + if (mmu030_ad[idxsize].done) { + write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n")); + } + } +#endif if (!(ssw & (MMU030_SSW_DF << 1))) { if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) { // Prefetch was software fixed, continue pipeline refill @@ -3075,7 +3217,12 @@ void m68k_do_rte_mmu030c (uaecptr a7) } } - if (ssw & MMU030_SSW_DF) { + if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) { + + // 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; @@ -3083,50 +3230,45 @@ void m68k_do_rte_mmu030c (uaecptr a7) int fc = ssw & 7; if (read) { - uae_u32 val = 0; - if (ssw & MMU030_SSW_RM) { - val = read_dcache030_lrmw_mmu_fcx(addr, size, fc); + if (!(mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1)) { + mmu030_data_buffer_out = mmu030_ad[idxsize].val; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_read_continue(addr, fc); } else { switch (size) { case sz_byte: - val = read_dcache030_bget(addr, fc); + mmu030_data_buffer_out = read_dcache030_bget(addr, fc); break; case sz_word: - val = read_dcache030_wget(addr, fc); + mmu030_data_buffer_out = read_dcache030_wget(addr, fc); break; case sz_long: - val = read_dcache030_lget(addr, fc); + mmu030_data_buffer_out = read_dcache030_lget(addr, fc); break; } } if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { - mmu030_data_buffer = val; mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; } else { - mmu030_ad[idxsize].val = val; + mmu030_ad[idxsize].val = mmu030_data_buffer_out; mmu030_ad[idxsize].done = true; - mmu030_ad[idxsize + 1].done = false; } } else { - uae_u32 val; - if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) - val = mdata; - else - val = mmu030_ad[idxsize].val; - if (ssw & MMU030_SSW_RM) { - write_dcache030_lrmw_mmu_fcx(addr, val, size, fc); + if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) { + mmu030_unaligned_write_continue(addr, fc); } else { switch (size) { case sz_byte: - write_dcache030_bput(addr, val, fc); + write_dcache030_bput(addr, mmu030_data_buffer_out, fc); break; case sz_word: - write_dcache030_wput(addr, val, fc); + write_dcache030_wput(addr, mmu030_data_buffer_out, fc); break; case sz_long: - write_dcache030_lput(addr, val, fc); + write_dcache030_lput(addr, mmu030_data_buffer_out, fc); break; } } @@ -3134,7 +3276,6 @@ void m68k_do_rte_mmu030c (uaecptr a7) mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; } else { mmu030_ad[idxsize].done = true; - mmu030_ad[idxsize + 1].done = false; } } } diff --git a/fpp.cpp b/fpp.cpp index c68de15e..cb3d082e 100644 --- a/fpp.cpp +++ b/fpp.cpp @@ -2449,7 +2449,7 @@ static uaecptr fmovem2mem (uaecptr ad, uae_u32 list, int incr, int regdir) if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2; } else { - mmu030_data_buffer = wrd[i]; + mmu030_data_buffer_out = wrd[i]; x_put_long(ad + i * 4, wrd[i]); } mmu030_state[0]++; @@ -2504,7 +2504,7 @@ static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir) if (mmu030_state[0] == idx * 3 + i) { if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) { mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2; - wrd[i] = mmu030_data_buffer; + wrd[i] = mmu030_data_buffer_out; } else { wrd[i] = x_get_long (ad + i * 4); } diff --git a/gencpu.cpp b/gencpu.cpp index bf94c3b6..1a0e571b 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -2194,10 +2194,10 @@ static void movem_mmu030 (const char *code, int size, bool put, bool aipi, bool printf ("\t\t\tif (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {\n"); printf ("\t\t\t\tmmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;\n"); if (!put) - printf ("\t\t\t\tval = %smmu030_data_buffer;\n", size == 2 ? "(uae_s32)(uae_s16)" : ""); + printf ("\t\t\t\tval = %smmu030_data_buffer_out;\n", size == 2 ? "(uae_s32)(uae_s16)" : ""); printf ("\t\t\t} else {\n"); if (put) - printf ("\t\t\t\t%s, (mmu030_data_buffer = m68k_%creg (regs, %s[%cmask])));\n", code, reg, index, reg); + printf ("\t\t\t\t%s, (mmu030_data_buffer_out = m68k_%creg (regs, %s[%cmask])));\n", code, reg, index, reg); else printf ("\t\t\t\tval = %s;\n", code); printf ("\t\t\t}\n"); diff --git a/include/cpummu.h b/include/cpummu.h index 7ff8f95d..b645197e 100644 --- a/include/cpummu.h +++ b/include/cpummu.h @@ -698,7 +698,7 @@ static ALWAYS_INLINE uae_u32 uae_mmu040_get_ilong(uaecptr addr) result |= uae_mmu040_getc_iword(addr + 2); return result; #else - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) return mmu_get_ilong_unaligned(addr); return mmu_get_ilong(addr, sz_long); #endif @@ -714,13 +714,13 @@ static ALWAYS_INLINE uae_u16 uae_mmu040_get_ibyte(uaecptr addr) } static ALWAYS_INLINE uae_u32 uae_mmu040_get_long(uaecptr addr) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) return mmu_get_long_unaligned(addr, true); return mmu_get_long(addr, true, sz_long); } static ALWAYS_INLINE uae_u16 uae_mmu040_get_word(uaecptr addr) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_page(addr, 2))) return mmu_get_word_unaligned(addr, true); return mmu_get_word(addr, true, sz_word); } @@ -731,7 +731,7 @@ static ALWAYS_INLINE uae_u8 uae_mmu040_get_byte(uaecptr addr) static ALWAYS_INLINE void uae_mmu040_put_word(uaecptr addr, uae_u16 val) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_page(addr, 2))) mmu_put_word_unaligned(addr, val, true); else mmu_put_word(addr, val, true, sz_word); @@ -742,7 +742,7 @@ static ALWAYS_INLINE void uae_mmu040_put_byte(uaecptr addr, uae_u8 val) } static ALWAYS_INLINE void uae_mmu040_put_long(uaecptr addr, uae_u32 val) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) mmu_put_long_unaligned(addr, val, true); else mmu_put_long(addr, val, true, sz_long); @@ -751,7 +751,7 @@ static ALWAYS_INLINE void uae_mmu040_put_long(uaecptr addr, uae_u32 val) static ALWAYS_INLINE uae_u32 uae_mmu060_get_ilong(uaecptr addr) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) return mmu_get_ilong_unaligned(addr); return mmu_get_ilong(addr, sz_long); } @@ -765,13 +765,13 @@ static ALWAYS_INLINE uae_u16 uae_mmu060_get_ibyte(uaecptr addr) } static ALWAYS_INLINE uae_u32 uae_mmu060_get_long(uaecptr addr) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) return mmu_get_long_unaligned(addr, true); return mmu_get_long(addr, true, sz_long); } static ALWAYS_INLINE uae_u16 uae_mmu060_get_word(uaecptr addr) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_page(addr, 2))) return mmu_get_word_unaligned(addr, true); return mmu_get_word(addr, true, sz_word); } @@ -787,14 +787,14 @@ static ALWAYS_INLINE void uae_mmu_get_move16(uaecptr addr, uae_u32 *val) static ALWAYS_INLINE void uae_mmu060_put_long(uaecptr addr, uae_u32 val) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_page(addr, 4))) mmu_put_long_unaligned(addr, val, true); else mmu_put_long(addr, val, true, sz_long); } static ALWAYS_INLINE void uae_mmu060_put_word(uaecptr addr, uae_u16 val) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_page(addr, 2))) mmu_put_word_unaligned(addr, val, true); else mmu_put_word(addr, val, true, sz_word); diff --git a/include/cpummu030.h b/include/cpummu030.h index f1114e6e..35848816 100644 --- a/include/cpummu030.h +++ b/include/cpummu030.h @@ -1,6 +1,8 @@ #ifndef UAE_CPUMMU030_H #define UAE_CPUMMU030_H +#define MMU030_DEBUG 1 + #include "uae/types.h" #include "mmu_common.h" @@ -12,7 +14,7 @@ extern uae_u64 srp_030, crp_030; extern uae_u32 tt0_030, tt1_030, tc_030; extern uae_u16 mmusr_030; -#define MAX_MMU030_ACCESS 10 +#define MAX_MMU030_ACCESS 9 extern uae_u32 mm030_stageb_address; extern int mmu030_idx; extern bool mmu030_retry; @@ -20,7 +22,7 @@ extern int mmu030_opcode, mmu030_opcode_stageb; extern int mmu030_fake_prefetch; extern uaecptr mmu030_fake_prefetch_addr; extern uae_u16 mmu030_state[3]; -extern uae_u32 mmu030_data_buffer; +extern uae_u32 mmu030_data_buffer_out; extern uae_u32 mmu030_disp_store[2]; extern uae_u32 mmu030_fmovem_store[2]; extern uae_u8 mmu030_cache_state, mmu030_cache_state_default; @@ -31,12 +33,20 @@ extern uae_u8 mmu030_cache_state, mmu030_cache_state_default; #define MMU030_STATEFLAG1_DISP0 0x0001 #define MMU030_STATEFLAG1_DISP1 0x0002 +#define MMU030_STATEFLAG1_SUBACCESS0 0x0004 +#define MMU030_STATEFLAG1_SUBACCESS1 0x0008 +#define MMU030_STATEFLAG1_SUBACCESS2 0x0010 +#define MMU030_STATEFLAG1_SUBACCESS3 0x0020 +#define MMU030_STATEFLAG1_SUBACCESSX 0x0040 +#define MMU030_STATEFLAG1_SUBACCESSL 0x0080 +#define MMU030_STATEFLAG1_SUBACCESS_SHIFT 2 + struct mmu030_access { bool done; uae_u32 val; }; -extern struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS]; +extern struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS + 1]; void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc); @@ -98,7 +108,7 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_ilong(uaecptr addr) { uae_u32 fc = uae_mmu030_get_fc_code(); - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) return mmu030_get_ilong_unaligned(addr, fc, 0); return mmu030_get_ilong(addr, fc); } @@ -119,7 +129,7 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_long(uaecptr addr) { uae_u32 fc = uae_mmu030_get_fc_data(); - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) return mmu030_get_long_unaligned(addr, fc, 0); return mmu030_get_long(addr, fc); } @@ -127,7 +137,7 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_word(uaecptr addr) { uae_u32 fc = uae_mmu030_get_fc_data(); - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) return mmu030_get_word_unaligned(addr, fc, 0); return mmu030_get_word(addr, fc); } @@ -142,7 +152,7 @@ static ALWAYS_INLINE void uae_mmu030_put_long(uaecptr addr, uae_u32 val) { uae_u32 fc = uae_mmu030_get_fc_data(); - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) mmu030_put_long_unaligned(addr, val, fc, 0); else mmu030_put_long(addr, val, fc); @@ -151,7 +161,7 @@ static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u32 val) { uae_u32 fc = uae_mmu030_get_fc_data(); - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) mmu030_put_word_unaligned(addr, val, fc, 0); else mmu030_put_word(addr, val, fc); @@ -165,7 +175,7 @@ static ALWAYS_INLINE void uae_mmu030_put_byte(uaecptr addr, uae_u32 val) static ALWAYS_INLINE uae_u32 uae_mmu030_get_ilong_fc(uaecptr addr) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) return mmu030_get_ilong_unaligned(addr, regs.fc030, 0); return mmu030_get_ilong(addr, regs.fc030); } @@ -179,13 +189,13 @@ static ALWAYS_INLINE uae_u16 uae_mmu030_get_ibyte_fc(uaecptr addr) } static ALWAYS_INLINE uae_u32 uae_mmu030_get_long_fc(uaecptr addr) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) return mmu030_get_long_unaligned(addr, regs.fc030, 0); return mmu030_get_long(addr, regs.fc030); } static ALWAYS_INLINE uae_u32 uae_mmu030_get_word_fc(uaecptr addr) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) return mmu030_get_word_unaligned(addr, regs.fc030, 0); return mmu030_get_word(addr, regs.fc030); } @@ -195,14 +205,14 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_byte_fc(uaecptr addr) } static ALWAYS_INLINE void uae_mmu030_put_long_fc(uaecptr addr, uae_u32 val) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) mmu030_put_long_unaligned(addr, val, regs.fc030, 0); else mmu030_put_long(addr, val, regs.fc030); } static ALWAYS_INLINE void uae_mmu030_put_word_fc(uaecptr addr, uae_u32 val) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) mmu030_put_word_unaligned(addr, val, regs.fc030, 0); else mmu030_put_word(addr, val, regs.fc030); @@ -215,13 +225,13 @@ uae_u8 uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size); static ALWAYS_INLINE uae_u32 uae_mmu030_get_long_fcx(uaecptr addr, int fc) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) return mmu030_get_long_unaligned(addr, fc, 0); return mmu030_get_long(addr, fc); } static ALWAYS_INLINE uae_u32 uae_mmu030_get_word_fcx(uaecptr addr, int fc) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) return mmu030_get_word_unaligned(addr, fc, 0); return mmu030_get_word(addr, fc); } @@ -231,14 +241,14 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_byte_fcx(uaecptr addr, int fc) } static ALWAYS_INLINE void uae_mmu030_put_long_fcx(uaecptr addr, uae_u32 val, int fc) { - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) mmu030_put_long_unaligned(addr, val, fc, 0); else mmu030_put_long(addr, val, fc); } static ALWAYS_INLINE void uae_mmu030_put_word_fcx(uaecptr addr, uae_u32 val, int fc) { - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) mmu030_put_word_unaligned(addr, val, fc, 0); else mmu030_put_word(addr, val, fc); @@ -251,7 +261,7 @@ static ALWAYS_INLINE void uae_mmu030_put_byte_fcx(uaecptr addr, uae_u32 val, int #define ACCESS_CHECK_PUT \ if (!mmu030_ad[mmu030_idx].done) { \ - mmu030_ad[mmu030_idx].val = v; \ + mmu030_data_buffer_out = v; \ } else if (mmu030_ad[mmu030_idx].done) { \ mmu030_idx++; \ return; \ @@ -273,6 +283,7 @@ static ALWAYS_INLINE void uae_mmu030_put_byte_fcx(uaecptr addr, uae_u32 val, int } #define ACCESS_EXIT_PUT \ + mmu030_ad[mmu030_idx].val = mmu030_data_buffer_out; \ mmu030_ad[mmu030_idx].done = true; \ mmu030_idx++; \ mmu030_ad[mmu030_idx].done = false; @@ -291,7 +302,7 @@ static ALWAYS_INLINE uae_u32 sfc030_get_long(uaecptr addr) #if MMUDEBUG > 2 write_log(_T("sfc030_get_long: FC = %i\n"),fc); #endif - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) return mmu030_get_long_unaligned(addr, fc, 0); return mmu030_get_long(addr, fc); } @@ -302,7 +313,7 @@ static ALWAYS_INLINE uae_u16 sfc030_get_word(uaecptr addr) #if MMUDEBUG > 2 write_log(_T("sfc030_get_word: FC = %i\n"),fc); #endif - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) return mmu030_get_word_unaligned(addr, fc, 0); return mmu030_get_word(addr, fc); } @@ -322,7 +333,7 @@ static ALWAYS_INLINE void dfc030_put_long(uaecptr addr, uae_u32 val) #if MMUDEBUG > 2 write_log(_T("dfc030_put_long: %08X = %08X FC = %i\n"), addr, val, fc); #endif - if (unlikely(is_unaligned(addr, 4))) + if (unlikely(is_unaligned_bus(addr, 4))) mmu030_put_long_unaligned(addr, val, fc, 0); else mmu030_put_long(addr, val, fc); @@ -334,7 +345,7 @@ static ALWAYS_INLINE void dfc030_put_word(uaecptr addr, uae_u16 val) #if MMUDEBUG > 2 write_log(_T("dfc030_put_word: %08X = %04X FC = %i\n"), addr, val, fc); #endif - if (unlikely(is_unaligned(addr, 2))) + if (unlikely(is_unaligned_bus(addr, 2))) mmu030_put_word_unaligned(addr, val, fc, 0); else mmu030_put_word(addr, val, fc); diff --git a/include/mmu_common.h b/include/mmu_common.h index 3a14495e..a04c954e 100644 --- a/include/mmu_common.h +++ b/include/mmu_common.h @@ -109,17 +109,14 @@ typedef int m68k_exception; #define ALWAYS_INLINE __inline // take care of 2 kinds of alignment, bus size and page -#if 1 -static ALWAYS_INLINE bool is_unaligned(uaecptr addr, int size) +static ALWAYS_INLINE bool is_unaligned_page(uaecptr addr, int size) { return unlikely((addr & (size - 1)) && (addr ^ (addr + size - 1)) & regs.mmu_page_size); } -#else -static ALWAYS_INLINE bool is_unaligned(uaecptr addr, int size) +static ALWAYS_INLINE bool is_unaligned_bus(uaecptr addr, int size) { return (addr & (size - 1)); } -#endif static ALWAYS_INLINE void phys_put_long(uaecptr addr, uae_u32 l) { diff --git a/newcpu.cpp b/newcpu.cpp index a88589a2..c88d3e73 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -1369,12 +1369,12 @@ static void set_x_funcs (void) } else { icache_fetch = uae_mmu030_get_ilong; } - dcache_lput = uae_mmu030_put_long; - dcache_wput = uae_mmu030_put_word; - dcache_bput = uae_mmu030_put_byte; - dcache_lget = uae_mmu030_get_long; - dcache_wget = uae_mmu030_get_word; - dcache_bget = uae_mmu030_get_byte; + dcache_lput = uae_mmu030_put_long_fc; + dcache_wput = uae_mmu030_put_word_fc; + dcache_bput = uae_mmu030_put_byte_fc; + dcache_lget = uae_mmu030_get_long_fc; + dcache_wget = uae_mmu030_get_word_fc; + dcache_bget = uae_mmu030_get_byte_fc; if (currprefs.cpu_data_cache) { read_data_030_bget = read_dcache030_mmu_bget; read_data_030_wget = read_dcache030_mmu_wget; @@ -1382,12 +1382,6 @@ static void set_x_funcs (void) write_data_030_bput = write_dcache030_mmu_bput; write_data_030_wput = write_dcache030_mmu_wput; write_data_030_lput = write_dcache030_mmu_lput; - dcache_lput = uae_mmu030_put_long_fc; - dcache_wput = uae_mmu030_put_word_fc; - dcache_bput = uae_mmu030_put_byte_fc; - dcache_lget = uae_mmu030_get_long_fc; - dcache_wget = uae_mmu030_get_word_fc; - dcache_bget = uae_mmu030_get_byte_fc; dcache_check = uae_mmu030_check_fc; } else { read_data_030_bget = uae_mmu030_get_byte; @@ -3136,18 +3130,28 @@ static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 // 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) { + write_log(_T("mmu030_idx out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS); + } +#endif for (i = 0; i < mmu030_idx + 1; i++) { m68k_areg (regs, 7) -= 4; x_put_long (m68k_areg (regs, 7), mmu030_ad[i].val); } - while (i < 9) { + while (i < MAX_MMU030_ACCESS) { uae_u32 v = 0; m68k_areg (regs, 7) -= 4; // mmu030_idx is always small enough if instruction is FMOVEM. if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) { - if (i == 7) +#if MMU030_DEBUG + if (mmu030_idx >= MAX_MMU030_ACCESS - 2) { + write_log(_T("mmu030_idx (FMOVEM) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS - 2); + } +#endif + if (i == MAX_MMU030_ACCESS - 2) v = mmu030_fmovem_store[0]; - else if (i == 8) + else if (i == MAX_MMU030_ACCESS - 1) v = mmu030_fmovem_store[1]; } x_put_long (m68k_areg (regs, 7), v); @@ -3189,8 +3193,8 @@ 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[0]); m68k_areg (regs, 7) -= 4; - // Data output buffer = value that was going to be written - x_put_long (m68k_areg (regs, 7), mmu030_data_buffer); + // Data output buffer = value that was going to be written + x_put_long (m68k_areg (regs, 7), mmu030_data_buffer_out); m68k_areg (regs, 7) -= 4; x_put_long (m68k_areg (regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage) m68k_areg (regs, 7) -= 4; @@ -3292,7 +3296,7 @@ static void Exception_mmu030 (int nr, uaecptr oldpc) } else if (nr == 3) { regs.mmu_fault_addr = last_fault_for_exception_3; mmu030_state[0] = mmu030_state[1] = 0; - mmu030_data_buffer = 0; + mmu030_data_buffer_out = 0; Exception_build_stack_frame (last_fault_for_exception_3, currpc, MMU030_SSW_RW | MMU030_SSW_SIZE_W | (regs.s ? 6 : 2), nr, 0xA); } else { Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);