From 1bd27e3676128ba05110af560fb7372aac1dfde4 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 18 Apr 2020 22:09:46 +0300 Subject: [PATCH] FMOVEM updates. Correct FPSR and FPCR masking. --- fpp.cpp | 138 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 32 deletions(-) diff --git a/fpp.cpp b/fpp.cpp index 3213d662..13e6d89c 100644 --- a/fpp.cpp +++ b/fpp.cpp @@ -38,6 +38,7 @@ #define SUPPORT_MMU 1 #else #define SUPPORT_MMU 0 +extern void cputester_fault(void); #endif #include "softfloat/softfloat.h" @@ -51,6 +52,7 @@ bool use_long_double = false; static bool support_exceptions; static bool support_denormals; +static uae_u32 fpcr_mask, fpsr_mask; FPP_PRINT fpp_print; @@ -699,18 +701,18 @@ uae_u32 fpp_get_fpsr (void) regs.fpsr |= FPSR_CC_N; } #endif - return regs.fpsr & 0x0ffffff8; + return regs.fpsr & fpsr_mask; } uae_u32 fpp_get_fpcr(void) { - return regs.fpcr & (currprefs.fpu_model == 68040 ? 0xffff : 0xfff0); + return regs.fpcr & fpcr_mask; } void fpp_set_fpcr (uae_u32 val) { fpp_set_mode(val); - regs.fpcr = val & 0xffff; + regs.fpcr = val & fpcr_mask; } static void fpnan (fpdata *fpd) @@ -729,7 +731,7 @@ static void fpset (fpdata *fpd, uae_s32 val) void fpp_set_fpsr (uae_u32 val) { - regs.fpsr = val; + regs.fpsr = val & fpsr_mask; #ifdef JIT // check comment in fpp_cond @@ -2179,7 +2181,9 @@ void fpuop_dbcc (uae_u32 opcode, uae_u16 extra) return; disp = (uae_s32) (uae_s16)x_cp_next_iword(); - if (fault_if_no_fpu_u (opcode, extra, pc + disp, true, pc - 4)) + // 68060 unimplemented stacked EA contains original extra + disp values + // not final absolute address. + if (fault_if_no_fpu_u (opcode, extra, (extra << 16) | (disp & 0xffff), true, pc - 4)) return; regs.fpiar = pc - 4; maybe_idle_state (); @@ -2230,6 +2234,13 @@ void fpuop_scc (uae_u32 opcode, uae_u16 extra) } } + // needs to be before 68060 check because + // unimplemented stack frame stacked EA is adjusted + // Register is not adjusted. + if (mode == Apdi) { + ad -= reg == 7 ? 2 : 1; + } + if (fault_if_no_fpu_u (opcode, extra, ad, adset, pc)) return; @@ -2247,7 +2258,6 @@ void fpuop_scc (uae_u32 opcode, uae_u16 extra) mmufixup[0].reg = reg; mmufixup[0].value = m68k_areg(regs, reg); fpu_mmu_fixup = true; - ad -= reg == 7 ? 2 : 1; m68k_areg(regs, reg) = ad; } x_cp_put_byte (ad, cc ? 0xff : 0x00); @@ -2871,12 +2881,13 @@ static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir) if (list & 0x80) { if (incr < 0) ad -= 3 * 4; - wrd1 = x_cp_get_long (ad + 0); - wrd2 = x_cp_get_long (ad + 4); - wrd3 = x_cp_get_long (ad + 8); + wrd1 = x_cp_get_long(ad + 0); + wrd2 = x_cp_get_long(ad + 4); + wrd3 = x_cp_get_long(ad + 8); if (incr > 0) ad += 3 * 4; - fpp_to_exten (®s.fp[reg], wrd1, wrd2, wrd3); + fpp_to_exten(®s.fp[reg], wrd1, wrd2, wrd3); + } list <<= 1; } @@ -3152,9 +3163,9 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) case 4: case 5: - // FMOVE Control Register <> Data or Address register + // FMOVE(M) Control Register(s) <> Data or Address register if ((opcode & 0x38) == 0) { - // Dn + // FMOVE(M) Control Register(s) <> Dn if (fault_if_no_fpu (opcode, extra, 0, false, pc)) return; // Only single selected control register is allowed @@ -3163,11 +3174,18 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) if (bits && bits != 0x1000 && bits != 0x0800 && bits != 0x400) { // 68060 does not generate f-line if multiple bits are set // but it also works unexpectedly, just do nothing for now. - if (currprefs.fpu_model != 68060) + if (currprefs.fpu_model != 68060) { fpu_noinst(opcode, pc); + } +#ifdef CPU_TESTER + if (currprefs.fpu_model == 68060) { + cputester_fault(); + } +#endif return; } if (extra & 0x2000) { + // CR -> Dn if (extra & 0x1000) m68k_dreg(regs, opcode & 7) = fpp_get_fpcr(); if (extra & 0x0800) @@ -3175,6 +3193,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) if ((extra & 0x0400) || !bits) m68k_dreg(regs, opcode & 7) = fpp_get_fpiar(); } else { + // Dn -> CR if (extra & 0x1000) fpp_set_fpcr(m68k_dreg (regs, opcode & 7)); if (extra & 0x0800) @@ -3183,24 +3202,35 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) fpp_set_fpiar(m68k_dreg (regs, opcode & 7)); } } else if ((opcode & 0x38) == 0x08) { - // An + // FMOVE(M) Control Register(s) <> An if (fault_if_no_fpu (opcode, extra, 0, false, pc)) return; // Only FPIAR can be moved to/from address register // All bits unset = FPIAR uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400); + if (bits && bits != 0x0400 && currprefs.fpu_model == 68060) { + // 68060 does not generate f-line if multiple bits are set + // but it also works unexpectedly, just do nothing for now. +#ifdef CPU_TESTER + cputester_fault(); +#endif + return; + } // 68060, An and all bits unset: f-line if ((bits && bits != 0x0400) || (!bits && currprefs.fpu_model == 68060)) { fpu_noinst(opcode, pc); return; } if (extra & 0x2000) { + // An -> FPIAR m68k_areg (regs, opcode & 7) = regs.fpiar; } else { + // FPIAR -> An regs.fpiar = m68k_areg (regs, opcode & 7); } } else if ((opcode & 0x3f) == 0x3c) { if ((extra & 0x2000) == 0) { + // FMOVE(M) #imm,Control Register(s) uae_u32 ext[3]; // 68060 FMOVEM.L #imm,more than 1 control register: unimplemented EA uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400); @@ -3208,6 +3238,10 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) if (fault_if_60()) return; } + // No control register bits set: FPIAR + if (!bits) { + extra |= 0x0400; + } // fetch first, use only after all data has been fetched ext[0] = ext[1] = ext[2] = 0; if (extra & 0x1000) @@ -3230,7 +3264,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) return; } } else if (extra & 0x2000) { - /* FMOVEM Control Register->Memory */ + /* FMOVE(M) Control Register(s),EA */ uae_u32 ad; int incr = 0; @@ -3246,6 +3280,11 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) return; } + // No control register bits set: FPIAR + if (!(extra & (0x1000 | 0x0800 | 0x0400))) { + extra |= 0x0400; + } + if ((opcode & 0x38) == 0x20) { if (extra & 0x1000) incr += 4; @@ -3268,13 +3307,17 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) ad += 4; } ad -= incr; - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad; + if ((opcode & 0x38) == 0x18) { + // (An)+ + m68k_areg(regs, opcode & 7) = ad; + } + if ((opcode & 0x38) == 0x20) { + // -(An) + m68k_areg(regs, opcode & 7) = ad; + } trace_t0_68040(); } else { - /* FMOVEM Memory->Control Register */ + /* FMOVE(M) EA,Control Register(s) */ uae_u32 ad; int incr = 0; @@ -3285,6 +3328,12 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) if (fault_if_no_fpu (opcode, extra, ad, adset, pc)) return; + // No control register bits set: FPIAR + if (!(extra & (0x1000 | 0x0800 | 0x0400))) { + extra |= 0x0400; + } + + // -(An) if((opcode & 0x38) == 0x20) { if (extra & 0x1000) incr += 4; @@ -3306,10 +3355,14 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) fpp_set_fpiar(x_cp_get_long (ad)); ad += 4; } - if ((opcode & 0x38) == 0x18) - m68k_areg (regs, opcode & 7) = ad; - if ((opcode & 0x38) == 0x20) - m68k_areg (regs, opcode & 7) = ad - incr; + if ((opcode & 0x38) == 0x18) { + // (An)+ + m68k_areg(regs, opcode & 7) = ad; + } + if ((opcode & 0x38) == 0x20) { + // -(An) + m68k_areg(regs, opcode & 7) = ad - incr; + } } return; @@ -3321,7 +3374,14 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) int incr = 1; int regdir = 1; if (get_fp_ad (opcode, &ad, &adset) == 0) { - fpu_noinst (opcode, pc); +#ifdef CPU_TESTER + // 68060 does weird things (no exception) if FMOVEM.X #imm to registers + if ((opcode & 0x3f) == 0x3c && !(extra & 0x2000) && currprefs.fpu_model == 68060) { + cputester_fault(); + return; + } +#endif + fpu_noinst(opcode, pc); return; } if (fault_if_no_fpu (opcode, extra, ad, adset, pc)) @@ -3348,11 +3408,17 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) case 3: /* dynamic postinc */ if (fault_if_60()) return; - list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; + list = m68k_dreg (regs, (extra >> 4) & 7) & 0xff; break; } - if ((opcode & 0x38) == 0x20) { // -(an) - incr = -1; + if (((opcode & 0x38) == 0x20) || (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882)) { + // -(an) + if ((opcode & 0x38) == 0x20) { + incr = -1; + if (currprefs.fpu_model == 68060) { + regdir = -1; + } + } switch ((extra >> 11) & 3) { case 0: /* static pred */ @@ -3363,14 +3429,16 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) } if (extra & 0x2000) { /* FMOVEM FPP->Memory */ - ad = fmovem2mem (ad, list, incr, regdir); + ad = fmovem2mem(ad, list, incr, regdir); trace_t0_68040(); } else { /* FMOVEM Memory->FPP */ - ad = fmovem2fpp (ad, list, incr, regdir); + ad = fmovem2fpp(ad, list, incr, regdir); + } + if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20) { + // (an)+ or -(an) + m68k_areg(regs, opcode & 7) = ad; } - if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20) // (an)+ or -(an) - m68k_areg (regs, opcode & 7) = ad; } return; @@ -3469,6 +3537,12 @@ static void get_features(void) } else { condition_table = condition_table_6888x; } + fpsr_mask = 0x0ffffff8; + if (currprefs.fpu_model == 68040) { + fpcr_mask = 0xffff; + } else { + fpcr_mask = 0xfff0; + } } void fpu_clearstatus(void) -- 2.47.3