]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Add missing invalid addressing mode checks for FMOVEM, FMOVE(M) Control Register...
authorToni Wilen <twilen@winuae.net>
Fri, 8 Jun 2018 20:05:14 +0000 (23:05 +0300)
committerToni Wilen <twilen@winuae.net>
Fri, 8 Jun 2018 20:05:14 +0000 (23:05 +0300)
fpp.cpp

diff --git a/fpp.cpp b/fpp.cpp
index 2150a5e45eb7116a8b14c453c9b4c98fbe3897c7..c95027633081409f6f649bc612575ebbca6a3833 100644 (file)
--- a/fpp.cpp
+++ b/fpp.cpp
@@ -1326,7 +1326,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
        size = (extra >> 10) & 7;
 
        switch (mode) {
-               case 0:
+               case 0: // Dn
                        if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
                                return -1;
                        switch (size)
@@ -1348,12 +1348,12 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                        return 0;
                        }
                        return 1;
-               case 1:
+               case 1: // An
                        return 0;
-               case 2:
+               case 2: // (An)
                        ad = m68k_areg (regs, reg);
                        break;
-               case 3:
+               case 3: // (An)+
                        // Also needed by fault_if_no_fpu 
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
@@ -1361,7 +1361,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                        ad = m68k_areg (regs, reg);
                        m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
                        break;
-               case 4:
+               case 4: // -(An)
                        // Also needed by fault_if_no_fpu 
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
@@ -1372,10 +1372,10 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                        if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12)
                                ad += 8;
                        break;
-               case 5:
+               case 5: // (d16,An)
                        ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
                        break;
-               case 6:
+               case 6: // (d8,An,Xn)+
                        ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
                        break;
                case 7:
@@ -1444,14 +1444,14 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
 
        switch (size)
        {
-               case 0:
+               case 0: // L
                        fpset(src, (uae_s32) (doext ? exts[0] : x_cp_get_long (ad)));
                        break;
-               case 1:
+               case 1: // S
                        fpp_to_single (src, (doext ? exts[0] : x_cp_get_long (ad)));
                        normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
                        break;
-               case 2:
+               case 2: // X
                        {
                                uae_u32 wrd1, wrd2, wrd3;
                                wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
@@ -1463,7 +1463,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
                        }
                        break;
-               case 3:
+               case 3: // P
                        {
                                uae_u32 wrd[3];
                                if (currprefs.cpu_model == 68060) {
@@ -1482,10 +1482,10 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                return 1;
                        }
                        break;
-               case 4:
+               case 4: // W
                        fpset(src, (uae_s16) (doext ? exts[0] : x_cp_get_word (ad)));
                        break;
-               case 5:
+               case 5: // D
                        {
                                uae_u32 wrd1, wrd2;
                                wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
@@ -1495,7 +1495,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                                normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
                        }
                        break;
-               case 6:
+               case 6: // B
                        fpset(src, (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad)));
                        break;
                default:
@@ -1528,13 +1528,13 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
        size = (extra >> 10) & 7;
        switch (mode)
        {
-               case 0:
+               case 0: // Dn
 
                        if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
                                return -1;
                        switch (size)
                        {
-                               case 6:
+                               case 6: // B
                                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 0) & 0xff)
@@ -1542,7 +1542,7 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                                        if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
                                                return -1;
                                        break;
-                               case 4:
+                               case 4: // W
                                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 1) & 0xffff)
@@ -1550,14 +1550,14 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                                        if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
                                                return -1;
                                        break;
-                               case 0:
+                               case 0: // L
                                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = (uae_u32)fpp_to_int (value, 2);
                                        if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
                                                return -1;
                                        break;
-                               case 1:
+                               case 1: // S
                                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
                                                return 1;
                                        m68k_dreg (regs, reg) = fpp_from_single (value);
@@ -1566,12 +1566,12 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                                        return 0;
                        }
                        return 1;
-               case 1:
+               case 1: // An
                        return 0;
-               case 2:
+               case 2: // (An)
                        ad = m68k_areg (regs, reg);
                        break;
-               case 3:
+               case 3: // (An)+
                        // Also needed by fault_if_no_fpu 
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
@@ -1579,7 +1579,7 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                        ad = m68k_areg (regs, reg);
                        m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
                        break;
-               case 4:
+               case 4: // -(An)
                        // Also needed by fault_if_no_fpu 
                        mmufixup[0].reg = reg;
                        mmufixup[0].value = m68k_areg (regs, reg);
@@ -1590,28 +1590,22 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                        if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12)
                                ad += 8;
                        break;
-               case 5:
+               case 5: // (d16,An)
                        ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
                        break;
-               case 6:
+               case 6: // (d8,An,Xn)+
                        ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
                        break;
                case 7:
                        switch (reg)
                        {
-                               case 0:
+                               case 0: // (xxx).W
                                        ad = (uae_s32) (uae_s16) x_cp_next_iword ();
                                        break;
-                               case 1:
+                               case 1: // (xxx).L
                                        ad = x_cp_next_ilong ();
                                        break;
-                               case 2:
-                                       ad = m68k_getpc ();
-                                       ad += (uae_s32) (uae_s16) x_cp_next_iword ();
-                                       break;
-                               case 3:
-                                       ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
-                                       break;
+                               // Immediate and PC-relative modes are not supported
                                default:
                                        return 0;
                        }
@@ -1624,19 +1618,19 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
 
        switch (size)
        {
-               case 0:
+               case 0: // L
                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
                                return 1;
                        x_cp_put_long(ad, (uae_u32)fpp_to_int(value, 2));
                        if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
                                return -1;
                        break;
-               case 1:
+               case 1: // S
                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
                                return 1;
                        x_cp_put_long(ad, fpp_from_single(value));
                        break;
-               case 2:
+               case 2: // X
                        {
                                if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
                                        return 1;
@@ -1669,14 +1663,14 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                                x_cp_put_long (ad, wrd[2]);
                        }
                        break;
-               case 4:
+               case 4: // W
                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
                                return 1;
                        x_cp_put_word(ad, (uae_s16)fpp_to_int(value, 1));
                        if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
                                return -1;
                        break;
-               case 5:
+               case 5: // D
                        {
                                if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
                                        return 1;
@@ -1687,7 +1681,7 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
                                x_cp_put_long (ad, wrd2);
                        }
                        break;
-               case 6:
+               case 6: // B
                        if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
                                return 1;
                        x_cp_put_byte(ad, (uae_s8)fpp_to_int(value, 0));
@@ -1709,38 +1703,38 @@ static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
        reg = opcode & 7;
        switch (mode)
        {
-               case 0:
-               case 1:
+               case 0: // Dn
+               case 1: // An
                        return 0;
-               case 2:
+               case 2: // (An)
                        *ad = m68k_areg (regs, reg);
                        break;
-               case 3:
+               case 3: // (An)+
                        *ad = m68k_areg (regs, reg);
                        break;
-               case 4:
+               case 4: // -(An)
                        *ad = m68k_areg (regs, reg);
                        break;
-               case 5:
+               case 5: // (d16,An)
                        *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
                        break;
-               case 6:
+               case 6: // (d8,An,Xn)+
                        *ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
                        break;
                case 7:
                        switch (reg)
                        {
-                               case 0:
+                               case 0: // (xxx).W
                                        *ad = (uae_s32) (uae_s16) x_cp_next_iword ();
                                        break;
-                               case 1:
+                               case 1: // (xxx).L
                                        *ad = x_cp_next_ilong ();
                                        break;
-                               case 2:
+                               case 2: // (d16,PC)
                                        *ad = m68k_getpc ();
                                        *ad += (uae_s32) (uae_s16) x_cp_next_iword ();
                                        break;
-                               case 3:
+                               case 3: // (d8,PC,Xn)+
                                        *ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
                                        break;
                                default:
@@ -2806,6 +2800,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
        switch ((extra >> 13) & 0x7)
        {
                case 3:
+                       // FMOVE FPP->EA
                        if (fp_exception_pending(true))
                                return;
 
@@ -2825,41 +2820,52 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
 
                case 4:
                case 5:
+                       // FMOVE Control Register <> Data or Address register
                        if ((opcode & 0x38) == 0) {
+                               // Dn
                                if (fault_if_no_fpu (opcode, extra, 0, pc))
                                        return;
+                               // Only single selected control register is allowed
+                               // All control register bits unset = FPIAR
+                               uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400);
+                               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)
+                                               fpu_noinst(opcode, pc);
+                                       return;
+                               }
                                if (extra & 0x2000) {
                                        if (extra & 0x1000)
                                                m68k_dreg (regs, opcode & 7) = fpp_get_fpcr();
                                        if (extra & 0x0800)
                                                m68k_dreg (regs, opcode & 7) = fpp_get_fpsr();
-                                       if (extra & 0x0400)
+                                       if ((extra & 0x0400) || !bits)
                                                m68k_dreg (regs, opcode & 7) = regs.fpiar;
                                } else {
                                        if (extra & 0x1000)
                                                fpp_set_fpcr(m68k_dreg (regs, opcode & 7));
                                        if (extra & 0x0800)
                                                fpp_set_fpsr(m68k_dreg (regs, opcode & 7));
-                                       if (extra & 0x0400)
+                                       if ((extra & 0x0400) || !bits)
                                                regs.fpiar = m68k_dreg (regs, opcode & 7);
                                }
                        } else if ((opcode & 0x38) == 0x08) {
+                               // An
                                if (fault_if_no_fpu (opcode, extra, 0, pc))
                                        return;
+                               // Only FPIAR can be moved to/from address register
+                               // All bits unset = FPIAR
+                               uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400);
+                               // 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) {
-                                       if (extra & 0x1000)
-                                               m68k_areg (regs, opcode & 7) = fpp_get_fpcr();
-                                       if (extra & 0x0800)
-                                               m68k_areg (regs, opcode & 7) = fpp_get_fpsr();
-                                       if (extra & 0x0400)
-                                               m68k_areg (regs, opcode & 7) = regs.fpiar;
+                                       m68k_areg (regs, opcode & 7) = regs.fpiar;
                                } else {
-                                       if (extra & 0x1000)
-                                               fpp_set_fpcr(m68k_areg (regs, opcode & 7));
-                                       if (extra & 0x0800)
-                                               fpp_set_fpsr(m68k_areg (regs, opcode & 7));
-                                       if (extra & 0x0400)
-                                               regs.fpiar = m68k_areg (regs, opcode & 7);
+                                       regs.fpiar = m68k_areg (regs, opcode & 7);
                                }
                        } else if ((opcode & 0x3f) == 0x3c) {
                                if ((extra & 0x2000) == 0) {
@@ -2892,7 +2898,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                        return;
                                }
                        } else if (extra & 0x2000) {
-                               /* FMOVEM FPP->memory */
+                               /* FMOVEM Control Register->Memory */
                                uae_u32 ad;
                                int incr = 0;
 
@@ -2902,6 +2908,11 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                }
                                if (fault_if_no_fpu (opcode, extra, ad, pc))
                                        return;
+                               if ((opcode & 0x3f) >= 0x3a) {
+                                       // PC relative modes not supported
+                                       fpu_noinst(opcode, pc);
+                                       return;
+                               }
 
                                if ((opcode & 0x38) == 0x20) {
                                        if (extra & 0x1000)
@@ -2930,7 +2941,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                if ((opcode & 0x38) == 0x20)
                                        m68k_areg (regs, opcode & 7) = ad;
                        } else {
-                               /* FMOVEM memory->FPP */
+                               /* FMOVEM Memory->Control Register */
                                uae_u32 ad;
                                int incr = 0;
 
@@ -2972,6 +2983,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                case 6:
                case 7:
                        {
+                               // FMOVEM FPP<>Memory
                                uae_u32 ad, list = 0;
                                int incr = 1;
                                int regdir = 1;
@@ -2981,6 +2993,18 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                }
                                if (fault_if_no_fpu (opcode, extra, ad, pc))
                                        return;
+
+                               if ((extra & 0x2000) && ((opcode & 0x38) == 0x18 || (opcode & 0x3f) >= 0x3a)) {
+                                       // FMOVEM FPP->Memory: (An)+ and PC relative modes not supported
+                                       fpu_noinst(opcode, pc);
+                                       return;
+                               }
+                               if (!(extra & 0x2000) && (opcode & 0x38) == 0x20) {
+                                       // FMOVEM Memory->FPP: -(An) not supported
+                                       fpu_noinst(opcode, pc);
+                                       return;
+                               }
+
                                switch ((extra >> 11) & 3)
                                {
                                        case 0: /* static pred */
@@ -3005,10 +3029,10 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                                        }
                                }
                                if (extra & 0x2000) {
-                                       /* FMOVEM FPP->memory */
+                                       /* FMOVEM FPP->Memory */
                                        ad = fmovem2mem (ad, list, incr, regdir);
                                } else {
-                                       /* FMOVEM memory->FPP */
+                                       /* FMOVEM Memory->FPP */
                                        ad = fmovem2fpp (ad, list, incr, regdir);
                                }
                                if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20) // (an)+ or -(an)