#define MAKE_FPSR(r) (regs).fp_result.fp=(r)
+static void fpnan (fpdata *fpd)
+{
+ fpd->fp = *fp_nan;
+#ifdef USE_SOFT_LONG_DOUBLE
+ fpd->fpe = ((uae_u64)dhex_nan[0] << 32) | dhex_nan[1];
+ fpd->fpm = dhex_nan[2];
+#endif
+}
+
static void fpclear (fpdata *fpd)
{
fpd->fp = 0;
#define FPU_EXP_UNIMP_INS 0
#define FPU_EXP_DISABLED 1
-#define FPU_EXP_UNIMP_DATATYPE 2
+#define FPU_EXP_UNIMP_DATATYPE_PRE 2
+#define FPU_EXP_UNIMP_DATATYPE_POST 3
-static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type)
+static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type, fpdata *src, int reg)
{
/* 68040 unimplemented/68060 FPU disabled exception.
* Line F exception with different stack frame.. */
int vector = 11;
- uaecptr newpc = m68k_getpc ();
+ uaecptr newpc = m68k_getpc (); // next instruction
static int warned = 20;
regs.t0 = regs.t1 = 0;
MakeSR ();
if (!regs.s) {
regs.usp = m68k_areg (regs, 7);
- m68k_areg (regs, 7) = regs.isp;
+ if (currprefs.cpu_model == 68060) {
+ m68k_areg (regs, 7) = regs.isp;
+ } else if (currprefs.cpu_model >= 68020) {
+ m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
+ } else {
+ m68k_areg (regs, 7) = regs.isp;
+ }
+ regs.s = 1;
+ if (currprefs.mmu_model)
+ mmu_set_super (regs.s != 0);
}
- regs.s = 1;
+ regs.fpu_exp_state = 1;
if (currprefs.cpu_model == 68060) {
regs.fpiar = oldpc;
if (type == FPU_EXP_DISABLED) {
+ // current PC
+ newpc = oldpc;
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), oldpc);
m68k_areg (regs, 7) -= 4;
x_put_word (m68k_areg (regs, 7), 0x4000 + vector * 4);
} else if (type == FPU_EXP_UNIMP_INS) {
// PC = next instruction
- oldpc = newpc;
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), ea);
m68k_areg (regs, 7) -= 2;
x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
//activate_debugger ();
- } else { // FPU_EXP_UNIMP_DATATYPE
- vector = 60;
+ } else if (type == FPU_EXP_UNIMP_DATATYPE_PRE) {
+ newpc = oldpc;
+ vector = 55;
m68k_areg (regs, 7) -= 2;
x_put_word (m68k_areg (regs, 7), 0x0000 + vector * 4);
+ } else { // FPU_EXP_UNIMP_DATATYPE_POST
+ // PC = next instruction
+ vector = 55;
+ m68k_areg (regs, 7) -= 4;
+ x_put_long (m68k_areg (regs, 7), ea);
+ m68k_areg (regs, 7) -= 2;
+ x_put_word (m68k_areg (regs, 7), 0x3000 + vector * 4);
}
} else if (currprefs.cpu_model == 68040) {
regs.fpiar = oldpc;
+ regs.exp_extra = extra;
+ regs.exp_opcode = opcode;
+ regs.exp_src1 = *src;
+ regs.exp_type = type;
+ if (reg >= 0)
+ regs.exp_src2 = regs.fp[reg];
+ else
+ fpclear (®s.exp_src2);
if (type == FPU_EXP_UNIMP_INS || type == FPU_EXP_DISABLED) {
// PC = next instruction
- oldpc = newpc;
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), ea);
m68k_areg (regs, 7) -= 2;
x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
- } else { // FPU_EXP_UNIMP_DATATYPE
+ } else if (type == FPU_EXP_UNIMP_DATATYPE_PRE) {
+ // current PC
+ newpc = oldpc;
+ vector = 55;
+ m68k_areg (regs, 7) -= 2;
+ x_put_word (m68k_areg (regs, 7), 0x0000 + vector * 4);
+ } else { // FPU_EXP_UNIMP_DATATYPE_POST
+ // PC = next instruction
vector = 55;
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), ea);
m68k_areg (regs, 7) -= 2;
- x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
+ x_put_word (m68k_areg (regs, 7), 0x3000 + vector * 4);
}
}
+ oldpc = newpc;
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), newpc);
m68k_areg (regs, 7) -= 2;
x_put_word (m68k_areg (regs, 7), regs.sr);
newpc = x_get_long (regs.vbr + vector * 4);
if (warned > 0) {
- write_log (_T("FPU EXCEPTION %d OP=%04X EA=%08X PC=%08X -> %08X\n"), type, opcode, ea, oldpc, newpc);
+ write_log (_T("FPU EXCEPTION %d OP=%04X-%04X EA=%08X PC=%08X -> %08X\n"), type, opcode, extra, ea, oldpc, newpc);
#if EXCEPTION_FPP == 0
warned--;
#endif
{
if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
|| (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_DISABLED);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_DISABLED, NULL, -1);
return;
}
regs.fp_exception = true;
{
if ((regs.pcr & 2) || currprefs.fpu_model <= 0) {
#if EXCEPTION_FPP
- write_log (_T("no FPU: %04x %08x PC=%08x\n"), opcode, extra, oldpc);
+ write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
#endif
fpu_op_illg2 (opcode, extra, ea, oldpc);
return true;
return false;
}
-static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
+static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, int reg)
{
if (fault_if_no_fpu (opcode, extra, ea, oldpc))
return true;
if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
+ if ((extra & (0x8000 | 0x2000)) != 0)
+ return false;
+ if ((extra & 0xfc00) == 0x5c00) {
+ // FMOVECR
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
+ return true;
+ }
uae_u16 v = extra & 0x7f;
switch (v)
{
case 0x03: /* FINTRZ */
// Unimplemented only in 68040.
if (currprefs.cpu_model == 68040) {
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
return true;
}
return false;
-
case 0x02: /* FSINH */
case 0x06: /* FLOGNP1 */
case 0x08: /* FETOXM1 */
case 0x21: /* FMOD */
case 0x25: /* FREM */
case 0x26: /* FSCALE */
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
return true;
}
}
case 0x67: /* FDMUL */
case 0x41: /* FSSQRT */
case 0x45: /* FDSQRT */
- fpu_noinst (opcode, oldpc);
+ fpu_noinst (opcode, oldpc);
return true;
}
}
return false;
}
-static bool fault_if_4060 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, int type)
+static bool fault_if_4060 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, int type, uae_u32 *pack)
{
if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
- // do not emulate missing datatype yet, much more complex
- // requires pre and post exceptions..
- if (type == FPU_EXP_UNIMP_DATATYPE)
+ // do not emulate missing datatype yet, probably not working yet.
+ if (type == FPU_EXP_UNIMP_DATATYPE_PRE || type == FPU_EXP_UNIMP_DATATYPE_POST)
return false;
- fpu_op_unimp (opcode, extra, ea, oldpc, type);
+ if (pack) {
+ regs.exp_pack[0] = pack[0];
+ regs.exp_pack[1] = pack[1];
+ regs.exp_pack[2] = pack[2];
+ }
+ fpu_op_unimp (opcode, extra, ea, oldpc, type, NULL, -1);
return true;
}
return false;
return true;
if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
// 68060 FTRAP, FDBcc or FScc are not implemented.
- fpu_op_unimp (opcode, extra, ea, m68k_getpc (), FPU_EXP_UNIMP_INS);
+ fpu_op_unimp (opcode, extra, ea, m68k_getpc (), FPU_EXP_UNIMP_INS, NULL, -1);
return true;
}
return false;
{
if (currprefs.cpu_model < 68040 && currprefs.fpu_model <= 0) {
#if EXCEPTION_FPP
- write_log (_T("6888x no FPU: %04x %08x PC=%08x\n"), opcode, extra, oldpc);
+ write_log (_T("6888x no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
#endif
m68k_setpc (oldpc);
regs.fp_exception = true;
static void fpu_null (void)
{
regs.fpu_state = 0;
+ regs.fpu_exp_state = 0;
regs.fpcr = 0;
regs.fpsr = 0;
regs.fpiar = 0;
regs.fpsr_highbyte = 0;
fpclear (®s.fp_result);
for (int i = 0; i < 8; i++)
- fpclear (®s.fp[i]);
+ fpnan (®s.fp[i]);
}
#define fp_round_to_minus_infinity(x) floor(x)
fpset (®s.fp_result, 1);
}
+uae_u32 get_ftag (fpdata *fp)
+{
+ uae_u32 sr;
+ regs.fp_result = *fp;
+ sr = get_fpsr ();
+ if (sr & 0x01000000)
+ return 3;
+ if (sr & 0x02000000)
+ return 2;
+ if (sr & 0x04000000)
+ return 1;
+ return 0;
+}
+
/* single : S 8*E 23*F */
/* double : S 11*E 52*F */
/* extended : S 15*E 64*F */
/* E = MAX & F # 0 -> NotANumber */
/* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
-static fptype to_pack (uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+static fptype to_pack (uae_u32 *wrd)
{
fptype d;
char *cp;
char str[100];
cp = str;
- if (wrd1 & 0x80000000)
+ if (wrd[0] & 0x80000000)
*cp++ = '-';
- *cp++ = (wrd1 & 0xf) + '0';
+ *cp++ = (wrd[0] & 0xf) + '0';
*cp++ = '.';
- *cp++ = ((wrd2 >> 28) & 0xf) + '0';
- *cp++ = ((wrd2 >> 24) & 0xf) + '0';
- *cp++ = ((wrd2 >> 20) & 0xf) + '0';
- *cp++ = ((wrd2 >> 16) & 0xf) + '0';
- *cp++ = ((wrd2 >> 12) & 0xf) + '0';
- *cp++ = ((wrd2 >> 8) & 0xf) + '0';
- *cp++ = ((wrd2 >> 4) & 0xf) + '0';
- *cp++ = ((wrd2 >> 0) & 0xf) + '0';
- *cp++ = ((wrd3 >> 28) & 0xf) + '0';
- *cp++ = ((wrd3 >> 24) & 0xf) + '0';
- *cp++ = ((wrd3 >> 20) & 0xf) + '0';
- *cp++ = ((wrd3 >> 16) & 0xf) + '0';
- *cp++ = ((wrd3 >> 12) & 0xf) + '0';
- *cp++ = ((wrd3 >> 8) & 0xf) + '0';
- *cp++ = ((wrd3 >> 4) & 0xf) + '0';
- *cp++ = ((wrd3 >> 0) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 28) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 24) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 20) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 16) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 12) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 8) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 4) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 0) & 0xf) + '0';
+ *cp++ = ((wrd[1] >> 28) & 0xf) + '0';
+ *cp++ = ((wrd[2] >> 24) & 0xf) + '0';
+ *cp++ = ((wrd[2] >> 20) & 0xf) + '0';
+ *cp++ = ((wrd[2] >> 16) & 0xf) + '0';
+ *cp++ = ((wrd[2] >> 12) & 0xf) + '0';
+ *cp++ = ((wrd[2] >> 8) & 0xf) + '0';
+ *cp++ = ((wrd[2] >> 4) & 0xf) + '0';
+ *cp++ = ((wrd[2] >> 0) & 0xf) + '0';
*cp++ = 'E';
- if (wrd1 & 0x40000000)
+ if (wrd[0] & 0x40000000)
*cp++ = '-';
- *cp++ = ((wrd1 >> 24) & 0xf) + '0';
- *cp++ = ((wrd1 >> 20) & 0xf) + '0';
- *cp++ = ((wrd1 >> 16) & 0xf) + '0';
+ *cp++ = ((wrd[0] >> 24) & 0xf) + '0';
+ *cp++ = ((wrd[0] >> 20) & 0xf) + '0';
+ *cp++ = ((wrd[0] >> 16) & 0xf) + '0';
*cp = 0;
#if USE_LONG_DOUBLE
sscanf (str, "%Le", &d);
}
// TODO: Positive k-Factor.
-static void from_pack (fptype src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3, int kfactor)
+static void from_pack (fptype src, uae_u32 *wrd, int kfactor)
{
int i, t, precision;
char *cp;
sprintf (str, "%#.*e", precision, src);
#endif
cp = str;
- *wrd1 = *wrd2 = *wrd3 = 0;
+ wrd[0] = wrd[1] = wrd[2] = 0;
if (*cp == '-') {
cp++;
- *wrd1 = 0x80000000;
+ wrd[0] = 0x80000000;
}
if (*cp == '+')
cp++;
- *wrd1 |= (*cp++ - '0');
+ wrd[0] |= (*cp++ - '0');
if (*cp == '.')
cp++;
for (i = 0; i < 8; i++) {
- *wrd2 <<= 4;
+ wrd[1] <<= 4;
if (*cp >= '0' && *cp <= '9')
- *wrd2 |= *cp++ - '0';
+ wrd[1] |= *cp++ - '0';
}
for (i = 0; i < 8; i++) {
- *wrd3 <<= 4;
+ wrd[2] <<= 4;
if (*cp >= '0' && *cp <= '9')
- *wrd3 |= *cp++ - '0';
+ wrd[2] |= *cp++ - '0';
}
if (*cp == 'e') {
cp++;
if (*cp == '-') {
cp++;
- *wrd1 |= 0x40000000;
+ wrd[0] |= 0x40000000;
}
if (*cp == '+')
cp++;
cp--;
}
}
- *wrd1 |= t << 16;
+ wrd[0] |= t << 16;
}
}
-STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc)
+static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
{
int size, mode, reg;
uae_u32 ad = 0;
case 6:
exts[0] = x_cp_next_iword ();
break;
- }
+ }
break;
default:
return 0;
}
}
- if (fault_if_unimplemented_680x0 (opcode, extra, ad, oldpc))
+ *adp = ad;
+
+ if (currprefs.fpu_model == 68060 && fault_if_unimplemented_680x0 (opcode, extra, ad, oldpc, src, -1))
return -1;
switch (size)
case 2:
{
uae_u32 wrd1, wrd2, wrd3;
- if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE))
- return -1;
wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
ad += 4;
wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
break;
case 3:
{
- uae_u32 wrd1, wrd2, wrd3;
- if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE))
- return -1;
- wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
+ uae_u32 wrd[3];
+ wrd[0] = (doext ? exts[0] : x_cp_get_long (ad));
ad += 4;
- wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
+ wrd[1] = (doext ? exts[1] : x_cp_get_long (ad));
ad += 4;
- wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
- src->fp = to_pack (wrd1, wrd2, wrd3);
+ wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
+ if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE_PRE, wrd))
+ return -1;
+ src->fp = to_pack (wrd);
}
break;
case 4:
return 1;
}
-STATIC_INLINE int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc)
+static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc)
{
int size, mode, reg;
uae_u32 ad = 0;
case 2:
{
uae_u32 wrd1, wrd2, wrd3;
- if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE))
- return -1;
from_exten (value, &wrd1, &wrd2, &wrd3);
x_cp_put_long (ad, wrd1);
ad += 4;
case 3: // Packed-Decimal Real with Static k-Factor
case 7: // Packed-Decimal Real with Dynamic k-Factor (P{Dn}) (reg to memory only)
{
- uae_u32 wrd1, wrd2, wrd3;
+ uae_u32 wrd[3];
int kfactor;
- if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE))
+ if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE_POST, NULL))
return -1;
kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
if (kfactor & 64)
kfactor |= ~63;
- from_pack (value->fp, &wrd1, &wrd2, &wrd3, kfactor);
- x_cp_put_long (ad, wrd1);
+ from_pack (value->fp, wrd, kfactor);
+ x_cp_put_long (ad, wrd[0]);
ad += 4;
- x_cp_put_long (ad, wrd2);
+ x_cp_put_long (ad, wrd[1]);
ad += 4;
- x_cp_put_long (ad, wrd3);
+ x_cp_put_long (ad, wrd[2]);
}
break;
case 4:
return -1;
}
+static void maybe_idle_state (void)
+{
+ // conditional floating point instruction does not change state
+ // from null to idle on 68040/060.
+ if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882)
+ regs.fpu_state = 1;
+}
+
void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
{
uaecptr pc = m68k_getpc ();
if (fault_if_no_fpu_u (opcode, extra, pc + disp, pc - 4))
return;
regs.fpiar = pc - 4;
- regs.fpu_state = 1;
+ maybe_idle_state ();
cc = fpp_cond (extra & 0x3f);
if (cc == -1) {
fpu_op_illg (opcode, extra, regs.fpiar);
return;
regs.fpiar = pc;
- regs.fpu_state = 1;
+ maybe_idle_state ();
cc = fpp_cond (extra & 0x3f);
if (cc == -1) {
fpu_op_illg (opcode, extra, regs.fpiar);
return;
regs.fpiar = oldpc;
- regs.fpu_state = 1;
+ maybe_idle_state ();
cc = fpp_cond (extra & 0x3f);
if (cc == -1) {
fpu_op_illg (opcode, extra, oldpc);
return;
regs.fpiar = oldpc - 2;
- regs.fpu_state = 1;
+ maybe_idle_state ();
cc = fpp_cond (opcode & 0x3f);
if (cc == -1) {
fpu_op_illg (opcode, extra, oldpc - 2);
if (fault_if_no_fpu (opcode, 0, ad, pc))
return;
+
regs.fpiar = pc;
if (currprefs.fpu_model == 68060) {
/* 12 byte 68060 NULL/IDLE frame. */
- uae_u32 frame_id = regs.fpu_state == 0 ? 0x00000000 : 0x00006000;
- if (incr < 0) {
- ad -= 4;
- x_put_long (ad, 0x00000000);
- ad -= 4;
- x_put_long (ad, 0x00000000);
- ad -= 4;
- x_put_long (ad, frame_id);
+ int frame_size = 12;
+ uae_u32 frame_id;
+
+ if (regs.fpu_exp_state) {
+ frame_id = 0x0000e000;
} else {
- x_put_long (ad, frame_id);
- ad += 4;
- x_put_long (ad, 0x00000000);
- ad += 4;
- x_put_long (ad, 0x00000000);
- ad += 4;
+ frame_id = regs.fpu_state == 0 ? 0x00000000 : 0x00006000;
}
+ if (incr < 0)
+ ad -= frame_size;
+ x_put_long (ad, frame_id);
+ ad += 4;
+ x_put_long (ad, 0x00000000);
+ ad += 4;
+ x_put_long (ad, 0x00000000);
+ ad += 4;
+ if (incr < 0)
+ ad -= frame_size;
} else if (currprefs.fpu_model == 68040) {
- /* 4 byte 68040 NULL/IDLE frame. */
- uae_u32 frame_id = regs.fpu_state == 0 ? 0 : fpu_version << 24;
- if (incr < 0) {
- ad -= 4;
- x_put_long (ad, frame_id);
+ if (!regs.fpu_exp_state) {
+ /* 4 byte 68040 NULL/IDLE frame. */
+ uae_u32 frame_id = regs.fpu_state == 0 ? 0 : fpu_version << 24;
+ if (incr < 0) {
+ ad -= 4;
+ x_put_long (ad, frame_id);
+ } else {
+ x_put_long (ad, frame_id);
+ ad += 4;
+ }
} else {
+ /* 52 byte 68040 unimplemented instruction frame */
+ int frame_size = 0x34;
+ uae_u32 frame_id = ((fpu_version << 8) | (frame_size - 4)) << 16;
+ uae_u32 src1[3], src2[3];
+ uae_u32 extra = regs.exp_extra;
+
+ from_exten (®s.exp_src1, &src1[0], &src1[1], &src1[2]);
+ from_exten (®s.exp_src2, &src2[0], &src2[1], &src2[2]);
+ if (incr < 0)
+ ad -= frame_size;
x_put_long (ad, frame_id);
ad += 4;
+ x_put_long (ad, ((extra & (0x200 | 0x100 | 0x80)) | (extra & (0x40 | 0x02 ||0x01)) | ((extra >> 1) & (0x04 | 0x08 | 0x10)) | ((extra & 0x04) ? 0x20 : 0x00)) << 16); // CMDREG3B
+ ad += 4;
+ x_put_long (ad, 0);
+ ad += 4;
+ x_put_long (ad, get_ftag (®s.exp_src1) << 29); // STAG
+ ad += 4;
+ x_put_long (ad, extra << 16); // CMDREG1B
+ ad += 4;
+ x_put_long (ad, get_ftag (®s.exp_src2) << 29); // DTAG
+ ad += 4;
+ x_put_long (ad, (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PRE ? 1 << 26 : 0) | (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_POST ? 1 << 20 : 0)); // E1 and T
+ ad += 4;
+ if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PRE) {
+ x_put_long (ad, 0); // FPTS/FPTE
+ ad += 4;
+ x_put_long (ad, 0); // FPTM
+ ad += 4;
+ x_put_long (ad, regs.exp_pack[0]); // FPTM
+ ad += 4;
+ x_put_long (ad, 0); // ETS/ETE
+ ad += 4;
+ x_put_long (ad, regs.exp_pack[1]); // ETM
+ ad += 4;
+ x_put_long (ad, regs.exp_pack[2]); // ETM
+ ad += 4;
+ } else {
+ x_put_long (ad, src2[0]); // FPTS/FPTE
+ ad += 4;
+ x_put_long (ad, src2[1]); // FPTM
+ ad += 4;
+ x_put_long (ad, src2[2]); // FPTM
+ ad += 4;
+ x_put_long (ad, src1[0]); // ETS/ETE
+ ad += 4;
+ x_put_long (ad, src1[1]); // ETM
+ ad += 4;
+ x_put_long (ad, src1[2]); // ETM
+ ad += 4;
+ }
+ if (incr < 0)
+ ad -= frame_size;
}
} else { /* 68881/68882 */
int frame_size = regs.fpu_state == 0 ? 0 : currprefs.fpu_model == 68882 ? 0x3c : 0x1c;
m68k_areg (regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg (regs, opcode & 7) = ad;
+ regs.fpu_exp_state = 0;
}
void fpuop_restore (uae_u32 opcode)
}
if (currprefs.fpu_model == 68060) {
- if ((d & 0x0000ff00) != 0) {
+ int ff = (d >> 8) & 0xff;
+ if (ff == 0x60) {
regs.fpu_state = 1;
+ regs.fpu_exp_state = 0;
+ } else if (ff == 0xe0) {
+ regs.fpu_exp_state = 1;
+ } else if (ff) {
+ write_log (_T("FRESTORE invalid frame format %X!\n"), (d >> 8) & 0xff);
} else {
fpu_null ();
}
static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
{
- int reg, v;
+ int reg = -1;
+ int v;
fptype src;
fpdata srcd;
uaecptr pc = m68k_getpc () - 4;
ad += 4;
}
if (extra & 0x0800) {
- x_cp_put_long (ad, get_fpsr());
+ x_cp_put_long (ad, get_fpsr ());
ad += 4;
}
if (extra & 0x0400) {
ad += 4;
}
if (extra & 0x0800) {
- set_fpsr(x_cp_get_long (ad));
+ set_fpsr (x_cp_get_long (ad));
ad += 4;
}
if (extra & 0x0400) {
{
uae_u32 ad, list = 0;
int incr = 0;
+ if (get_fp_ad (opcode, &ad) == 0) {
+ fpu_noinst (opcode, pc);
+ return;
+ }
+ if (fault_if_no_fpu (opcode, extra, ad, pc))
+ return;
+ switch ((extra >> 11) & 3)
+ {
+ case 0: /* static pred */
+ list = extra & 0xff;
+ incr = -1;
+ break;
+ case 1: /* dynamic pred */
+ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
+ incr = -1;
+ break;
+ case 2: /* static postinc */
+ list = extra & 0xff;
+ incr = 1;
+ break;
+ case 3: /* dynamic postinc */
+ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
+ incr = 1;
+ break;
+ }
+ // (an)+ and -(an) override incr
+ if ((opcode & 0x38) == 0x18)
+ incr = 1;
+ if ((opcode & 0x38) == 0x20)
+ incr = -1;
if (extra & 0x2000) {
/* FMOVEM FPP->memory */
- if (get_fp_ad (opcode, &ad) == 0) {
- fpu_noinst (opcode, pc);
- return;
- }
- if (fault_if_no_fpu (opcode, extra, ad, pc))
- return;
-
- switch ((extra >> 11) & 3)
- {
- case 0: /* static pred */
- list = extra & 0xff;
- incr = -1;
- break;
- case 1: /* dynamic pred */
- list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
- incr = -1;
- break;
- case 2: /* static postinc */
- list = extra & 0xff;
- incr = 1;
- break;
- case 3: /* dynamic postinc */
- list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
- incr = 1;
- break;
- }
ad = fmovem2mem (ad, list, incr);
- if ((opcode & 0x38) == 0x18)
- m68k_areg (regs, opcode & 7) = ad;
- if ((opcode & 0x38) == 0x20)
- m68k_areg (regs, opcode & 7) = ad;
} else {
/* FMOVEM memory->FPP */
- if (get_fp_ad (opcode, &ad) == 0) {
- fpu_noinst (opcode, pc);
- return;
- }
- if (fault_if_no_fpu (opcode, extra, ad, pc))
- return;
- switch ((extra >> 11) & 3)
- {
- case 0: /* static pred */
- list = extra & 0xff;
- incr = -1;
- break;
- case 1: /* dynamic pred */
- list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
- incr = -1;
- break;
- case 2: /* static postinc */
- list = extra & 0xff;
- incr = 1;
- break;
- case 3: /* dynamic postinc */
- list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
- incr = 1;
- break;
- }
ad = fmovem2fpp (ad, list, 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 || (opcode & 0x38) == 0x20)
+ m68k_areg (regs, opcode & 7) = ad;
}
return;
case 0:
case 2: /* Extremely common */
- regs.fpiar = pc;
+ regs.fpiar = pc;
reg = (extra >> 7) & 7;
#ifdef USE_SOFT_LONG_DOUBLE
regs.fp[reg].fpx = false;
if ((extra & 0xfc00) == 0x5c00) {
if (fault_if_no_fpu (opcode, extra, 0, pc))
return;
+ if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &srcd, reg))
+ return;
switch (extra & 0x7f)
{
case 0x00:
if (fault_if_unimplemented_6888x (opcode, extra, pc))
return;
- v = get_fp_value (opcode, extra, &srcd, pc);
+ v = get_fp_value (opcode, extra, &srcd, pc, &ad);
if (v <= 0) {
if (v == 0)
fpu_noinst (opcode, pc);
src = srcd.fp;
// get_fp_value() checked this, but only if EA was nonzero (non-register)
- if (fault_if_unimplemented_680x0 (opcode, extra, 0, pc))
+ if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &srcd, reg))
return;
regs.fpiar = pc;
void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
{
+#if 0
if (opcode == 0xf210 && extra == 0x7c00) {
// activate_debugger();
// return;
write_log (_T("*"));
}
-
+#endif
regs.fpsr_highbyte = 0;
regs.fpu_state = 1;
regs.fp_exception = false;
void fpu_reset (void)
{
regs.fpcr = regs.fpsr = regs.fpiar = 0;
+ regs.fpu_exp_state = 0;
fpset (®s.fp_result, 1);
native_set_fpucw (regs.fpcr);
fpux_restore (NULL);
restore_u32 ();
}
regs.fpu_state = (flags & 1) ? 0 : 1;
+ regs.fpu_exp_state = (flags & 2) ? 1 : 0;
write_log (_T("FPU: %d\n"), currprefs.fpu_model);
return src;
}
else
dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4);
save_u32 (currprefs.fpu_model);
- save_u32 (0x80000000 | (regs.fpu_state == 0 ? 1 : 0));
+ save_u32 (0x80000000 | (regs.fpu_state == 0 ? 1 : 0) | (regs.fpu_exp_state ? 2 : 0));
for (i = 0; i < 8; i++) {
uae_u32 w1, w2, w3;
from_exten (®s.fp[i], &w1, &w2, &w3);