diff options
Diffstat (limited to 'arch/i386/math-emu/reg_divide.c')
-rw-r--r-- | arch/i386/math-emu/reg_divide.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/arch/i386/math-emu/reg_divide.c b/arch/i386/math-emu/reg_divide.c new file mode 100644 index 000000000000..5cee7ff920d9 --- /dev/null +++ b/arch/i386/math-emu/reg_divide.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /*---------------------------------------------------------------------------+ | ||
2 | | reg_divide.c | | ||
3 | | | | ||
4 | | Divide one FPU_REG by another and put the result in a destination FPU_REG.| | ||
5 | | | | ||
6 | | Copyright (C) 1996 | | ||
7 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | | ||
8 | | E-mail billm@jacobi.maths.monash.edu.au | | ||
9 | | | | ||
10 | | Return value is the tag of the answer, or-ed with FPU_Exception if | | ||
11 | | one was raised, or -1 on internal error. | | ||
12 | | | | ||
13 | +---------------------------------------------------------------------------*/ | ||
14 | |||
15 | /*---------------------------------------------------------------------------+ | ||
16 | | The destination may be any FPU_REG, including one of the source FPU_REGs. | | ||
17 | +---------------------------------------------------------------------------*/ | ||
18 | |||
19 | #include "exception.h" | ||
20 | #include "reg_constant.h" | ||
21 | #include "fpu_emu.h" | ||
22 | #include "fpu_system.h" | ||
23 | |||
24 | /* | ||
25 | Divide one register by another and put the result into a third register. | ||
26 | */ | ||
27 | int FPU_div(int flags, int rm, int control_w) | ||
28 | { | ||
29 | FPU_REG x, y; | ||
30 | FPU_REG const *a, *b, *st0_ptr, *st_ptr; | ||
31 | FPU_REG *dest; | ||
32 | u_char taga, tagb, signa, signb, sign, saved_sign; | ||
33 | int tag, deststnr; | ||
34 | |||
35 | if ( flags & DEST_RM ) | ||
36 | deststnr = rm; | ||
37 | else | ||
38 | deststnr = 0; | ||
39 | |||
40 | if ( flags & REV ) | ||
41 | { | ||
42 | b = &st(0); | ||
43 | st0_ptr = b; | ||
44 | tagb = FPU_gettag0(); | ||
45 | if ( flags & LOADED ) | ||
46 | { | ||
47 | a = (FPU_REG *)rm; | ||
48 | taga = flags & 0x0f; | ||
49 | } | ||
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 | |||
75 | signa = getsign(a); | ||
76 | signb = getsign(b); | ||
77 | |||
78 | sign = signa ^ signb; | ||
79 | |||
80 | dest = &st(deststnr); | ||
81 | saved_sign = getsign(dest); | ||
82 | |||
83 | if ( !(taga | tagb) ) | ||
84 | { | ||
85 | /* Both regs Valid, this should be the most common case. */ | ||
86 | reg_copy(a, &x); | ||
87 | reg_copy(b, &y); | ||
88 | setpositive(&x); | ||
89 | setpositive(&y); | ||
90 | tag = FPU_u_div(&x, &y, dest, control_w, sign); | ||
91 | |||
92 | if ( tag < 0 ) | ||
93 | return tag; | ||
94 | |||
95 | FPU_settagi(deststnr, tag); | ||
96 | return tag; | ||
97 | } | ||
98 | |||
99 | if ( taga == TAG_Special ) | ||
100 | taga = FPU_Special(a); | ||
101 | if ( tagb == TAG_Special ) | ||
102 | tagb = FPU_Special(b); | ||
103 | |||
104 | if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) | ||
105 | || ((taga == TW_Denormal) && (tagb == TAG_Valid)) | ||
106 | || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) | ||
107 | { | ||
108 | if ( denormal_operand() < 0 ) | ||
109 | return FPU_Exception; | ||
110 | |||
111 | FPU_to_exp16(a, &x); | ||
112 | FPU_to_exp16(b, &y); | ||
113 | tag = FPU_u_div(&x, &y, dest, control_w, sign); | ||
114 | if ( tag < 0 ) | ||
115 | return tag; | ||
116 | |||
117 | FPU_settagi(deststnr, tag); | ||
118 | return tag; | ||
119 | } | ||
120 | else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) ) | ||
121 | { | ||
122 | if ( tagb != TAG_Zero ) | ||
123 | { | ||
124 | /* Want to find Zero/Valid */ | ||
125 | if ( tagb == TW_Denormal ) | ||
126 | { | ||
127 | if ( denormal_operand() < 0 ) | ||
128 | return FPU_Exception; | ||
129 | } | ||
130 | |||
131 | /* The result is zero. */ | ||
132 | FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); | ||
133 | setsign(dest, sign); | ||
134 | return TAG_Zero; | ||
135 | } | ||
136 | /* We have an exception condition, either 0/0 or Valid/Zero. */ | ||
137 | if ( taga == TAG_Zero ) | ||
138 | { | ||
139 | /* 0/0 */ | ||
140 | return arith_invalid(deststnr); | ||
141 | } | ||
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 | ||
199 | else | ||
200 | { | ||
201 | EXCEPTION(EX_INTERNAL|0x102); | ||
202 | return FPU_Exception; | ||
203 | } | ||
204 | #endif /* PARANOID */ | ||
205 | |||
206 | return 0; | ||
207 | } | ||