]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
68030 MMU SSW FC exception handler modifications are now emulated. If FC is modified...
authorToni Wilen <twilen@winuae.net>
Sat, 20 Oct 2018 10:40:05 +0000 (13:40 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 20 Oct 2018 10:40:05 +0000 (13:40 +0300)
cpummu30.cpp
gencpu.cpp
include/cpummu030.h

index fd2493a36a7207970a17a7d03cc1230e4a4d53fc..5e3700e245160cb7c59accc2ea2d930c7db7fd24 100644 (file)
@@ -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_mmu030(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;
        }
index e7811e3b6a14f87f7ed2476c9f854a2be65c14c9..6ad2ab7beeb6f21262c05e3cf0a8f52c917bb609 100644 (file)
@@ -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;
index e321c9d05bfdffb0ad805dc6f3ed14730f6c0e80..b123f838705a1e0cdf9726d726d12b4ed020421e 100644 (file)
@@ -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)