diff options
Diffstat (limited to 'arch/x86/math-emu/reg_divide.c')
-rw-r--r-- | arch/x86/math-emu/reg_divide.c | 301 |
1 files changed, 138 insertions, 163 deletions
diff --git a/arch/x86/math-emu/reg_divide.c b/arch/x86/math-emu/reg_divide.c index 5cee7ff920d9..6827012db341 100644 --- a/arch/x86/math-emu/reg_divide.c +++ b/arch/x86/math-emu/reg_divide.c | |||
@@ -26,182 +26,157 @@ | |||
26 | */ | 26 | */ |
27 | int FPU_div(int flags, int rm, int control_w) | 27 | int FPU_div(int flags, int rm, int control_w) |
28 | { | 28 | { |
29 | FPU_REG x, y; | 29 | FPU_REG x, y; |
30 | FPU_REG const *a, *b, *st0_ptr, *st_ptr; | 30 | FPU_REG const *a, *b, *st0_ptr, *st_ptr; |
31 | FPU_REG *dest; | 31 | FPU_REG *dest; |
32 | u_char taga, tagb, signa, signb, sign, saved_sign; | 32 | u_char taga, tagb, signa, signb, sign, saved_sign; |
33 | int tag, deststnr; | 33 | int tag, deststnr; |
34 | 34 | ||
35 | if ( flags & DEST_RM ) | 35 | if (flags & DEST_RM) |
36 | deststnr = rm; | 36 | deststnr = rm; |
37 | else | 37 | else |
38 | deststnr = 0; | 38 | deststnr = 0; |
39 | 39 | ||
40 | if ( flags & REV ) | 40 | if (flags & REV) { |
41 | { | 41 | b = &st(0); |
42 | b = &st(0); | 42 | st0_ptr = b; |
43 | st0_ptr = b; | 43 | tagb = FPU_gettag0(); |
44 | tagb = FPU_gettag0(); | 44 | if (flags & LOADED) { |
45 | if ( flags & LOADED ) | 45 | a = (FPU_REG *) rm; |
46 | { | 46 | taga = flags & 0x0f; |
47 | a = (FPU_REG *)rm; | 47 | } else { |
48 | taga = flags & 0x0f; | 48 | a = &st(rm); |
49 | st_ptr = a; | ||
50 | taga = FPU_gettagi(rm); | ||
51 | } | ||
52 | } else { | ||
53 | a = &st(0); | ||
54 | st0_ptr = a; | ||
55 | taga = FPU_gettag0(); | ||
56 | if (flags & LOADED) { | ||
57 | b = (FPU_REG *) rm; | ||
58 | tagb = flags & 0x0f; | ||
59 | } else { | ||
60 | b = &st(rm); | ||
61 | st_ptr = b; | ||
62 | tagb = FPU_gettagi(rm); | ||
63 | } | ||
49 | } | 64 | } |
50 | else | ||
51 | { | ||
52 | a = &st(rm); | ||
53 | st_ptr = a; | ||
54 | taga = FPU_gettagi(rm); | ||
55 | } | ||
56 | } | ||
57 | else | ||
58 | { | ||
59 | a = &st(0); | ||
60 | st0_ptr = a; | ||
61 | taga = FPU_gettag0(); | ||
62 | if ( flags & LOADED ) | ||
63 | { | ||
64 | b = (FPU_REG *)rm; | ||
65 | tagb = flags & 0x0f; | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | b = &st(rm); | ||
70 | st_ptr = b; | ||
71 | tagb = FPU_gettagi(rm); | ||
72 | } | ||
73 | } | ||
74 | 65 | ||
75 | signa = getsign(a); | 66 | signa = getsign(a); |
76 | signb = getsign(b); | 67 | signb = getsign(b); |
77 | 68 | ||
78 | sign = signa ^ signb; | 69 | sign = signa ^ signb; |
79 | 70 | ||
80 | dest = &st(deststnr); | 71 | dest = &st(deststnr); |
81 | saved_sign = getsign(dest); | 72 | saved_sign = getsign(dest); |
82 | 73 | ||
83 | if ( !(taga | tagb) ) | 74 | if (!(taga | tagb)) { |
84 | { | 75 | /* Both regs Valid, this should be the most common case. */ |
85 | /* Both regs Valid, this should be the most common case. */ | 76 | reg_copy(a, &x); |
86 | reg_copy(a, &x); | 77 | reg_copy(b, &y); |
87 | reg_copy(b, &y); | 78 | setpositive(&x); |
88 | setpositive(&x); | 79 | setpositive(&y); |
89 | setpositive(&y); | 80 | tag = FPU_u_div(&x, &y, dest, control_w, sign); |
90 | tag = FPU_u_div(&x, &y, dest, control_w, sign); | ||
91 | 81 | ||
92 | if ( tag < 0 ) | 82 | if (tag < 0) |
93 | return tag; | 83 | return tag; |
94 | 84 | ||
95 | FPU_settagi(deststnr, tag); | 85 | FPU_settagi(deststnr, tag); |
96 | return tag; | 86 | return tag; |
97 | } | 87 | } |
98 | 88 | ||
99 | if ( taga == TAG_Special ) | 89 | if (taga == TAG_Special) |
100 | taga = FPU_Special(a); | 90 | taga = FPU_Special(a); |
101 | if ( tagb == TAG_Special ) | 91 | if (tagb == TAG_Special) |
102 | tagb = FPU_Special(b); | 92 | tagb = FPU_Special(b); |
103 | 93 | ||
104 | if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) | 94 | if (((taga == TAG_Valid) && (tagb == TW_Denormal)) |
105 | || ((taga == TW_Denormal) && (tagb == TAG_Valid)) | 95 | || ((taga == TW_Denormal) && (tagb == TAG_Valid)) |
106 | || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) | 96 | || ((taga == TW_Denormal) && (tagb == TW_Denormal))) { |
107 | { | 97 | if (denormal_operand() < 0) |
108 | if ( denormal_operand() < 0 ) | 98 | return FPU_Exception; |
109 | return FPU_Exception; | 99 | |
110 | 100 | FPU_to_exp16(a, &x); | |
111 | FPU_to_exp16(a, &x); | 101 | FPU_to_exp16(b, &y); |
112 | FPU_to_exp16(b, &y); | 102 | tag = FPU_u_div(&x, &y, dest, control_w, sign); |
113 | tag = FPU_u_div(&x, &y, dest, control_w, sign); | 103 | if (tag < 0) |
114 | if ( tag < 0 ) | 104 | return tag; |
115 | return tag; | 105 | |
116 | 106 | FPU_settagi(deststnr, tag); | |
117 | FPU_settagi(deststnr, tag); | 107 | return tag; |
118 | return tag; | 108 | } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) { |
119 | } | 109 | if (tagb != TAG_Zero) { |
120 | else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) ) | 110 | /* Want to find Zero/Valid */ |
121 | { | 111 | if (tagb == TW_Denormal) { |
122 | if ( tagb != TAG_Zero ) | 112 | if (denormal_operand() < 0) |
123 | { | 113 | return FPU_Exception; |
124 | /* Want to find Zero/Valid */ | 114 | } |
125 | if ( tagb == TW_Denormal ) | 115 | |
126 | { | 116 | /* The result is zero. */ |
127 | if ( denormal_operand() < 0 ) | 117 | FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); |
128 | return FPU_Exception; | 118 | setsign(dest, sign); |
129 | } | 119 | return TAG_Zero; |
130 | 120 | } | |
131 | /* The result is zero. */ | 121 | /* We have an exception condition, either 0/0 or Valid/Zero. */ |
132 | FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); | 122 | if (taga == TAG_Zero) { |
133 | setsign(dest, sign); | 123 | /* 0/0 */ |
134 | return TAG_Zero; | 124 | return arith_invalid(deststnr); |
125 | } | ||
126 | /* Valid/Zero */ | ||
127 | return FPU_divide_by_zero(deststnr, sign); | ||
135 | } | 128 | } |
136 | /* We have an exception condition, either 0/0 or Valid/Zero. */ | 129 | /* Must have infinities, NaNs, etc */ |
137 | if ( taga == TAG_Zero ) | 130 | else if ((taga == TW_NaN) || (tagb == TW_NaN)) { |
138 | { | 131 | if (flags & LOADED) |
139 | /* 0/0 */ | 132 | return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0, |
140 | return arith_invalid(deststnr); | 133 | st0_ptr); |
134 | |||
135 | if (flags & DEST_RM) { | ||
136 | int tag; | ||
137 | tag = FPU_gettag0(); | ||
138 | if (tag == TAG_Special) | ||
139 | tag = FPU_Special(st0_ptr); | ||
140 | return real_2op_NaN(st0_ptr, tag, rm, | ||
141 | (flags & REV) ? st0_ptr : &st(rm)); | ||
142 | } else { | ||
143 | int tag; | ||
144 | tag = FPU_gettagi(rm); | ||
145 | if (tag == TAG_Special) | ||
146 | tag = FPU_Special(&st(rm)); | ||
147 | return real_2op_NaN(&st(rm), tag, 0, | ||
148 | (flags & REV) ? st0_ptr : &st(rm)); | ||
149 | } | ||
150 | } else if (taga == TW_Infinity) { | ||
151 | if (tagb == TW_Infinity) { | ||
152 | /* infinity/infinity */ | ||
153 | return arith_invalid(deststnr); | ||
154 | } else { | ||
155 | /* tagb must be Valid or Zero */ | ||
156 | if ((tagb == TW_Denormal) && (denormal_operand() < 0)) | ||
157 | return FPU_Exception; | ||
158 | |||
159 | /* Infinity divided by Zero or Valid does | ||
160 | not raise and exception, but returns Infinity */ | ||
161 | FPU_copy_to_regi(a, TAG_Special, deststnr); | ||
162 | setsign(dest, sign); | ||
163 | return taga; | ||
164 | } | ||
165 | } else if (tagb == TW_Infinity) { | ||
166 | if ((taga == TW_Denormal) && (denormal_operand() < 0)) | ||
167 | return FPU_Exception; | ||
168 | |||
169 | /* The result is zero. */ | ||
170 | FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); | ||
171 | setsign(dest, sign); | ||
172 | return TAG_Zero; | ||
141 | } | 173 | } |
142 | /* Valid/Zero */ | ||
143 | return FPU_divide_by_zero(deststnr, sign); | ||
144 | } | ||
145 | /* Must have infinities, NaNs, etc */ | ||
146 | else if ( (taga == TW_NaN) || (tagb == TW_NaN) ) | ||
147 | { | ||
148 | if ( flags & LOADED ) | ||
149 | return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr); | ||
150 | |||
151 | if ( flags & DEST_RM ) | ||
152 | { | ||
153 | int tag; | ||
154 | tag = FPU_gettag0(); | ||
155 | if ( tag == TAG_Special ) | ||
156 | tag = FPU_Special(st0_ptr); | ||
157 | return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm)); | ||
158 | } | ||
159 | else | ||
160 | { | ||
161 | int tag; | ||
162 | tag = FPU_gettagi(rm); | ||
163 | if ( tag == TAG_Special ) | ||
164 | tag = FPU_Special(&st(rm)); | ||
165 | return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm)); | ||
166 | } | ||
167 | } | ||
168 | else if (taga == TW_Infinity) | ||
169 | { | ||
170 | if (tagb == TW_Infinity) | ||
171 | { | ||
172 | /* infinity/infinity */ | ||
173 | return arith_invalid(deststnr); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | /* tagb must be Valid or Zero */ | ||
178 | if ( (tagb == TW_Denormal) && (denormal_operand() < 0) ) | ||
179 | return FPU_Exception; | ||
180 | |||
181 | /* Infinity divided by Zero or Valid does | ||
182 | not raise and exception, but returns Infinity */ | ||
183 | FPU_copy_to_regi(a, TAG_Special, deststnr); | ||
184 | setsign(dest, sign); | ||
185 | return taga; | ||
186 | } | ||
187 | } | ||
188 | else if (tagb == TW_Infinity) | ||
189 | { | ||
190 | if ( (taga == TW_Denormal) && (denormal_operand() < 0) ) | ||
191 | return FPU_Exception; | ||
192 | |||
193 | /* The result is zero. */ | ||
194 | FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); | ||
195 | setsign(dest, sign); | ||
196 | return TAG_Zero; | ||
197 | } | ||
198 | #ifdef PARANOID | 174 | #ifdef PARANOID |
199 | else | 175 | else { |
200 | { | 176 | EXCEPTION(EX_INTERNAL | 0x102); |
201 | EXCEPTION(EX_INTERNAL|0x102); | 177 | return FPU_Exception; |
202 | return FPU_Exception; | 178 | } |
203 | } | 179 | #endif /* PARANOID */ |
204 | #endif /* PARANOID */ | ||
205 | 180 | ||
206 | return 0; | 181 | return 0; |
207 | } | 182 | } |