xref: /386bsd/usr/src/kernel/fpu-emu/reg_compare.c (revision a2142627)
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