aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/nwfpe/fpa11_cpdo.c
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@rpsys.net>2005-08-03 14:49:17 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-08-03 14:49:17 -0400
commitf148af2593ef76ac705d1cc6abe48f455c9912cc (patch)
treecd1e0b0959624234ca3489df8888434ffea5050e /arch/arm/nwfpe/fpa11_cpdo.c
parent1fcf844861eb08ee05e05dba13b5436f2f2e29ed (diff)
[PATCH] ARM: 2837/2: Re: ARM: Make NWFPE preempt safe
Patch from Richard Purdie NWFPE used global variables which meant it wasn't safe for use with preemptive kernels. This patch removes them and communicates the information between functions in a preempt safe manner. Generation of some exceptions was broken and this has also been corrected. Tests with glibc's maths test suite show no change in the results before/after this patch. Signed-off-by: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/nwfpe/fpa11_cpdo.c')
-rw-r--r--arch/arm/nwfpe/fpa11_cpdo.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/arch/arm/nwfpe/fpa11_cpdo.c b/arch/arm/nwfpe/fpa11_cpdo.c
index 1bea67437b6f..4a31dfd94068 100644
--- a/arch/arm/nwfpe/fpa11_cpdo.c
+++ b/arch/arm/nwfpe/fpa11_cpdo.c
@@ -24,15 +24,16 @@
24#include "fpa11.h" 24#include "fpa11.h"
25#include "fpopcode.h" 25#include "fpopcode.h"
26 26
27unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd); 27unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
28unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd); 28unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
29unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd); 29unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
30 30
31unsigned int EmulateCPDO(const unsigned int opcode) 31unsigned int EmulateCPDO(const unsigned int opcode)
32{ 32{
33 FPA11 *fpa11 = GET_FPA11(); 33 FPA11 *fpa11 = GET_FPA11();
34 FPREG *rFd; 34 FPREG *rFd;
35 unsigned int nType, nDest, nRc; 35 unsigned int nType, nDest, nRc;
36 struct roundingData roundData;
36 37
37 /* Get the destination size. If not valid let Linux perform 38 /* Get the destination size. If not valid let Linux perform
38 an invalid instruction trap. */ 39 an invalid instruction trap. */
@@ -40,7 +41,9 @@ unsigned int EmulateCPDO(const unsigned int opcode)
40 if (typeNone == nDest) 41 if (typeNone == nDest)
41 return 0; 42 return 0;
42 43
43 SetRoundingMode(opcode); 44 roundData.mode = SetRoundingMode(opcode);
45 roundData.precision = SetRoundingPrecision(opcode);
46 roundData.exception = 0;
44 47
45 /* Compare the size of the operands in Fn and Fm. 48 /* Compare the size of the operands in Fn and Fm.
46 Choose the largest size and perform operations in that size, 49 Choose the largest size and perform operations in that size,
@@ -63,14 +66,14 @@ unsigned int EmulateCPDO(const unsigned int opcode)
63 66
64 switch (nType) { 67 switch (nType) {
65 case typeSingle: 68 case typeSingle:
66 nRc = SingleCPDO(opcode, rFd); 69 nRc = SingleCPDO(&roundData, opcode, rFd);
67 break; 70 break;
68 case typeDouble: 71 case typeDouble:
69 nRc = DoubleCPDO(opcode, rFd); 72 nRc = DoubleCPDO(&roundData, opcode, rFd);
70 break; 73 break;
71#ifdef CONFIG_FPE_NWFPE_XP 74#ifdef CONFIG_FPE_NWFPE_XP
72 case typeExtended: 75 case typeExtended:
73 nRc = ExtendedCPDO(opcode, rFd); 76 nRc = ExtendedCPDO(&roundData, opcode, rFd);
74 break; 77 break;
75#endif 78#endif
76 default: 79 default:
@@ -93,9 +96,9 @@ unsigned int EmulateCPDO(const unsigned int opcode)
93 case typeSingle: 96 case typeSingle:
94 { 97 {
95 if (typeDouble == nType) 98 if (typeDouble == nType)
96 rFd->fSingle = float64_to_float32(rFd->fDouble); 99 rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
97 else 100 else
98 rFd->fSingle = floatx80_to_float32(rFd->fExtended); 101 rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
99 } 102 }
100 break; 103 break;
101 104
@@ -104,7 +107,7 @@ unsigned int EmulateCPDO(const unsigned int opcode)
104 if (typeSingle == nType) 107 if (typeSingle == nType)
105 rFd->fDouble = float32_to_float64(rFd->fSingle); 108 rFd->fDouble = float32_to_float64(rFd->fSingle);
106 else 109 else
107 rFd->fDouble = floatx80_to_float64(rFd->fExtended); 110 rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
108 } 111 }
109 break; 112 break;
110 113
@@ -121,12 +124,15 @@ unsigned int EmulateCPDO(const unsigned int opcode)
121#else 124#else
122 if (nDest != nType) { 125 if (nDest != nType) {
123 if (nDest == typeSingle) 126 if (nDest == typeSingle)
124 rFd->fSingle = float64_to_float32(rFd->fDouble); 127 rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
125 else 128 else
126 rFd->fDouble = float32_to_float64(rFd->fSingle); 129 rFd->fDouble = float32_to_float64(rFd->fSingle);
127 } 130 }
128#endif 131#endif
129 } 132 }
130 133
134 if (roundData.exception)
135 float_raise(roundData.exception);
136
131 return nRc; 137 return nRc;
132} 138}