FPP_FROM_EXTEN fpp_from_exten_fmovem;
FPP_A fpp_normalize;
-FPP_PACK fpp_get_exceptional_operand;
+FPP_A fpp_get_internal_overflow;
+FPP_A fpp_get_internal_underflow;
FPP_PACKG fpp_get_exceptional_operand_grs;
FPP_A fpp_round_single;
return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model;
}
+static int warned = 100;
+
struct fpp_cr_entry {
uae_u32 val[3];
uae_u8 inexact;
static struct {
// 6888x and 68060
+ uae_u32 ccr;
uae_u32 eo[3];
// 68060
uae_u32 v;
fsave_data.et[i] = 0;
fsave_data.wbt[i] = 0;
}
+ fsave_data.ccr = 0;
fsave_data.v = 0;
fsave_data.fpiarcu = 0;
fsave_data.cmdreg1b = 0;
return 0; // NORMAL
}
-static bool fp_arithmetic_exception(bool pre)
+STATIC_INLINE bool fp_is_dyadic(uae_u16 extra)
+{
+ return ((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38);
+}
+
+static bool fp_exception_pending(bool pre)
{
// first check for pending arithmetic exceptions
if (currprefs.fpu_exceptions) {
if (regs.fp_exp_pend) {
- write_log (_T("FPU ARITHMETIC EXCEPTION (%d)\n"), regs.fp_exp_pend);
+ if (warned > 0) {
+ write_log (_T("FPU ARITHMETIC EXCEPTION (%d)\n"), regs.fp_exp_pend);
+ }
regs.fpu_exp_pre = pre;
Exception(regs.fp_exp_pend);
if (currprefs.fpu_model != 68882)
return true;
}
}
- // no arithmetic exceptions pending, check for unimplemented
+ // no arithmetic exceptions pending, check for unimplemented datatype
if (regs.fp_unimp_pend) {
- write_log (_T("FPU UNIMPLEMENTED DATATYPE EXCEPTION\n"));
+ if (warned > 0) {
+ write_log (_T("FPU unimplemented datatype exception (%s)\n"), pre ? _T("pre") : _T("mid/post"));
+ }
regs.fpu_exp_pre = pre;
Exception(55);
regs.fp_unimp_pend = 0;
return false;
}
-static void fp_unimplemented_instruction_exception(void)
+static void fp_unimp_instruction_exception_pending(void)
{
if (regs.fp_unimp_ins) {
- write_log (_T("FPU UNIMPLEMENTED INSTRUCTION EXCEPTION\n"));
+ if (warned > 0) {
+ write_log (_T("FPU UNIMPLEMENTED INSTRUCTION EXCEPTION\n"));
+ }
regs.fpu_exp_pre = true;
Exception(11);
regs.fp_unimp_ins = false;
return 0;
}
-static void fpsr_check_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea)
+static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea)
{
if (!currprefs.fpu_softfloat)
return;
if (exception) {
regs.fp_exp_pend = fpsr_get_vector(exception);
nonmaskable = (regs.fp_exp_pend != fpsr_get_vector(regs.fpsr & regs.fpcr));
- write_log(_T("FPU %s arithmetic exception pending: FPSR: %08x, FPCR: %04x (vector: %d)!\n"),
- nonmaskable ? _T("nonmaskable") : _T(""), regs.fpsr, regs.fpcr, regs.fp_exp_pend);
+ if (warned > 0) {
+ write_log(_T("FPU %s arithmetic exception pending: FPSR: %08x, FPCR: %04x (vector: %d)!\n"),
+ nonmaskable ? _T("nonmaskable") : _T(""), regs.fpsr, regs.fpcr, regs.fp_exp_pend);
+#if EXCEPTION_FPP == 0
+ warned--;
+#endif
+ }
if (!currprefs.fpu_exceptions) {
// log message and exit
// data for FSAVE stack frame
regs.fpu_exp_state = 2; // 68060 EXCP frame, 68040 BUSY frame, 6888x IDLE frame
- /* TODO: more FSAVE data */
+ uae_u32 opclass = (extra >> 13) & 7;
if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) {
// fsave data for 68881 and 68882
- fpp_get_exceptional_operand(&fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
+ fpdata eo;
+
+ if (opclass == 3) { // 011
+ fsave_data.ccr = ((uae_u32)extra << 16) | extra;
+ } else { // 000 or 010
+ fsave_data.ccr = ((uae_u32)(opcode | 0x0080) << 16) | extra;
+ }
+ if (regs.fp_exp_pend == 54 || regs.fp_exp_pend == 52 || regs.fp_exp_pend == 50) { // SNAN, OPERR, DZ
+ fpp_from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
+ if (regs.fp_exp_pend == 52 && opclass == 3) { // OPERR from move to integer or packed
+ fsave_data.eo[0] &= 0x4fff0000;
+ fsave_data.eo[1] = fsave_data.eo[2] = 0;
+ }
+ } else if (regs.fp_exp_pend == 53) { // OVFL
+ fpp_get_internal_overflow(&eo);
+ if (((regs.fpcr >> 6) & 3) == 1)
+ fpp_round32(&eo);
+ if (((regs.fpcr >> 6) & 3) >= 2)
+ fpp_round64(&eo);
+ fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
+ } else if (regs.fp_exp_pend == 51) { // UNFL
+ fpp_get_internal_underflow(&eo);
+ if (((regs.fpcr >> 6) & 3) == 1)
+ fpp_round32(&eo);
+ if (((regs.fpcr >> 6) & 3) >= 2)
+ fpp_round64(&eo);
+ fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
+ } // else INEX1, INEX2: do nothing
+
} else if (currprefs.cpu_model == 68060) {
// fsave data for 68060
fsave_data.v = regs.fp_exp_pend & 7;
- fpp_get_exceptional_operand(&fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
} else {
uae_u32 reg = (extra >> 7) & 7;
uae_u32 size = (extra >> 10) & 7;
- uae_u32 opclass = (extra >> 13) & 7;
- bool dyadic = ((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38);
bool exp_e3 = false;
// fsave data for 68040
fsave_data.e1 = 1;
fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
fsave_data.stag = get_ftag(src, size);
- if (dyadic) {
+ if (fp_is_dyadic(extra)) {
fpp_from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
fsave_data.dtag = get_ftag(®s.fp[reg], -1);
}
write_log (_T("FPU exception: BSUN! (FPSR: %08x, FPCR: %04x)\n"), regs.fpsr, regs.fpcr);
if (currprefs.fpu_exceptions) {
regs.fp_exp_pend = fpsr_get_vector(FPSR_BSUN);
- fp_arithmetic_exception(true);
+ fp_exception_pending(true);
return 1;
}
}
}
#endif
-static void fpu_op_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, int reg, int size)
+static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, int reg, int size)
{
- static int warned = 20;
-
- regs.fpiar = oldpc;
-
if ((extra & 0x7f) == 4) // FSQRT 4->5
extra |= 1;
if (currprefs.cpu_model == 68060) {
// fsave data for 68060
- fpp_get_exceptional_operand(&fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
+ fsave_data.v = 0; // really?
} else if(currprefs.cpu_model == 68040) {
// fsave data for 68040
fsave_data.fpiarcu = regs.fpiar;
- if (!regs.fp_unimp_pend) { // else data has been saved by fp_check_unimp_datatype
+ if (regs.fp_unimp_pend == 0) { // else data has been saved by fp_unimp_datatype
reset_fsave_data();
fsave_data.cmdreg3b = (extra & 0x3C3) | ((extra & 0x038) >> 1) | ((extra & 0x004) << 3);
fsave_data.cmdreg1b = extra;
}
}
if (warned > 0) {
- write_log(_T("FPU UNIMPLEMENTED INSTRUCTION EXCEPTION OP=%04X-%04X EA=%08X PC=%08X -> %08X\n"),
- opcode, extra, ea, oldpc, m68k_getpc());
-#if EXCEPTION_FPP == 0
+ write_log (_T("FPU unimplemented instruction: OP=%04X-%04X EA=%08X PC=%08X\n"),
+ opcode, extra, ea, oldpc);
+ #if EXCEPTION_FPP == 0
warned--;
-#endif
+ #endif
}
- // report exception immediately
regs.fp_ea = ea;
regs.fp_unimp_ins = true;
- fp_unimplemented_instruction_exception();
+ fp_unimp_instruction_exception_pending();
regs.fp_exception = true;
}
-static void fp_check_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
+static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
{
- static int warned = 20;
uae_u32 reg = (extra >> 7) & 7;
uae_u32 size = (extra >> 10) & 7;
uae_u32 opclass = (extra >> 13) & 7;
- bool dyadic = ((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38);
- regs.fpiar = oldpc;
regs.fp_ea = ea;
+ regs.fp_unimp_pend = packed ? 2 : 1;
if((extra & 0x7f) == 4) // FSQRT 4->5
extra |= 1;
- regs.fp_unimp_pend = 1;
- if (packed)
- regs.fp_unimp_pend |= 2;
-
// data for fsave stack frame
reset_fsave_data();
regs.fpu_exp_state = 2; // 68060 EXCP frame, 68040 BUSY frame
if (currprefs.cpu_model == 68060) {
// fsave data for 68060
fsave_data.v = 7; // vector & 0x7
- fpp_get_exceptional_operand(&fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
} else if (currprefs.cpu_model == 68040) {
// fsave data for 68040
fsave_data.cmdreg1b = extra;
if (fsave_data.stag == 5) {
fsave_data.et[0] = (size == 1) ? 0x3f800000 : 0x3c000000; // exponent for denormalized single and double
}
- if (dyadic) {
+ if (fp_is_dyadic(extra)) {
fpp_from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
fsave_data.dtag = get_ftag(®s.fp[reg], -1);
}
}
}
if (warned > 0) {
- write_log (_T("FPU EXCEPTION OP=%04X-%04X EA=%08X PC=%08X -> %08X\n"), opcode, extra, ea, oldpc, m68k_getpc());
+ write_log (_T("FPU unimplemented datatype (%s): OP=%04X-%04X EA=%08X PC=%08X\n"),
+ packed ? _T("packed") : _T("denormal"), opcode, extra, ea, oldpc);
#if EXCEPTION_FPP == 0
warned--;
#endif
|| (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
regs.fp_unimp_ins = true;
regs.fp_ea = ea;
- fp_unimplemented_instruction_exception();
+ fp_unimp_instruction_exception_pending();
return;
}
regs.fp_exception = true;
return false;
if ((extra & 0xfc00) == 0x5c00) {
// FMOVECR
- fpu_op_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
+ fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
return true;
}
uae_u16 v = extra & 0x7f;
return false;
}
default:
- fpu_op_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
+ fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
return true;
}
}
return false;
}
-static bool fault_if_4060 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
-{
- if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
- fp_check_unimp_datatype(opcode, extra, ea, oldpc, src, packed);
- //fpu_op_unimp (opcode, extra, ea, oldpc, type, src, -1, -1);
- return true;
- }
- return false;
-}
-
static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
{
if (fault_if_no_fpu (opcode, extra, ea, oldpc))
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_instruction(opcode, extra, ea, oldpc, NULL, -1, -1);
+ regs.fp_unimp_ins = true;
+ regs.fp_ea = ea;
+ fp_unimp_instruction_exception_pending();
return true;
}
return false;
// get exponent
cp = str;
- while (*cp++ != 'e');
+ while (*cp != 'e') {
+ if (*cp == 0)
+ return;
+ cp++;
+ }
+ cp++;
if (*cp == '+')
cp++;
exp = atoi (cp);
// remove trailing zeros
cp = str;
- while (*cp != 'e')
+ while (*cp != 'e') {
cp++;
+ }
cp[0] = 0;
cp--;
while (cp > str && *cp == '0') {
{
if (fpp_is_unnormal(src) || fpp_is_denormal(src)) {
if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
- fp_check_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
- //fpu_op_unimp(opcode, extra, ea, oldpc, FP_EXP_UNIMP_DATATYPE_PRE, fpd, -1, size);
+ fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
return true;
} else {
fpp_normalize(src);
- return false;
}
}
return false;
{
if (fpp_is_unnormal(dst) || fpp_is_denormal(dst)) {
if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
- fp_check_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
- //fpu_op_unimp(opcode, extra, ea, oldpc, FP_EXP_UNIMP_DATATYPE_POST, fpd, -1, size);
+ fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
return true;
} else {
fpp_normalize(dst);
- return false;
}
}
return false;
}
+// 68040/060 does not support packed decimal format
+static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
+{
+ if (currprefs.cpu_model >= 68040 && currprefs.fpu_model) {
+ fp_unimp_datatype(opcode, extra, ea, oldpc, src, packed);
+ return true;
+ }
+ return false;
+ }
+
+// 68040 does not support move to integer format
static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
{
if (currprefs.cpu_model == 68040 && currprefs.fpu_model) {
fpsr_make_status();
if (regs.fpsr & (FPSR_SNAN | FPSR_OPERR)) {
- fpsr_check_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea);
- fp_arithmetic_exception(false); // post
+ fpsr_check_arithmetic_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea);
+ fp_exception_pending(false); // post
if (currprefs.fpu_exceptions)
return true;
}
if (fault_if_no_fpu (opcode, extra, 0, oldpc))
return -1;
*src = regs.fp[(extra >> 10) & 7];
- if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src))
- return -1;
+ normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
return 1;
}
mode = (opcode >> 3) & 7;
break;
case 1:
fpp_to_single (src, m68k_dreg (regs, reg));
- if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src))
- return -1;
+ normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
break;
default:
return 0;
}
*adp = ad;
+ uae_u32 adold = ad;
- if (currprefs.fpu_model == 68060 && fault_if_unimplemented_680x0 (opcode, extra, ad, oldpc, src, -1))
- return -1;
+ if (currprefs.fpu_model == 68060) {
+ if (fault_if_unimplemented_680x0(opcode, extra, ad, oldpc, src, -1)) {
+ return -1;
+ }
+ }
switch (size)
{
break;
case 1:
fpp_to_single (src, (doext ? exts[0] : x_cp_get_long (ad)));
- if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src))
- return -1;
+ normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
break;
case 2:
{
ad += 4;
wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
fpp_to_exten (src, wrd1, wrd2, wrd3);
- if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src))
- return -1;
+ normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
}
break;
case 3:
{
uae_u32 wrd[3];
- uae_u32 adold = ad;
if (currprefs.cpu_model == 68060) {
- if (fault_if_4060 (opcode, extra, adold, oldpc, NULL, wrd))
- return -1;
+ if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd))
+ return 1;
}
wrd[0] = (doext ? exts[0] : x_cp_get_long (ad));
ad += 4;
wrd[1] = (doext ? exts[1] : x_cp_get_long (ad));
ad += 4;
wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
- if (fault_if_4060 (opcode, extra, adold, oldpc, NULL, wrd))
- return -1;
+ if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd))
+ return 1;
to_pack (src, wrd);
fpp_normalize(src);
return 1;
ad += 4;
wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
fpp_to_double (src, wrd1, wrd2);
- if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src))
- return -1;
+ normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
}
break;
case 6:
switch (mode)
{
case 0:
- if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
- return -1;
switch (size)
{
case 6:
+ 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)
| (m68k_dreg (regs, reg) & ~0xff)));
if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
return -1;
break;
case 4:
+ 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)
| (m68k_dreg (regs, reg) & ~0xffff)));
if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
return -1;
break;
case 0:
+ 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:
+ if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
+ return 1;
m68k_dreg (regs, reg) = fpp_from_single (value);
break;
default:
{
case 0:
if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
- return -1;
+ 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:
if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
- return -1;
+ return 1;
x_cp_put_long(ad, fpp_from_single(value));
break;
case 2:
{
- uae_u32 wrd1, wrd2, wrd3;
if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
- return -1;
+ return 1;
+ uae_u32 wrd1, wrd2, wrd3;
fpp_from_exten(value, &wrd1, &wrd2, &wrd3);
x_cp_put_long (ad, wrd1);
ad += 4;
{
uae_u32 wrd[3];
int kfactor;
- if (fault_if_4060 (opcode, extra, ad, oldpc, value, wrd))
- return 1; // for calling fp_arithmetic_exception
+ if (fault_if_no_packed_support (opcode, extra, ad, oldpc, value, wrd))
+ return 1;
kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
kfactor &= 127;
if (kfactor & 64)
break;
case 4:
if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
- return -1;
+ 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:
{
- uae_u32 wrd1, wrd2;
if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
- return -1;
+ return 1;
+ uae_u32 wrd1, wrd2;
fpp_from_double(value, &wrd1, &wrd2);
x_cp_put_long (ad, wrd1);
ad += 4;
break;
case 6:
if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
- return -1;
+ return 1;
x_cp_put_byte(ad, (uae_s8)fpp_to_int(value, 0));
if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
return -1;
uae_s32 disp;
int cc;
- if (fp_arithmetic_exception(true))
+ if (fp_exception_pending(true))
return;
regs.fp_exception = false;
int cc;
uaecptr pc = m68k_getpc () - 4;
- if (fp_arithmetic_exception(true))
+ if (fp_exception_pending(true))
return;
regs.fp_exception = false;
{
int cc;
- if (fp_arithmetic_exception(true))
+ if (fp_exception_pending(true))
return;
regs.fp_exception = false;
{
int cc;
- if (fp_arithmetic_exception(true))
+ if (fp_exception_pending(true))
return;
regs.fp_exception = false;
ad -= frame_size;
}
} else { /* 68881/68882 */
- uae_u32 biu_flags = 0x7000ffff;
+ uae_u32 biu_flags = 0x540effff;
int frame_size_real = currprefs.fpu_model == 68882 ? 0x3c : 0x1c;
uae_u32 frame_id = regs.fpu_state == 0 ? ((frame_size_real - 4) << 16) : (fpu_version << 24) | ((frame_size_real - 4) << 16);
- if (regs.fpu_state) { // not in null state
- biu_flags |= regs.fp_exp_pend ? 0x00000000 : 0x08000000;
- regs.fp_exp_pend = 0;
+ regs.fp_exp_pend = 0;
+ if (regs.fpu_exp_state) {
+ biu_flags |= 0x20000000;
+ } else {
+ biu_flags |= 0x08000000;
}
if (currprefs.mmu_model) {
i++;
ad -= 4;
if (mmu030_state[0] == i) {
- x_put_long (ad, fsave_data.eo[0]); // exceptional operand lo
+ x_put_long (ad, fsave_data.eo[2]); // exceptional operand lo
mmu030_state[0]++;
}
i++;
i++;
ad -= 4;
if (mmu030_state[0] == i) {
- x_put_long (ad, fsave_data.eo[2]); // exceptional operand hi
+ x_put_long (ad, fsave_data.eo[0]); // exceptional operand hi
mmu030_state[0]++;
}
i++;
}
ad -= 4;
if (mmu030_state[0] == i) {
- x_put_long(ad, 0x00000000); // command/condition register
+ x_put_long(ad, fsave_data.ccr); // command/condition register
mmu030_state[0]++;
}
i++;
i++;
if (regs.fpu_state != 0) { // idle frame
if(mmu030_state[0] == i) {
- x_put_long(ad, 0x00000000); // command/condition register
+ x_put_long(ad, fsave_data.ccr); // command/condition register
mmu030_state[0]++;
}
ad += 4;
}
}
if (mmu030_state[0] == i) {
- x_put_long (ad, fsave_data.eo[2]); // exceptional operand lo
+ x_put_long (ad, fsave_data.eo[0]); // exceptional operand lo
mmu030_state[0]++;
}
ad += 4;
ad += 4;
i++;
if (mmu030_state[0] == i) {
- x_put_long (ad, fsave_data.eo[0]); // exceptional operand hi
+ x_put_long (ad, fsave_data.eo[2]); // exceptional operand hi
mmu030_state[0]++;
}
ad += 4;
ad -= 4;
x_put_long(ad, 0x00000000); // operand register
ad -= 4;
- x_put_long(ad, fsave_data.eo[0]); // exceptional operand lo
+ x_put_long(ad, fsave_data.eo[2]); // exceptional operand lo
ad -= 4;
x_put_long(ad, fsave_data.eo[1]); // exceptional operand mid
ad -= 4;
- x_put_long(ad, fsave_data.eo[2]); // exceptional operand hi
+ x_put_long(ad, fsave_data.eo[0]); // exceptional operand hi
if (currprefs.fpu_model == 68882) {
for (i = 0; i < 32; i += 4) {
ad -= 4;
}
}
ad -= 4;
- x_put_long(ad, 0x00000000); // command/condition register
+ x_put_long(ad, fsave_data.ccr); // command/condition register
}
ad -= 4;
x_put_long (ad, frame_id); // frame id
x_put_long(ad, frame_id); // frame id
ad += 4;
if (regs.fpu_state != 0) { // idle frame
- x_put_long(ad, 0x00000000); // command/condition register
+ x_put_long(ad, fsave_data.ccr); // command/condition register
ad += 4;
if(currprefs.fpu_model == 68882) {
for(i = 0; i < 32; i += 4) {
ad += 4;
}
}
- x_put_long(ad, fsave_data.eo[2]); // exceptional operand hi
+ x_put_long(ad, fsave_data.eo[0]); // exceptional operand hi
ad += 4;
x_put_long(ad, fsave_data.eo[1]); // exceptional operand mid
ad += 4;
- x_put_long(ad, fsave_data.eo[0]); // exceptional operand lo
+ x_put_long(ad, fsave_data.eo[2]); // exceptional operand lo
ad += 4;
x_put_long(ad, 0x00000000); // operand register
ad += 4;
ad += 4;
}
if ((biu_flags & 0x08000000) == 0x00000000) {
+ regs.fpu_exp_state = 2;
regs.fp_exp_pend = fpsr_get_vector(regs.fpsr & regs.fpcr & 0xff00);
}
} else { // null frame
break;
case 0x24: /* FSGLDIV */
fpp_sgldiv(dst, src);
+ fpsr_set_result(dst);
if (fpsr_make_status())
return false;
- fpsr_set_result(dst);
return true;
case 0x25: /* FREM */
fpp_rem(dst, src, &q, &s);
break;
case 0x27: /* FSGLMUL */
fpp_sglmul(dst, src);
+ fpsr_set_result(dst);
if (fpsr_make_status())
return false;
- fpsr_set_result(dst);
return true;
case 0x28: /* FSUB */
case 0x68: /* FSSUB */
case 0x38: /* FCMP */
{
fpp_cmp(dst, src);
+ fpsr_set_result(dst);
if (fpsr_make_status())
return false;
- fpsr_set_result(dst);
return false;
}
case 0x3a: /* FTST */
{
fpp_tst(dst, src);
+ fpsr_set_result(dst);
if (fpsr_make_status())
return false;
- fpsr_set_result(dst);
return false;
}
default:
fpp_round_double(dst);
}
+ fpsr_set_result(dst);
+
if (fpsr_make_status())
return false;
- fpsr_set_result(dst);
return true;
}
switch ((extra >> 13) & 0x7)
{
case 3:
- if (fp_arithmetic_exception(true))
+ if (fp_exception_pending(true))
return;
regs.fpiar = pc;
return;
}
fpsr_make_status();
- fpsr_check_exception(0, &src, opcode, extra, ad);
- fp_arithmetic_exception(false); // post/mid instruction
+ fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
+ fp_exception_pending(false); // post/mid instruction
return;
case 4:
case 0:
case 2: /* Extremely common */
- if (fp_arithmetic_exception(true))
+ if (fp_exception_pending(true))
return;
regs.fpiar = pc;
fpsr_clear_status();
fpu_get_constant(®s.fp[reg], extra);
fpsr_make_status();
- fpsr_check_exception(0, &src, opcode, extra, ad);
+ fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
return;
}
v = get_fp_value (opcode, extra, &src, pc, &ad);
if (v <= 0) {
- if (v == 0) {
+ if (v == 0)
fpu_noinst (opcode, pc);
- return;
- }
- fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg);
return;
}
- // get_fp_value() checked this, but only if EA was nonzero (non-register)
+ dst = regs.fp[reg];
+
+ if (fp_is_dyadic(extra))
+ normalize_or_fault_if_no_denormal_support_dst(opcode, extra, ad, pc, &dst, &src);
+
+ // check for 680x0 unimplemented instruction
if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg))
return;
- dst = regs.fp[reg];
-
- if((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38) { // dyadic operation
- if (normalize_or_fault_if_no_denormal_support_dst(opcode, extra, ad, pc, &dst, &src))
- return;
- }
+ // unimplemented datatype was checked in get_fp_value
+ if (regs.fp_unimp_pend)
+ return;
v = arithmetic(&src, &dst, extra);
if (v)
regs.fp[reg] = dst;
- fpsr_check_exception(0, &src, opcode, extra, ad);
+ fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
return;
default:
break;
*----------------------------------------------------------------------------*/
#include "softfloat-macros.h"
+/*----------------------------------------------------------------------------
+ | Variables for storing sign, exponent and significand of internal extended
+ | double-precision floating-point value for external use.
+ *----------------------------------------------------------------------------*/
+flag floatx80_internal_sign = 0;
+uint32_t floatx80_internal_exp = 0;
+uint64_t floatx80_internal_sig0 = 0;
+uint64_t floatx80_internal_sig1 = 0;
+
+/*----------------------------------------------------------------------------
+ | Function for storing sign, exponent and significand of extended
+ | double-precision floating-point intermediate result for external use.
+ *----------------------------------------------------------------------------*/
+static void saveFloatx80Internal( flag zSign, uint32_t zExp, uint64_t zSig0, uint64_t zSig1 )
+{
+ floatx80_internal_sign = zSign;
+ floatx80_internal_exp = zExp;
+ floatx80_internal_sig0 = zSig0;
+ floatx80_internal_sig1 = zSig1;
+}
+
+static void saveFloat64Internal( flag zSign, uint16_t zExp, uint64_t zSig, float_status *status )
+{
+ floatx80 z = roundAndPackFloatx80( 64, zSign, 0x3FFF, zSig<<1, 0, status );
+
+ floatx80_internal_sign = zSign;
+ floatx80_internal_exp = zExp + 0x3C01;
+ floatx80_internal_sig0 = extractFloatx80Frac( z );
+ floatx80_internal_sig1 = 0;
+}
+
+static void saveFloat32Internal( flag zSign, uint16_t zExp, uint32_t zSig, float_status *status )
+{
+ floatx80 z = roundAndPackFloatx80( 32, zSign, 0x3FFF, ( (uint64_t) zSig )<<33, 0, status );
+
+ floatx80_internal_sign = zSign;
+ floatx80_internal_exp = zExp + 0x3F81;
+ floatx80_internal_sig0 = extractFloatx80Frac( z );
+ floatx80_internal_sig1 = 0;
+}
+
/*----------------------------------------------------------------------------
| Functions and definitions to determine: (1) whether tininess for underflow
| is detected before or after rounding by default, (2) what (if anything)
) {
#ifdef SOFTFLOAT_68K
float_raise( float_flag_overflow, status );
+ saveFloat32Internal( zSign, zExp, zSig, status );
if ( roundBits ) float_raise( float_flag_inexact, status );
#else
float_raise(float_flag_overflow | float_flag_inexact, status);
== float_tininess_before_rounding)
|| ( zExp < -1 )
|| ( zSig + roundIncrement < 0x80000000 );
+#ifdef SOFTFLOAT_68K
+ if ( isTiny ) {
+ float_raise( float_flag_underflow, status );
+ saveFloat32Internal( zSign, zExp, zSig, status );
+ }
+#endif
shift32RightJamming( zSig, - zExp, &zSig );
zExp = 0;
roundBits = zSig & 0x7F;
-#ifdef SOFTFLOAT_68K
- if ( isTiny ) float_raise( float_flag_underflow, status );
-#else
- if (isTiny && roundBits) {
+#ifndef SOFTFLOAT_68K
+ if (isTiny && roundBits)
float_raise(float_flag_underflow, status);
- }
#endif
}
}
) {
#ifdef SOFTFLOAT_68K
float_raise( float_flag_overflow, status );
+ saveFloat64Internal( zSign, zExp, zSig, status );
if ( roundBits ) float_raise( float_flag_inexact, status );
#else
float_raise(float_flag_overflow | float_flag_inexact, status);
== float_tininess_before_rounding)
|| ( zExp < -1 )
|| ( zSig + roundIncrement < LIT64( 0x8000000000000000 ) );
+#ifdef SOFTFLOAT_68K
+ if ( isTiny ) {
+ float_raise( float_flag_underflow, status );
+ saveFloat64Internal( zSign, zExp, zSig, status );
+ }
+#endif
shift64RightJamming( zSig, - zExp, &zSig );
zExp = 0;
roundBits = zSig & 0x3FF;
-#ifdef SOFTFLOAT_68K
- if ( isTiny ) float_raise( float_flag_underflow, status );
-#else
- if (isTiny && roundBits) {
+#ifndef SOFTFLOAT_68K
+ if (isTiny && roundBits)
float_raise(float_flag_underflow, status);
- }
#endif
}
}
#endif
|| ( zSig0 <= zSig0 + roundIncrement );
#ifdef SOFTFLOAT_68K
+ if ( isTiny ) {
+ float_raise( float_flag_underflow, status );
+ saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+ }
shift64RightJamming( zSig0, -zExp, &zSig0 );
#else
shift64RightJamming( zSig0, 1 - zExp, &zSig0 );
float_raise(float_flag_overflow | float_flag_inexact, status);
#else
float_raise( float_flag_overflow, status );
+ saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
if ( ( zSig0 & roundMask ) || zSig1 ) float_raise( float_flag_inexact, status );
#endif
if ( ( roundingMode == float_round_to_zero )
|| ! increment
|| ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) );
#ifdef SOFTFLOAT_68K
+ if ( isTiny ) {
+ float_raise( float_flag_underflow, status );
+ saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+ }
shift64ExtraRightJamming( zSig0, zSig1, -zExp, &zSig0, &zSig1 );
#else
shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 );
#endif
zExp = 0;
-#ifdef SOFTFLOAT_68K
- if ( isTiny ) float_raise( float_flag_underflow, status );
-#else
- if (isTiny && zSig1) {
- float_raise(float_flag_underflow, status);
- }
+#ifndef SOFTFLOAT_68K
+ if ( isTiny && zSig1 ) float_raise( float_flag_underflow, status );
#endif
- if (zSig1) {
- status->float_exception_flags |= float_flag_inexact;
- }
+ if (zSig1) float_raise(float_flag_inexact, status);
switch (roundingMode) {
case float_round_nearest_even:
case float_round_ties_away:
|| ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
) {
float_raise( float_flag_overflow, status );
+ saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
if ( zSig0 & roundMask ) float_raise( float_flag_inexact, status );
if ( ( roundingMode == float_round_to_zero )
|| ( zSign && ( roundingMode == float_round_up ) )
( status->float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < -1 )
|| ( zSig0 <= zSig0 + roundIncrement );
+ if ( isTiny ) {
+ float_raise( float_flag_underflow, status );
+ saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+ }
shift64RightJamming( zSig0, -zExp, &zSig0 );
zExp = 0;
roundBits = zSig0 & roundMask;
- if ( isTiny ) float_raise( float_flag_underflow, status );
if ( roundBits ) status->float_exception_flags |= float_flag_inexact;
zSig0 += roundIncrement;
if ( roundNearestEven && ( roundBits == roundIncrement ) ) {
}
return packFloat32( aSign, 0xFF, 0 );
}
+#ifdef SOFTFLOAT_68K
+ if ( aExp == 0 ) {
+ if ( aSig == 0) return packFloat32( aSign, 0, 0 );
+ normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+ }
+ shift64RightJamming( aSig, 33, &aSig );
+ aExp -= 0x3F81;
+#else
shift64RightJamming( aSig, 33, &aSig );
if ( aExp || aSig ) aExp -= 0x3F81;
+#endif
return roundAndPackFloat32(aSign, aExp, aSig, status);
}
}
return packFloat64( aSign, 0x7FF, 0 );
}
+#ifdef SOFTFLOAT_68K
+ if ( aExp == 0 ) {
+ if ( aSig == 0) return packFloat64( aSign, 0, 0 );
+ normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+ }
+ shift64RightJamming( aSig, 1, &zSig );
+ aExp -= 0x3C01;
+#else
shift64RightJamming( aSig, 1, &zSig );
if ( aExp || aSig ) aExp -= 0x3C01;
+#endif
return roundAndPackFloat64(aSign, aExp, zSig, status);
}