1 /*
2 * reg_compare.c
3 *
4 * Compare two floating point registers
5 *
6 *
7 * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
8 * Vic 3163, Australia.
9 * E-mail apm233m@vaxc.cc.monash.edu.au
10 * All rights reserved.
11 *
12 * This copyright notice covers the redistribution and use of the
13 * FPU emulator developed by W. Metzenthen. It covers only its use
14 * in the 386BSD operating system. Any other use is not permitted
15 * under this copyright.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must include information specifying
23 * that source code for the emulator is freely available and include
24 * either:
25 * a) an offer to provide the source code for a nominal distribution
26 * fee, or
27 * b) list at least two alternative methods whereby the source
28 * can be obtained, e.g. a publically accessible bulletin board
29 * and an anonymous ftp site from which the software can be
30 * downloaded.
31 * 3. All advertising materials specifically mentioning features or use of
32 * this emulator must acknowledge that it was developed by W. Metzenthen.
33 * 4. The name of W. Metzenthen may not be used to endorse or promote
34 * products derived from this software without specific prior written
35 * permission.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
38 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
40 * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
41 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
42 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
43 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
44 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
45 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 *
48 */
49
50 /*---------------------------------------------------------------------------+
51 | compare() is the core FPU_REG comparison function |
52 +---------------------------------------------------------------------------*/
53
54 #ifdef __386BSD__
55 #include "sys/param.h"
56 #include "sys/user.h"
57 /*#include "sys/signal.h"*/
58 /*#include "sys/errno.h"*/
59 #include "systm.h"
60 #include "proc.h"
61 #include "machine/cpu.h"
62 #include "prototypes.h"
63 #endif
64 #include "fpu_system.h"
65 #include "exception.h"
66 #include "fpu_emu.h"
67 #include "control_w.h"
68 #include "status_w.h"
69
70
compare(FPU_REG * b)71 int compare(FPU_REG *b)
72 {
73 int diff;
74
75 if ( FPU_st0_ptr->tag | b->tag )
76 {
77 if ( FPU_st0_ptr->tag == TW_Zero )
78 {
79 if ( b->tag == TW_Zero ) return COMP_A_eq_B;
80 if ( b->tag == TW_Valid )
81 {
82 #ifdef DENORM_OPERAND
83 if ( (b->exp <= EXP_UNDER) && (denormal_operand()) )
84 return COMP_Denormal;
85 #endif DENORM_OPERAND
86 return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B ;
87 }
88 }
89 else if ( b->tag == TW_Zero )
90 {
91 if ( FPU_st0_ptr->tag == TW_Valid )
92 {
93 #ifdef DENORM_OPERAND
94 if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
95 return COMP_Denormal;
96 #endif DENORM_OPERAND
97 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B ;
98 }
99 }
100
101 if ( FPU_st0_ptr->tag == TW_Infinity )
102 {
103 if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
104 {
105 #ifdef DENORM_OPERAND
106 if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER)
107 && (denormal_operand()) )
108 return COMP_Denormal;
109 #endif DENORM_OPERAND
110 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
111 }
112 else if ( b->tag == TW_Infinity )
113 {
114 /* The 80486 book says that infinities can be equal! */
115 return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
116 ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
117 }
118 /* Fall through to the NaN code */
119 }
120 else if ( b->tag == TW_Infinity )
121 {
122 if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
123 {
124 #ifdef DENORM_OPERAND
125 if ( (FPU_st0_ptr->tag == TW_Valid)
126 && (FPU_st0_ptr->exp <= EXP_UNDER)
127 && (denormal_operand()) )
128 return COMP_Denormal;
129 #endif DENORM_OPERAND
130 return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
131 }
132 /* Fall through to the NaN code */
133 }
134
135 /* The only possibility now should be that one of the arguments
136 is a NaN */
137 if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
138 {
139 if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
140 || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
141 /* At least one arg is a signaling NaN */
142 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
143 else
144 /* Neither is a signaling NaN */
145 return COMP_No_Comp | COMP_NaN;
146 }
147
148 EXCEPTION(EX_Invalid);
149 }
150
151 #ifdef PARANOID
152 if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
153 if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
154 #endif PARANOID
155
156 #ifdef DENORM_OPERAND
157 if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
158 (b->exp <= EXP_UNDER)) && (denormal_operand()) )
159 return COMP_Denormal;
160 #endif DENORM_OPERAND
161
162 if (FPU_st0_ptr->sign != b->sign)
163 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
164
165 diff = FPU_st0_ptr->exp - b->exp;
166 if ( diff == 0 )
167 {
168 diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits are
169 identical */
170 if ( diff == 0 )
171 {
172 diff = FPU_st0_ptr->sigl > b->sigl;
173 if ( diff == 0 )
174 diff = -(FPU_st0_ptr->sigl < b->sigl);
175 }
176 }
177
178 if ( diff > 0 )
179 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B ;
180 if ( diff < 0 )
181 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B ;
182 return COMP_A_eq_B;
183
184 }
185
186
187 /* This function requires that st(0) is not empty */
compare_st_data(void)188 int compare_st_data(void)
189 {
190 int f, c;
191
192 c = compare(&FPU_loaded_data);
193
194 if (c & (COMP_NaN|COMP_Denormal))
195 {
196 if (c & COMP_NaN)
197 {
198 EXCEPTION(EX_Invalid);
199 f = SW_C3 | SW_C2 | SW_C0;
200 }
201 else
202 {
203 /* One of the operands is a de-normal */
204 return 0;
205 }
206 }
207 else
208 switch (c)
209 {
210 case COMP_A_lt_B:
211 f = SW_C0;
212 break;
213 case COMP_A_eq_B:
214 f = SW_C3;
215 break;
216 case COMP_A_gt_B:
217 f = 0;
218 break;
219 case COMP_No_Comp:
220 f = SW_C3 | SW_C2 | SW_C0;
221 break;
222 #ifdef PARANOID
223 default:
224 EXCEPTION(EX_INTERNAL|0x121);
225 f = SW_C3 | SW_C2 | SW_C0;
226 break;
227 #endif PARANOID
228 }
229 setcc(f);
230 return 1;
231 }
232
233
compare_st_st(int nr)234 static int compare_st_st(int nr)
235 {
236 int f, c;
237
238 if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
239 {
240 setcc(SW_C3 | SW_C2 | SW_C0);
241 /* Stack fault */
242 EXCEPTION(EX_StackUnder);
243 return control_word & CW_Invalid;
244 }
245
246 c = compare(&st(nr));
247 if (c & (COMP_NaN|COMP_Denormal))
248 {
249 if (c & COMP_NaN)
250 {
251 setcc(SW_C3 | SW_C2 | SW_C0);
252 EXCEPTION(EX_Invalid);
253 return control_word & CW_Invalid;
254 }
255 else
256 {
257 /* One of the operands is a de-normal */
258 return control_word & CW_Denormal;
259 }
260 }
261 else
262 switch (c)
263 {
264 case COMP_A_lt_B:
265 f = SW_C0;
266 break;
267 case COMP_A_eq_B:
268 f = SW_C3;
269 break;
270 case COMP_A_gt_B:
271 f = 0;
272 break;
273 case COMP_No_Comp:
274 f = SW_C3 | SW_C2 | SW_C0;
275 break;
276 #ifdef PARANOID
277 default:
278 EXCEPTION(EX_INTERNAL|0x122);
279 f = SW_C3 | SW_C2 | SW_C0;
280 break;
281 #endif PARANOID
282 }
283 setcc(f);
284 return 1;
285 }
286
287
compare_u_st_st(int nr)288 static int compare_u_st_st(int nr)
289 {
290 int f, c;
291
292 if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
293 {
294 setcc(SW_C3 | SW_C2 | SW_C0);
295 /* Stack fault */
296 EXCEPTION(EX_StackUnder);
297 return control_word & CW_Invalid;
298 }
299
300 c = compare(&st(nr));
301 if (c & (COMP_NaN|COMP_Denormal))
302 {
303 if (c & COMP_NaN)
304 {
305 setcc(SW_C3 | SW_C2 | SW_C0);
306 if (c & COMP_SNaN) /* This is the only difference between
307 un-ordered and ordinary comparisons */
308 {
309 EXCEPTION(EX_Invalid);
310 return control_word & CW_Invalid;
311 }
312 return 1;
313 }
314 else
315 {
316 /* One of the operands is a de-normal */
317 return control_word & CW_Denormal;
318 }
319 }
320 else
321 switch (c)
322 {
323 case COMP_A_lt_B:
324 f = SW_C0;
325 break;
326 case COMP_A_eq_B:
327 f = SW_C3;
328 break;
329 case COMP_A_gt_B:
330 f = 0;
331 break;
332 case COMP_No_Comp:
333 f = SW_C3 | SW_C2 | SW_C0;
334 break;
335 #ifdef PARANOID
336 default:
337 EXCEPTION(EX_INTERNAL|0x123);
338 f = SW_C3 | SW_C2 | SW_C0;
339 break;
340 #endif PARANOID
341 }
342 setcc(f);
343 return 1;
344 }
345
346 /*---------------------------------------------------------------------------*/
347
fcom_st()348 void fcom_st()
349 {
350 /* fcom st(i) */
351 compare_st_st(FPU_rm);
352 }
353
354
fcompst()355 void fcompst()
356 {
357 /* fcomp st(i) */
358 if ( compare_st_st(FPU_rm) )
359 pop();
360 }
361
362
fcompp()363 void fcompp()
364 {
365 /* fcompp */
366 if (FPU_rm != 1)
367 return Un_impl();
368 if ( compare_st_st(1) )
369 {
370 pop(); FPU_st0_ptr = &st(0);
371 pop();
372 }
373 }
374
375
fucom_()376 void fucom_()
377 {
378 /* fucom st(i) */
379 compare_u_st_st(FPU_rm);
380
381 }
382
383
fucomp()384 void fucomp()
385 {
386 /* fucomp st(i) */
387 if ( compare_u_st_st(FPU_rm) )
388 pop();
389 }
390
391
fucompp()392 void fucompp()
393 {
394 /* fucompp */
395 if (FPU_rm == 1)
396 {
397 if ( compare_u_st_st(1) )
398 {
399 pop(); FPU_st0_ptr = &st(0);
400 pop();
401 }
402 }
403 else
404 Un_impl();
405 }
406