From d34751b9a9f5319368eb80b2da9956b657afca2c Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 20 Oct 2018 13:40:05 +0300 Subject: [PATCH] 68030 MMU SSW FC exception handler modifications are now emulated. If FC is modified, retried access cycle uses modified FC. --- cpummu30.cpp | 137 +++++++++++++++++++++++++++++++++++++++++--- gencpu.cpp | 19 +++--- include/cpummu030.h | 123 +++++++++++++++++++++++++++++++++++---- 3 files changed, 254 insertions(+), 25 deletions(-) diff --git a/cpummu30.cpp b/cpummu30.cpp index fd2493a3..5e3700e2 100644 --- a/cpummu30.cpp +++ b/cpummu30.cpp @@ -1774,7 +1774,7 @@ static uaecptr mmu030_put_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) { #endif if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) { - mmu030_page_fault(addr, false, MMU030_SSW_SIZE_B, fc); + mmu030_page_fault(addr, false, size, fc); return 0; } @@ -2524,9 +2524,12 @@ void m68k_do_rte_mmu030 (uaecptr a7) { // Restore access error exception state - uae_u16 format = get_word_mmu030 (a7 + 6); + uae_u16 format = get_word_mmu030(a7 + 6); uae_u16 frame = format >> 12; - uae_u16 ssw = get_word_mmu030 (a7 + 10); + uae_u16 ssw = get_word_mmu030(a7 + 10); + uae_u16 sr = get_word_mmu030(a7); + uae_u32 pc = get_long_mmu030(a7 + 2); + uae_u32 fault_addr = get_long_mmu030(a7 + 16); // 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. @@ -2536,9 +2539,9 @@ void m68k_do_rte_mmu030 (uaecptr a7) get_word_mmu030(a7 + 32 - 2); // Internal register, misc flags - uae_u32 ps = get_long_mmu030c(a7 + 0x28); + uae_u32 ps = get_long_mmu030(a7 + 0x28); // Internal register, our opcode storage area - uae_u32 oc = get_long_mmu030c (a7 + 0x14); + uae_u32 oc = get_long_mmu030(a7 + 0x14); mmu030_opcode = (ps & 0x80000000) ? -1 : (oc & 0xffff); // Misc state data mmu030_state[0] = get_word_mmu030 (a7 + 0x30); @@ -2592,7 +2595,72 @@ void m68k_do_rte_mmu030 (uaecptr a7) write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode, stageb); } } - m68k_areg (regs, 7) += 92; + + 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) { + // retry faulted access + uaecptr addr = fault_addr; + bool read = (ssw & MMU030_SSW_RW) != 0; + int size = (ssw & MMU030_SSW_SIZE_B) ? 1 : ((ssw & MMU030_SSW_SIZE_W) ? 2 : 4); + int fc = ssw & 7; + + if (read) { + uae_u32 val = 0; + switch (size) + { + case 1: + val = mmu030_get_byte(addr, fc); + break; + case 2: + val = mmu030_get_word(addr, fc); + break; + case 4: + val = mmu030_get_long(addr, fc); + break; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_data_buffer = val; + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (mmu030_state[1] & MMU030_STATEFLAG1_SKIP_INS) { + mmu030_state[0]++; + } else { + mmu030_ad[idxsize].val = val; + mmu030_ad[idxsize].done = true; + mmu030_ad[idxsize + 1].done = false; + } + } else { + uae_u32 val = mmu030_ad[idxsize].val; + switch (size) + { + case 1: + mmu030_put_byte(addr, val, fc); + break; + case 2: + mmu030_put_word(addr, val, fc); + break; + case 4: + mmu030_put_long(addr, val, fc); + break; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (mmu030_state[1] & MMU030_STATEFLAG1_SKIP_INS) { + mmu030_state[0]++; + } else { + mmu030_ad[idxsize].done = true; + mmu030_ad[idxsize + 1].done = false; + } + } + } + } else { m68k_areg (regs, 7) += 32; } @@ -2788,6 +2856,7 @@ void m68k_do_rte_mmu030c (uaecptr a7) uae_u16 ssw = get_word_mmu030c (a7 + 10); uae_u16 sr = get_word_mmu030c (a7); uae_u32 pc = get_long_mmu030c (a7 + 2); + uae_u32 fault_addr = get_long_mmu030c(a7 + 16); // 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. @@ -2865,7 +2934,6 @@ void m68k_do_rte_mmu030c (uaecptr a7) } m68k_areg (regs, 7) += 92; - regs.sr = sr; MakeFromSR_T0(); if (pc & 1) { @@ -2888,6 +2956,61 @@ void m68k_do_rte_mmu030c (uaecptr a7) } } + 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) ? 1 : ((ssw & MMU030_SSW_SIZE_W) ? 2 : 4); + int fc = ssw & 7; + if (read) { + uae_u32 val = 0; + switch (size) + { + case 1: + val = read_dcache030_bget(addr, fc); + break; + case 2: + val = read_dcache030_wget(addr, fc); + break; + case 4: + val = read_dcache030_lget(addr, fc); + break; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_data_buffer = val; + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (mmu030_state[1] & MMU030_STATEFLAG1_SKIP_INS) { + mmu030_state[0]++; + } else { + mmu030_ad[idxsize].val = val; + mmu030_ad[idxsize].done = true; + mmu030_ad[idxsize + 1].done = false; + } + } else { + uae_u32 val = mmu030_ad[idxsize].val; + switch (size) + { + case 1: + write_dcache030_bput(addr, val, fc); + break; + case 2: + write_dcache030_wput(addr, val, fc); + break; + case 4: + write_dcache030_lput(addr, val, fc); + break; + } + if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) { + mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2; + } else if (mmu030_state[1] & MMU030_STATEFLAG1_SKIP_INS) { + mmu030_state[0]++; + } else { + mmu030_ad[idxsize].done = true; + mmu030_ad[idxsize + 1].done = false; + } + } + } + } else { m68k_areg (regs, 7) += 32; } diff --git a/gencpu.cpp b/gencpu.cpp index e7811e3b..6ad2ab7b 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -44,7 +44,7 @@ static int cpu_level, cpu_generic; static int count_read, count_write, count_cycles, count_ncycles; static int count_cycles_ce020; static int count_read_ea, count_write_ea, count_cycles_ea; -static const char *mmu_postfix; +static const char *mmu_postfix, *xfc_postfix; static int memory_cycle_cnt; static int did_prefetch; static int ipl_fetched; @@ -1663,9 +1663,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char if (using_mmu) { if (flags & GF_FC) { switch (size) { - case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = sfc%s_get_byte (%sa);\n", name, mmu_postfix, name); break; - case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = sfc%s_get_word (%sa);\n", name, mmu_postfix, name); break; - case sz_long: insn_n_cycles += 8; printf ("\tuae_s32 %s = sfc%s_get_long (%sa);\n", name, mmu_postfix, name); break; + case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = sfc%s_get_byte%s (%sa);\n", name, mmu_postfix, xfc_postfix, name); break; + case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = sfc%s_get_word%s (%sa);\n", name, mmu_postfix, xfc_postfix, name); break; + case sz_long: insn_n_cycles += 8; printf ("\tuae_s32 %s = sfc%s_get_long%s (%sa);\n", name, mmu_postfix, xfc_postfix, name); break; default: term (); } } else { @@ -1884,7 +1884,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz case sz_byte: insn_n_cycles += 4; if (flags & GF_FC) - printf ("\tdfc%s_put_byte (%sa, %s);\n", mmu_postfix, to, from); + printf ("\tdfc%s_put_byte%s (%sa, %s);\n", mmu_postfix, xfc_postfix, to, from); else printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstblrmw : (candormw ? dstbrmw : dstb), to, from); break; @@ -1893,7 +1893,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) term (); if (flags & GF_FC) - printf ("\tdfc%s_put_word (%sa, %s);\n", mmu_postfix, to, from); + printf ("\tdfc%s_put_word%s (%sa, %s);\n", mmu_postfix, xfc_postfix, to, from); else printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstwlrmw : (candormw ? dstwrmw : dstw), to, from); break; @@ -1902,7 +1902,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) term (); if (flags & GF_FC) - printf ("\tdfc%s_put_long (%sa, %s);\n", mmu_postfix, to, from); + printf ("\tdfc%s_put_long%s (%sa, %s);\n", mmu_postfix, xfc_postfix, to, from); else printf ("\t%s (%sa, %s);\n", (flags & GF_LRMW) ? dstllrmw : (candormw ? dstlrmw : dstl), to, from); break; @@ -3985,7 +3985,7 @@ static void gen_opcode (unsigned int opcode) printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr); } else { printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030 (a); break; }\n"); - printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030 (a); break; }\n"); + printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr); } } else { printf ("\t\telse if (frame == 0xa) { m68k_areg (regs, 7) += offset + 24; break; }\n"); @@ -5965,6 +5965,7 @@ static void generate_cpu (int id, int mode) using_waitstates = 0; memory_cycle_cnt = 4; mmu_postfix = ""; + xfc_postfix = ""; using_simple_cycles = 0; using_indirect = 0; cpu_generic = false; @@ -6040,6 +6041,7 @@ static void generate_cpu (int id, int mode) opcode_next_clev[rp] = cpu_level; } else if (id == 32) { // 32 = 68030 MMU mmu_postfix = "030"; + xfc_postfix = "_state"; cpu_level = 3; using_mmu = 68030; read_counts (); @@ -6054,6 +6056,7 @@ static void generate_cpu (int id, int mode) opcode_next_clev[rp] = cpu_level; } else if (id == 34) { // 34 = 68030 MMU + caches mmu_postfix = "030c"; + xfc_postfix = "_state"; cpu_level = 3; using_prefetch_020 = 2; using_mmu = 68030; diff --git a/include/cpummu030.h b/include/cpummu030.h index e321c9d0..b123f838 100644 --- a/include/cpummu030.h +++ b/include/cpummu030.h @@ -25,6 +25,7 @@ extern uae_u32 mmu030_disp_store[2]; extern uae_u32 mmu030_fmovem_store[2]; extern uae_u8 mmu030_cache_state, mmu030_cache_state_default; +#define MMU030_STATEFLAG1_SKIP_INS 0x1000 #define MMU030_STATEFLAG1_FMOVEM 0x2000 #define MMU030_STATEFLAG1_MOVEM1 0x4000 #define MMU030_STATEFLAG1_MOVEM2 0x8000 @@ -82,9 +83,19 @@ extern uae_u32 REGPARAM3 mmu030_get_lrmw_long_unaligned(uaecptr addr, uae_u32 fc extern void REGPARAM3 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags) REGPARAM; extern void REGPARAM3 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc, int flags) REGPARAM; +static ALWAYS_INLINE uae_u32 uae_mmu030_get_fc_code(void) +{ + return (regs.s ? 4 : 0) | 2; +} + +static ALWAYS_INLINE uae_u32 uae_mmu030_get_fc_data(void) +{ + return (regs.s ? 4 : 0) | 1; +} + static ALWAYS_INLINE uae_u32 uae_mmu030_get_ilong(uaecptr addr) { - uae_u32 fc = (regs.s ? 4 : 0) | 2; + uae_u32 fc = uae_mmu030_get_fc_code(); if (unlikely(is_unaligned(addr, 4))) return mmu030_get_ilong_unaligned(addr, fc, 0); @@ -92,18 +103,20 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_ilong(uaecptr addr) } static ALWAYS_INLINE uae_u16 uae_mmu030_get_iword(uaecptr addr) { - uae_u32 fc = (regs.s ? 4 : 0) | 2; + uae_u32 fc = uae_mmu030_get_fc_code(); + return mmu030_get_iword(addr, fc); } static ALWAYS_INLINE uae_u16 uae_mmu030_get_ibyte(uaecptr addr) { - uae_u32 fc = (regs.s ? 4 : 0) | 2; + uae_u32 fc = uae_mmu030_get_fc_code(); return mmu030_get_byte(addr, fc); } + static ALWAYS_INLINE uae_u32 uae_mmu030_get_long(uaecptr addr) { - uae_u32 fc = (regs.s ? 4 : 0) | 1; + uae_u32 fc = uae_mmu030_get_fc_data(); if (unlikely(is_unaligned(addr, 4))) return mmu030_get_long_unaligned(addr, fc, 0); @@ -111,7 +124,7 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_long(uaecptr addr) } static ALWAYS_INLINE uae_u32 uae_mmu030_get_word(uaecptr addr) { - uae_u32 fc = (regs.s ? 4 : 0) | 1; + uae_u32 fc = uae_mmu030_get_fc_data(); if (unlikely(is_unaligned(addr, 2))) return mmu030_get_word_unaligned(addr, fc, 0); @@ -119,14 +132,15 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_word(uaecptr addr) } static ALWAYS_INLINE uae_u32 uae_mmu030_get_byte(uaecptr addr) { - uae_u32 fc = (regs.s ? 4 : 0) | 1; + uae_u32 fc = uae_mmu030_get_fc_data(); return mmu030_get_byte(addr, fc); } + static ALWAYS_INLINE void uae_mmu030_put_long(uaecptr addr, uae_u32 val) { - uae_u32 fc = (regs.s ? 4 : 0) | 1; - + uae_u32 fc = uae_mmu030_get_fc_data(); + if (unlikely(is_unaligned(addr, 4))) mmu030_put_long_unaligned(addr, val, fc, 0); else @@ -134,7 +148,7 @@ static ALWAYS_INLINE void uae_mmu030_put_long(uaecptr addr, uae_u32 val) } static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u32 val) { - uae_u32 fc = (regs.s ? 4 : 0) | 1; + uae_u32 fc = uae_mmu030_get_fc_data(); if (unlikely(is_unaligned(addr, 2))) mmu030_put_word_unaligned(addr, val, fc, 0); @@ -143,7 +157,7 @@ static ALWAYS_INLINE void uae_mmu030_put_word(uaecptr addr, uae_u32 val) } static ALWAYS_INLINE void uae_mmu030_put_byte(uaecptr addr, uae_u32 val) { - uae_u32 fc = (regs.s ? 4 : 0) | 1; + uae_u32 fc = uae_mmu030_get_fc_data(); mmu030_put_byte(addr, val, fc); } @@ -298,6 +312,51 @@ static ALWAYS_INLINE void dfc030_put_byte(uaecptr addr, uae_u8 val) mmu030_put_byte(addr, val, fc); } +static ALWAYS_INLINE uae_u32 sfc030_get_long_state(uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = sfc030_get_long(addr); + ACCESS_EXIT_GET + return v; +} +static ALWAYS_INLINE uae_u16 sfc030_get_word_state(uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = sfc030_get_word(addr); + ACCESS_EXIT_GET + return v; +} +static ALWAYS_INLINE uae_u8 sfc030_get_byte_state(uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = sfc030_get_byte(addr); + ACCESS_EXIT_GET + return v; +} + +static ALWAYS_INLINE void dfc030_put_long_state(uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + dfc030_put_long(addr, v); + ACCESS_EXIT_PUT +} +static ALWAYS_INLINE void dfc030_put_word_state(uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + dfc030_put_word(addr, v); + ACCESS_EXIT_PUT +} +static ALWAYS_INLINE void dfc030_put_byte_state(uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + dfc030_put_byte(addr, v); + ACCESS_EXIT_PUT +} + + uae_u32 REGPARAM3 get_disp_ea_020_mmu030 (uae_u32 base, int idx) REGPARAM; STATIC_INLINE void put_byte_mmu030_state (uaecptr addr, uae_u32 v) @@ -572,6 +631,50 @@ static ALWAYS_INLINE void dfc030c_put_byte(uaecptr addr, uae_u8 val) write_data_030_fc_bput(addr, val, regs.dfc); } +static ALWAYS_INLINE uae_u32 sfc030c_get_long_state(uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = sfc030c_get_long(addr); + ACCESS_EXIT_GET + return v; +} +static ALWAYS_INLINE uae_u16 sfc030c_get_word_state(uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = sfc030c_get_word(addr); + ACCESS_EXIT_GET + return v; +} +static ALWAYS_INLINE uae_u8 sfc030c_get_byte_state(uaecptr addr) +{ + uae_u32 v; + ACCESS_CHECK_GET + v = sfc030c_get_byte(addr); + ACCESS_EXIT_GET + return v; +} + +static ALWAYS_INLINE void dfc030c_put_long_state(uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + dfc030c_put_long(addr, v); + ACCESS_EXIT_PUT +} +static ALWAYS_INLINE void dfc030c_put_word_state(uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + dfc030c_put_word(addr, v); + ACCESS_EXIT_PUT +} +static ALWAYS_INLINE void dfc030c_put_byte_state(uaecptr addr, uae_u32 v) +{ + ACCESS_CHECK_PUT + dfc030c_put_byte(addr, v); + ACCESS_EXIT_PUT +} + uae_u32 REGPARAM3 get_disp_ea_020_mmu030c (uae_u32 base, int idx) REGPARAM; STATIC_INLINE void put_byte_mmu030c_state (uaecptr addr, uae_u32 v) -- 2.47.3