diff options
| author | 2016-05-16 11:11:16 +0200 | |
|---|---|---|
| committer | 2016-05-18 15:24:42 +0200 | |
| commit | 693cca8f1f069ddd88a3f47f94fae5e53712ded4 (patch) | |
| tree | 0c6bad361aae029c3c1c404368ac8c0bdab3f9da /src | |
| parent | Fix exception propagation for VFP double precision (diff) | |
| download | yuzu-693cca8f1f069ddd88a3f47f94fae5e53712ded4.tar.gz yuzu-693cca8f1f069ddd88a3f47f94fae5e53712ded4.tar.xz yuzu-693cca8f1f069ddd88a3f47f94fae5e53712ded4.zip | |
Fix exception propagation for VFP single precision
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/arm/skyeye_common/vfp/vfp_helper.h | 8 | ||||
| -rw-r--r-- | src/core/arm/skyeye_common/vfp/vfpsingle.cpp | 63 |
2 files changed, 38 insertions, 33 deletions
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index c1cc4fd7e..c66a3fad4 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h | |||
| @@ -271,8 +271,9 @@ inline int vfp_single_type(const vfp_single* s) | |||
| 271 | // Unpack a single-precision float. Note that this returns the magnitude | 271 | // Unpack a single-precision float. Note that this returns the magnitude |
| 272 | // of the single-precision float mantissa with the 1. if necessary, | 272 | // of the single-precision float mantissa with the 1. if necessary, |
| 273 | // aligned to bit 30. | 273 | // aligned to bit 30. |
| 274 | inline void vfp_single_unpack(vfp_single* s, s32 val, u32* fpscr) | 274 | inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr) |
| 275 | { | 275 | { |
| 276 | u32 exceptions = 0; | ||
| 276 | s->sign = vfp_single_packed_sign(val) >> 16, | 277 | s->sign = vfp_single_packed_sign(val) >> 16, |
| 277 | s->exponent = vfp_single_packed_exponent(val); | 278 | s->exponent = vfp_single_packed_exponent(val); |
| 278 | 279 | ||
| @@ -283,12 +284,13 @@ inline void vfp_single_unpack(vfp_single* s, s32 val, u32* fpscr) | |||
| 283 | 284 | ||
| 284 | // If flush-to-zero mode is enabled, turn the denormal into zero. | 285 | // If flush-to-zero mode is enabled, turn the denormal into zero. |
| 285 | // On a VFPv2 architecture, the sign of the zero is always positive. | 286 | // On a VFPv2 architecture, the sign of the zero is always positive. |
| 286 | if ((*fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) { | 287 | if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) { |
| 287 | s->sign = 0; | 288 | s->sign = 0; |
| 288 | s->exponent = 0; | 289 | s->exponent = 0; |
| 289 | s->significand = 0; | 290 | s->significand = 0; |
| 290 | *fpscr |= FPSCR_IDC; | 291 | exceptions |= FPSCR_IDC; |
| 291 | } | 292 | } |
| 293 | return exceptions; | ||
| 292 | } | 294 | } |
| 293 | 295 | ||
| 294 | // Re-pack a single-precision float. This assumes that the float is | 296 | // Re-pack a single-precision float. This assumes that the float is |
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index e47ad2760..5fb6b51ec 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp | |||
| @@ -334,8 +334,9 @@ static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 f | |||
| 334 | { | 334 | { |
| 335 | struct vfp_single vsm, vsd, *vsp; | 335 | struct vfp_single vsm, vsd, *vsp; |
| 336 | int ret, tm; | 336 | int ret, tm; |
| 337 | u32 exceptions = 0; | ||
| 337 | 338 | ||
| 338 | vfp_single_unpack(&vsm, m, &fpscr); | 339 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 339 | tm = vfp_single_type(&vsm); | 340 | tm = vfp_single_type(&vsm); |
| 340 | if (tm & (VFP_NAN|VFP_INFINITY)) { | 341 | if (tm & (VFP_NAN|VFP_INFINITY)) { |
| 341 | vsp = &vsd; | 342 | vsp = &vsd; |
| @@ -408,7 +409,9 @@ sqrt_invalid: | |||
| 408 | } | 409 | } |
| 409 | vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); | 410 | vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); |
| 410 | 411 | ||
| 411 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); | 412 | exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); |
| 413 | |||
| 414 | return exceptions; | ||
| 412 | } | 415 | } |
| 413 | 416 | ||
| 414 | /* | 417 | /* |
| @@ -503,7 +506,7 @@ static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 f | |||
| 503 | int tm; | 506 | int tm; |
| 504 | u32 exceptions = 0; | 507 | u32 exceptions = 0; |
| 505 | 508 | ||
| 506 | vfp_single_unpack(&vsm, m, &fpscr); | 509 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 507 | 510 | ||
| 508 | tm = vfp_single_type(&vsm); | 511 | tm = vfp_single_type(&vsm); |
| 509 | 512 | ||
| @@ -511,7 +514,7 @@ static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 f | |||
| 511 | * If we have a signalling NaN, signal invalid operation. | 514 | * If we have a signalling NaN, signal invalid operation. |
| 512 | */ | 515 | */ |
| 513 | if (tm == VFP_SNAN) | 516 | if (tm == VFP_SNAN) |
| 514 | exceptions = FPSCR_IOC; | 517 | exceptions |= FPSCR_IOC; |
| 515 | 518 | ||
| 516 | if (tm & VFP_DENORMAL) | 519 | if (tm & VFP_DENORMAL) |
| 517 | vfp_single_normalise_denormal(&vsm); | 520 | vfp_single_normalise_denormal(&vsm); |
| @@ -568,7 +571,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f | |||
| 568 | int rmode = fpscr & FPSCR_RMODE_MASK; | 571 | int rmode = fpscr & FPSCR_RMODE_MASK; |
| 569 | int tm; | 572 | int tm; |
| 570 | 573 | ||
| 571 | vfp_single_unpack(&vsm, m, &fpscr); | 574 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 572 | vfp_single_dump("VSM", &vsm); | 575 | vfp_single_dump("VSM", &vsm); |
| 573 | 576 | ||
| 574 | /* | 577 | /* |
| @@ -583,7 +586,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f | |||
| 583 | 586 | ||
| 584 | if (vsm.exponent >= 127 + 32) { | 587 | if (vsm.exponent >= 127 + 32) { |
| 585 | d = vsm.sign ? 0 : 0xffffffff; | 588 | d = vsm.sign ? 0 : 0xffffffff; |
| 586 | exceptions = FPSCR_IOC; | 589 | exceptions |= FPSCR_IOC; |
| 587 | } else if (vsm.exponent >= 127) { | 590 | } else if (vsm.exponent >= 127) { |
| 588 | int shift = 127 + 31 - vsm.exponent; | 591 | int shift = 127 + 31 - vsm.exponent; |
| 589 | u32 rem, incr = 0; | 592 | u32 rem, incr = 0; |
| @@ -648,7 +651,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f | |||
| 648 | int rmode = fpscr & FPSCR_RMODE_MASK; | 651 | int rmode = fpscr & FPSCR_RMODE_MASK; |
| 649 | int tm; | 652 | int tm; |
| 650 | 653 | ||
| 651 | vfp_single_unpack(&vsm, m, &fpscr); | 654 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 652 | vfp_single_dump("VSM", &vsm); | 655 | vfp_single_dump("VSM", &vsm); |
| 653 | 656 | ||
| 654 | /* | 657 | /* |
| @@ -774,7 +777,7 @@ vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn, | |||
| 774 | /* | 777 | /* |
| 775 | * different signs -> invalid | 778 | * different signs -> invalid |
| 776 | */ | 779 | */ |
| 777 | exceptions = FPSCR_IOC; | 780 | exceptions |= FPSCR_IOC; |
| 778 | vsp = &vfp_single_default_qnan; | 781 | vsp = &vfp_single_default_qnan; |
| 779 | } else { | 782 | } else { |
| 780 | /* | 783 | /* |
| @@ -921,27 +924,27 @@ static u32 | |||
| 921 | vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func) | 924 | vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func) |
| 922 | { | 925 | { |
| 923 | vfp_single vsd, vsp, vsn, vsm; | 926 | vfp_single vsd, vsp, vsn, vsm; |
| 924 | u32 exceptions; | 927 | u32 exceptions = 0; |
| 925 | s32 v; | 928 | s32 v; |
| 926 | 929 | ||
| 927 | v = vfp_get_float(state, sn); | 930 | v = vfp_get_float(state, sn); |
| 928 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, v); | 931 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, v); |
| 929 | vfp_single_unpack(&vsn, v, &fpscr); | 932 | exceptions |= vfp_single_unpack(&vsn, v, fpscr); |
| 930 | if (vsn.exponent == 0 && vsn.significand) | 933 | if (vsn.exponent == 0 && vsn.significand) |
| 931 | vfp_single_normalise_denormal(&vsn); | 934 | vfp_single_normalise_denormal(&vsn); |
| 932 | 935 | ||
| 933 | vfp_single_unpack(&vsm, m, &fpscr); | 936 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 934 | if (vsm.exponent == 0 && vsm.significand) | 937 | if (vsm.exponent == 0 && vsm.significand) |
| 935 | vfp_single_normalise_denormal(&vsm); | 938 | vfp_single_normalise_denormal(&vsm); |
| 936 | 939 | ||
| 937 | exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); | 940 | exceptions |= vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); |
| 938 | 941 | ||
| 939 | if (negate & NEG_MULTIPLY) | 942 | if (negate & NEG_MULTIPLY) |
| 940 | vsp.sign = vfp_sign_negate(vsp.sign); | 943 | vsp.sign = vfp_sign_negate(vsp.sign); |
| 941 | 944 | ||
| 942 | v = vfp_get_float(state, sd); | 945 | v = vfp_get_float(state, sd); |
| 943 | LOG_TRACE(Core_ARM11, "s%u = %08x", sd, v); | 946 | LOG_TRACE(Core_ARM11, "s%u = %08x", sd, v); |
| 944 | vfp_single_unpack(&vsn, v, &fpscr); | 947 | exceptions |= vfp_single_unpack(&vsn, v, fpscr); |
| 945 | if (vsn.exponent == 0 && vsn.significand != 0) | 948 | if (vsn.exponent == 0 && vsn.significand != 0) |
| 946 | vfp_single_normalise_denormal(&vsn); | 949 | vfp_single_normalise_denormal(&vsn); |
| 947 | 950 | ||
| @@ -1000,20 +1003,20 @@ static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr | |||
| 1000 | static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | 1003 | static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) |
| 1001 | { | 1004 | { |
| 1002 | struct vfp_single vsd, vsn, vsm; | 1005 | struct vfp_single vsd, vsn, vsm; |
| 1003 | u32 exceptions; | 1006 | u32 exceptions = 0; |
| 1004 | s32 n = vfp_get_float(state, sn); | 1007 | s32 n = vfp_get_float(state, sn); |
| 1005 | 1008 | ||
| 1006 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); | 1009 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); |
| 1007 | 1010 | ||
| 1008 | vfp_single_unpack(&vsn, n, &fpscr); | 1011 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); |
| 1009 | if (vsn.exponent == 0 && vsn.significand) | 1012 | if (vsn.exponent == 0 && vsn.significand) |
| 1010 | vfp_single_normalise_denormal(&vsn); | 1013 | vfp_single_normalise_denormal(&vsn); |
| 1011 | 1014 | ||
| 1012 | vfp_single_unpack(&vsm, m, &fpscr); | 1015 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 1013 | if (vsm.exponent == 0 && vsm.significand) | 1016 | if (vsm.exponent == 0 && vsm.significand) |
| 1014 | vfp_single_normalise_denormal(&vsm); | 1017 | vfp_single_normalise_denormal(&vsm); |
| 1015 | 1018 | ||
| 1016 | exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | 1019 | exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); |
| 1017 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); | 1020 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); |
| 1018 | } | 1021 | } |
| 1019 | 1022 | ||
| @@ -1023,20 +1026,20 @@ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | |||
| 1023 | static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | 1026 | static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) |
| 1024 | { | 1027 | { |
| 1025 | struct vfp_single vsd, vsn, vsm; | 1028 | struct vfp_single vsd, vsn, vsm; |
| 1026 | u32 exceptions; | 1029 | u32 exceptions = 0; |
| 1027 | s32 n = vfp_get_float(state, sn); | 1030 | s32 n = vfp_get_float(state, sn); |
| 1028 | 1031 | ||
| 1029 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); | 1032 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); |
| 1030 | 1033 | ||
| 1031 | vfp_single_unpack(&vsn, n, &fpscr); | 1034 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); |
| 1032 | if (vsn.exponent == 0 && vsn.significand) | 1035 | if (vsn.exponent == 0 && vsn.significand) |
| 1033 | vfp_single_normalise_denormal(&vsn); | 1036 | vfp_single_normalise_denormal(&vsn); |
| 1034 | 1037 | ||
| 1035 | vfp_single_unpack(&vsm, m, &fpscr); | 1038 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 1036 | if (vsm.exponent == 0 && vsm.significand) | 1039 | if (vsm.exponent == 0 && vsm.significand) |
| 1037 | vfp_single_normalise_denormal(&vsm); | 1040 | vfp_single_normalise_denormal(&vsm); |
| 1038 | 1041 | ||
| 1039 | exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | 1042 | exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); |
| 1040 | vsd.sign = vfp_sign_negate(vsd.sign); | 1043 | vsd.sign = vfp_sign_negate(vsd.sign); |
| 1041 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); | 1044 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); |
| 1042 | } | 1045 | } |
| @@ -1047,7 +1050,7 @@ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr | |||
| 1047 | static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | 1050 | static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) |
| 1048 | { | 1051 | { |
| 1049 | struct vfp_single vsd, vsn, vsm; | 1052 | struct vfp_single vsd, vsn, vsm; |
| 1050 | u32 exceptions; | 1053 | u32 exceptions = 0; |
| 1051 | s32 n = vfp_get_float(state, sn); | 1054 | s32 n = vfp_get_float(state, sn); |
| 1052 | 1055 | ||
| 1053 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); | 1056 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); |
| @@ -1055,15 +1058,15 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | |||
| 1055 | /* | 1058 | /* |
| 1056 | * Unpack and normalise denormals. | 1059 | * Unpack and normalise denormals. |
| 1057 | */ | 1060 | */ |
| 1058 | vfp_single_unpack(&vsn, n, &fpscr); | 1061 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); |
| 1059 | if (vsn.exponent == 0 && vsn.significand) | 1062 | if (vsn.exponent == 0 && vsn.significand) |
| 1060 | vfp_single_normalise_denormal(&vsn); | 1063 | vfp_single_normalise_denormal(&vsn); |
| 1061 | 1064 | ||
| 1062 | vfp_single_unpack(&vsm, m, &fpscr); | 1065 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 1063 | if (vsm.exponent == 0 && vsm.significand) | 1066 | if (vsm.exponent == 0 && vsm.significand) |
| 1064 | vfp_single_normalise_denormal(&vsm); | 1067 | vfp_single_normalise_denormal(&vsm); |
| 1065 | 1068 | ||
| 1066 | exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); | 1069 | exceptions |= vfp_single_add(&vsd, &vsn, &vsm, fpscr); |
| 1067 | 1070 | ||
| 1068 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); | 1071 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); |
| 1069 | } | 1072 | } |
| @@ -1095,8 +1098,8 @@ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | |||
| 1095 | 1098 | ||
| 1096 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); | 1099 | LOG_TRACE(Core_ARM11, "s%u = %08x", sn, n); |
| 1097 | 1100 | ||
| 1098 | vfp_single_unpack(&vsn, n, &fpscr); | 1101 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); |
| 1099 | vfp_single_unpack(&vsm, m, &fpscr); | 1102 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); |
| 1100 | 1103 | ||
| 1101 | vsd.sign = vsn.sign ^ vsm.sign; | 1104 | vsd.sign = vsn.sign ^ vsm.sign; |
| 1102 | 1105 | ||
| @@ -1165,13 +1168,13 @@ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) | |||
| 1165 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); | 1168 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); |
| 1166 | 1169 | ||
| 1167 | vsn_nan: | 1170 | vsn_nan: |
| 1168 | exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); | 1171 | exceptions |= vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); |
| 1169 | pack: | 1172 | pack: |
| 1170 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | 1173 | vfp_put_float(state, vfp_single_pack(&vsd), sd); |
| 1171 | return exceptions; | 1174 | return exceptions; |
| 1172 | 1175 | ||
| 1173 | vsm_nan: | 1176 | vsm_nan: |
| 1174 | exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); | 1177 | exceptions |= vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); |
| 1175 | goto pack; | 1178 | goto pack; |
| 1176 | 1179 | ||
| 1177 | zero: | 1180 | zero: |
| @@ -1180,7 +1183,7 @@ zero: | |||
| 1180 | goto pack; | 1183 | goto pack; |
| 1181 | 1184 | ||
| 1182 | divzero: | 1185 | divzero: |
| 1183 | exceptions = FPSCR_DZC; | 1186 | exceptions |= FPSCR_DZC; |
| 1184 | infinity: | 1187 | infinity: |
| 1185 | vsd.exponent = 255; | 1188 | vsd.exponent = 255; |
| 1186 | vsd.significand = 0; | 1189 | vsd.significand = 0; |