uae_u32 exception;
// Any exception status bit and matching exception enable bits set?
exception = regs.fpsr & regs.fpcr & 0xff00;
- // Add 68040/68060 nonmaskable exceptions
- if (currprefs.cpu_model >= 68040 && currprefs.fpu_model)
+ // Add 68040/68060 nonmaskable exceptions. Only if no unimplemented instruction emulation.
+ if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL | mask);
+ }
if (exception) {
regs.fp_exp_pend = fpsr_get_vector(exception);
// return exceptions that interrupt calculation
exception = regs.fpsr & regs.fpcr & (FPSR_SNAN | FPSR_OPERR | FPSR_DZ);
- if (currprefs.cpu_model >= 68040 && currprefs.fpu_model)
+ if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented)
exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL);
return exception;
}
if (warned > 0) {
write_log (_T("FPU unimplemented datatype (%s): OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"),
- packed ? "packed" : "denormal", opcode, extra,
+ packed ? _T("packed") : _T("denormal"), opcode, extra,
packed ? fsave_data.fpt[2] : fsave_data.et[0], fsave_data.et[1], fsave_data.et[2], ea, oldpc);
#if EXCEPTION_FPP == 0
warned--;
return false;
}
-#if 0
-// 68040/060 automatically converts infinity
-static void check_and_fix_infinity(fpdata *value)
-{
- if (fpp_fix_infinity && (currprefs.fpu_model == 68040 || currprefs.fpu_model == 68060)) {
- if (fpp_is_infinity(value)) {
- fpp_fix_infinity(value);
- }
- }
-}
-#endif
-
static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
{
int size, mode, reg;
if (fault_if_no_fpu (opcode, extra, 0, oldpc))
return -1;
*src = regs.fp[(extra >> 10) & 7];
-#if 0
- check_and_fix_infinity(src);
-#endif
normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
return 1;
}
v = fp_arithmetic(&src, &dst, extra);
-#if 0
- check_and_fix_infinity(&dst);
-#endif
-
fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
if (v)
fpp_from_exten_fmovem(®s.fp[i], &temp_ext[i][0], &temp_ext[i][1], &temp_ext[i][2]);
}
if (currprefs.fpu_mode > 0) {
- fp_init_softfloat();
+ fp_init_softfloat(currprefs.fpu_model);
#ifdef MSVC_LONG_DOUBLE
use_long_double = false;
} else if (currprefs.fpu_mode < 0) {
void fpu_reset (void)
{
if (currprefs.fpu_mode > 0) {
- fp_init_softfloat();
+ fp_init_softfloat(currprefs.fpu_model);
#ifdef MSVC_LONG_DOUBLE
use_long_double = false;
} else if (currprefs.fpu_mode < 0) {
flag aSign;
int32_t aExp;
uint64_t lastBitMask, roundBitsMask;
- floatx80 z;
+ int8_t roundingMode;
+ floatx80 z;
- if (floatx80_invalid_encoding(a)) {
- float_raise(float_flag_invalid, status);
- return floatx80_default_nan(status);
- }
+ roundingMode = status->float_rounding_mode;
+ aSign = extractFloatx80Sign(a);
aExp = extractFloatx80Exp( a );
if ( 0x403E <= aExp ) {
- if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
- return propagateFloatx80NaNOneArg(a, status);
+ if ( aExp == 0x7FFF ) {
+ if ((uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+ return propagateFloatx80NaNOneArg(a, status);
+ return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
}
return a;
}
return a;
}
status->float_exception_flags |= float_flag_inexact;
- aSign = extractFloatx80Sign( a );
switch (status->float_rounding_mode) {
case float_round_nearest_even:
if ( ( aExp == 0x3FFE ) && (uint64_t) ( extractFloatx80Frac( a )<<1 )
uint64_t lastBitMask, roundBitsMask;
floatx80 z;
- aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign(a);
+ aExp = extractFloatx80Exp( a );
if ( 0x403E <= aExp ) {
- if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
- return propagateFloatx80NaNOneArg( a, status );
+ if ( aExp == 0x7FFF ) {
+ if ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+ return propagateFloatx80NaNOneArg( a, status );
+ return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
}
return a;
}
return a;
}
status->float_exception_flags |= float_flag_inexact;
- aSign = extractFloatx80Sign( a );
return packFloatx80( aSign, 0, 0 );
}
lastBitMask = 1;
expDiff = aExp - bExp;
if ( 0 < expDiff ) {
if ( aExp == 0x7FFF ) {
- if ((uint64_t)(aSig << 1)) {
+ if ((uint64_t)(aSig << 1))
return propagateFloatx80NaN(a, b, status);
- }
- return a;
+ return inf_clear_intbit(status) ? packFloatx80(extractFloatx80Sign(a), aExp, 0) : a;
}
#ifndef SOFTFLOAT_68K
if ( bExp == 0 ) --expDiff;
}
else if ( expDiff < 0 ) {
if ( bExp == 0x7FFF ) {
- if ((uint64_t)(bSig << 1)) {
+ if ((uint64_t)(bSig << 1))
return propagateFloatx80NaN(a, b, status);
- }
- return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+ if (inf_clear_intbit(status)) bSig = 0;
+ return packFloatx80( zSign, bExp, bSig );
}
#ifndef SOFTFLOAT_68K
if ( aExp == 0 ) ++expDiff;
if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) {
return propagateFloatx80NaN(a, b, status);
}
- return a;
+ if (inf_clear_intbit(status)) return packFloatx80(extractFloatx80Sign(a), aExp, 0);
+ return faddsub_swap_inf(status) ? b : a;
}
zSig1 = 0;
zSig0 = aSig + bSig;
return packFloatx80(status->float_rounding_mode == float_round_down, 0, 0);
bExpBigger:
if ( bExp == 0x7FFF ) {
- if ((uint64_t)(bSig << 1)) {
- return propagateFloatx80NaN(a, b, status);
- }
- return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
- }
+ if ((uint64_t)(bSig << 1)) return propagateFloatx80NaN(a, b, status);
+ if (inf_clear_intbit(status)) bSig = 0;
+ return packFloatx80(zSign ^ 1, bExp, bSig);
+ }
#ifndef SOFTFLOAT_68K
if ( aExp == 0 ) ++expDiff;
#endif
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0x7FFF ) {
- if ((uint64_t)(aSig << 1)) {
- return propagateFloatx80NaN(a, b, status);
- }
- return a;
- }
+ if ((uint64_t)(aSig << 1)) return propagateFloatx80NaN(a, b, status);
+ return inf_clear_intbit(status) ? packFloatx80(extractFloatx80Sign(a), aExp, 0) : a;
+ }
#ifndef SOFTFLOAT_68K
if ( bExp == 0 ) --expDiff;
#endif
return propagateFloatx80NaN(a, b, status);
}
if ( ( bExp | bSig ) == 0 ) goto invalid;
- return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
- }
+ if (inf_clear_intbit(status)) aSig = 0;
+ return packFloatx80(zSign, aExp, aSig);
+ }
if ( bExp == 0x7FFF ) {
if ((uint64_t)(bSig << 1)) {
return propagateFloatx80NaN(a, b, status);
float_raise(float_flag_invalid, status);
return floatx80_default_nan(status);
}
- return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
- }
+ if (inf_clear_intbit(status)) bSig = 0;
+ return packFloatx80(zSign, bExp, bSig);
+ }
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
flag aSign, bSign, zSign;
int32_t aExp, bExp, zExp;
uint64_t aSig, bSig, zSig0, zSig1;
- floatx80 z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
return propagateFloatx80NaN( a, b, status );
}
if ( ( bExp | bSig ) == 0 ) goto invalid;
- return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+ if (inf_clear_intbit(status)) aSig = 0;
+ return packFloatx80(zSign, aExp, aSig);
}
if ( bExp == 0x7FFF ) {
if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
if ( ( aExp | aSig ) == 0 ) {
invalid:
float_raise( float_flag_invalid, status );
- z.low = floatx80_default_nan_low;
- z.high = floatx80_default_nan_high;
- return z;
+ return floatx80_default_nan(status);
}
- return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+ if (inf_clear_intbit(status)) bSig = 0;
+ return packFloatx80(zSign, bExp, bSig);
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
}
goto invalid;
}
- return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
- }
+ if (inf_clear_intbit(status)) aSig = 0;
+ return packFloatx80(zSign, aExp, aSig);
+ }
if ( bExp == 0x7FFF ) {
if ((uint64_t)(bSig << 1)) {
return propagateFloatx80NaN(a, b, status);
int32_t aExp, bExp, zExp;
uint64_t aSig, bSig, zSig0, zSig1;
uint64_t rem0, rem1, rem2, term0, term1, term2;
- floatx80 z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
goto invalid;
}
- return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+ if (inf_clear_intbit(status)) aSig = 0;
+ return packFloatx80(zSign, aExp, aSig);
}
if ( bExp == 0x7FFF ) {
if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
if ( ( aExp | aSig ) == 0 ) {
invalid:
float_raise( float_flag_invalid, status );
- z.low = floatx80_default_nan_low;
- z.high = floatx80_default_nan_high;
- return z;
+ return floatx80_default_nan(status);
}
float_raise( float_flag_divbyzero, status );
return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
int32_t aExp, bExp, expDiff;
uint64_t aSig0, aSig1, bSig;
uint64_t qTemp, term0, term1, alternateASig0, alternateASig1;
- floatx80 z;
aSig0 = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
if ( bSig == 0 ) {
invalid:
float_raise( float_flag_invalid, status );
- z.low = floatx80_default_nan_low;
- z.high = floatx80_default_nan_high;
- return z;
+ return floatx80_default_nan(status);
}
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
}
int32_t aExp, bExp, expDiff;
uint64_t aSig0, aSig1, bSig;
uint64_t qTemp, term0, term1;
- floatx80 z;
aSig0 = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
if ( bSig == 0 ) {
invalid:
float_raise( float_flag_invalid, status );
- z.low = floatx80_default_nan_low;
- z.high = floatx80_default_nan_high;
- return z;
- }
+ return floatx80_default_nan(status);
+ }
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FFF ) {
- if ((uint64_t)(aSig0 << 1)) {
+ if ((uint64_t)(aSig0 << 1))
return propagateFloatx80NaNOneArg(a, status);
- }
- if ( ! aSign ) return a;
+ if (!aSign) return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
goto invalid;
}
if ( aSign ) {
if ( aExp == 0x7FFF ) {
if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaNOneArg( a, status );
float_raise( float_flag_invalid, status );
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
if ( aExp == 0 ) {
if ( aExp == 0x7FFF ) {
if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaNOneArg( a, status );
float_raise( float_flag_invalid, status );
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
if ( aExp == 0 ) {
return propagateFloatx80NaN( a, b, status );
}
float_raise( float_flag_invalid, status );
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
if ( aExp == 0x7FFF ) {
if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
- return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return a;
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( aSign, 0, 0);
if ( aExp == 0x7FFF ) {
if ( (uint64_t) ( aSig<<1 ) )
return propagateFloatx80NaNOneArg( a, status );
- return packFloatx80( 0, 0x7FFF, floatx80_default_infinity_low );
- }
+ if (inf_clear_intbit(status)) aSig = 0;
+ return packFloatx80(0, aExp, aSig);
+ }
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( 0, 0, 0 );
if ( aExp == 0x7FFF ) {
if ( (uint64_t) ( aSig<<1 ) )
return propagateFloatx80NaNOneArg( a, status );
- return packFloatx80 ( !aSign, 0x7FFF, floatx80_default_infinity_low );
- }
+ if (inf_clear_intbit(status)) aSig = 0;
+ return packFloatx80(!aSign, aExp, aSig);
+ }
aSign = !aSign;
if ( ( aExp == 0x7FFF && (uint64_t) ( aSig<<1 ) ) ||
( bExp == 0x7FFF && (uint64_t) ( bSig<<1 ) ) ) {
// 68040 FCMP -NaN return N flag set
- if (status->fpu_model == 68040)
- return propagateFloatx80NaN( packFloatx80( aSign, aExp, aSig ),
- packFloatx80( bSign, bExp, bSig ), status );
+ if (fcmp_signed_nan(status))
+ return propagateFloatx80NaN(a, b, status );
return propagateFloatx80NaN(packFloatx80(0, aExp, aSig),
packFloatx80(0, bExp, bSig), status);
}
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FFF ) {
- if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaNOneArg( a, status );
- return a;
+ if ((uint64_t)(aSig << 1)) return propagateFloatx80NaNOneArg(a, status);
+ return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return a;
}
} else { // |X| > 1
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
} // |X| < 1
return floatx80_move(a, status);
} else { // |X| > 1
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
} // |X| < 1
return packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
} else { // |X| > 1
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
} // |X| < 1
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return packFloatx80(0, aExp, aSig);
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign) return packFloatx80(0, 0, 0);
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign) return packFloatx80(aSign, one_exp, one_sig);
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign == 0)
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0 && aSig == 0) {
if (aSign) {
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
SET_PREC;
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign == 0)
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0) {
if (aSign) {
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
SET_PREC;
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign == 0)
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
adjk = 0;
if (aSign) {
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
SET_PREC;
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign) {
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0 && aSig == 0) {
return packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
}
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
if (aExp < 0x3f99 || (aExp == 0x3f99 && aSig == one_sig)) { // <= min threshold
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
- return packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
float_raise(float_flag_invalid, status);
- a.low = floatx80_default_nan_low;
- a.high = floatx80_default_nan_high;
- return a;
+ return floatx80_default_nan(status);
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign) return packFloatx80(0, 0, 0);
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0 && aSig == 0) {
if (aExp == 0x7FFF) {
if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
if (aSign) return packFloatx80(0, 0, 0);
- return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+ return a;
}
if (aExp == 0 && aSig == 0) {