Oh GACK! src-clean doesn't quite work that easily since cleandist rebuilds the
[unix-history] / contrib / FAQ / programs / fp-emu / fpemul / reg_compare.c
CommitLineData
f24c459c
JH
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#include "param.h"
54#include "proc.h"
55#include "systm.h"
56#include "machine/cpu.h"
57#include "machine/pcb.h"
58
59#include "fpu_emu.h"
60#include "fpu_system.h"
61#include "exception.h"
62#include "control_w.h"
63#include "status_w.h"
64
65
66int
67compare(FPU_REG * b)
68{
69 int diff;
70
71 if (FPU_st0_ptr->tag | b->tag) {
72 if (FPU_st0_ptr->tag == TW_Zero) {
73 if (b->tag == TW_Zero)
74 return COMP_A_eq_B;
75 if (b->tag == TW_Valid) {
76#ifdef DENORM_OPERAND
77 if ((b->exp <= EXP_UNDER) && (denormal_operand()))
78 return COMP_Denormal;
79#endif /* DENORM_OPERAND */
80 return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
81 }
82 } else
83 if (b->tag == TW_Zero) {
84 if (FPU_st0_ptr->tag == TW_Valid) {
85#ifdef DENORM_OPERAND
86 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
87 return COMP_Denormal;
88#endif /* DENORM_OPERAND */
89 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
90 }
91 }
92 if (FPU_st0_ptr->tag == TW_Infinity) {
93 if ((b->tag == TW_Valid) || (b->tag == TW_Zero)) {
94#ifdef DENORM_OPERAND
95 if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)
96 && (denormal_operand()))
97 return COMP_Denormal;
98#endif /* DENORM_OPERAND */
99 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
100 } else
101 if (b->tag == TW_Infinity) {
102 /* The 80486 book says that infinities
103 * can be equal! */
104 return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
105 ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
106 }
107 /* Fall through to the NaN code */
108 } else
109 if (b->tag == TW_Infinity) {
110 if ((FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero)) {
111#ifdef DENORM_OPERAND
112 if ((FPU_st0_ptr->tag == TW_Valid)
113 && (FPU_st0_ptr->exp <= EXP_UNDER)
114 && (denormal_operand()))
115 return COMP_Denormal;
116#endif /* DENORM_OPERAND */
117 return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
118 }
119 /* Fall through to the NaN code */
120 }
121 /* The only possibility now should be that one of the
122 * arguments is a NaN */
123 if ((FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN)) {
124 if (((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
125 || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)))
126 /* At least one arg is a signaling NaN */
127 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
128 else
129 /* Neither is a signaling NaN */
130 return COMP_No_Comp | COMP_NaN;
131 }
132 EXCEPTION(EX_Invalid);
133 }
134#ifdef PARANOID
135 if (!(FPU_st0_ptr->sigh & 0x80000000))
136 EXCEPTION(EX_Invalid);
137 if (!(b->sigh & 0x80000000))
138 EXCEPTION(EX_Invalid);
139#endif /* PARANOID */
140
141#ifdef DENORM_OPERAND
142 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
143 (b->exp <= EXP_UNDER)) && (denormal_operand()))
144 return COMP_Denormal;
145#endif /* DENORM_OPERAND */
146
147 if (FPU_st0_ptr->sign != b->sign)
148 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
149
150 diff = FPU_st0_ptr->exp - b->exp;
151 if (diff == 0) {
152 diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits
153 * are identical */
154 if (diff == 0) {
155 diff = FPU_st0_ptr->sigl > b->sigl;
156 if (diff == 0)
157 diff = -(FPU_st0_ptr->sigl < b->sigl);
158 }
159 }
160 if (diff > 0)
161 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
162 if (diff < 0)
163 return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
164 return COMP_A_eq_B;
165
166}
167
168
169/* This function requires that st(0) is not empty */
170int
171compare_st_data(void)
172{
173 int f, c;
174
175 c = compare(&FPU_loaded_data);
176
177 if (c & (COMP_NaN | COMP_Denormal)) {
178 if (c & COMP_NaN) {
179 EXCEPTION(EX_Invalid);
180 f = SW_C3 | SW_C2 | SW_C0;
181 } else {
182 /* One of the operands is a de-normal */
183 return 0;
184 }
185 } else
186 switch (c) {
187 case COMP_A_lt_B:
188 f = SW_C0;
189 break;
190 case COMP_A_eq_B:
191 f = SW_C3;
192 break;
193 case COMP_A_gt_B:
194 f = 0;
195 break;
196 case COMP_No_Comp:
197 f = SW_C3 | SW_C2 | SW_C0;
198 break;
199#ifdef PARANOID
200 default:
201 EXCEPTION(EX_INTERNAL | 0x121);
202 f = SW_C3 | SW_C2 | SW_C0;
203 break;
204#endif /* PARANOID */
205 }
206 setcc(f);
207 return 1;
208}
209
210
211static int
212compare_st_st(int nr)
213{
214 int f, c;
215
216 if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
217 setcc(SW_C3 | SW_C2 | SW_C0);
218 /* Stack fault */
219 EXCEPTION(EX_StackUnder);
220 return control_word & CW_Invalid;
221 }
222 c = compare(&st(nr));
223 if (c & (COMP_NaN | COMP_Denormal)) {
224 if (c & COMP_NaN) {
225 setcc(SW_C3 | SW_C2 | SW_C0);
226 EXCEPTION(EX_Invalid);
227 return control_word & CW_Invalid;
228 } else {
229 /* One of the operands is a de-normal */
230 return control_word & CW_Denormal;
231 }
232 } else
233 switch (c) {
234 case COMP_A_lt_B:
235 f = SW_C0;
236 break;
237 case COMP_A_eq_B:
238 f = SW_C3;
239 break;
240 case COMP_A_gt_B:
241 f = 0;
242 break;
243 case COMP_No_Comp:
244 f = SW_C3 | SW_C2 | SW_C0;
245 break;
246#ifdef PARANOID
247 default:
248 EXCEPTION(EX_INTERNAL | 0x122);
249 f = SW_C3 | SW_C2 | SW_C0;
250 break;
251#endif /* PARANOID */
252 }
253 setcc(f);
254 return 1;
255}
256
257
258static int
259compare_u_st_st(int nr)
260{
261 int f, c;
262
263 if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
264 setcc(SW_C3 | SW_C2 | SW_C0);
265 /* Stack fault */
266 EXCEPTION(EX_StackUnder);
267 return control_word & CW_Invalid;
268 }
269 c = compare(&st(nr));
270 if (c & (COMP_NaN | COMP_Denormal)) {
271 if (c & COMP_NaN) {
272 setcc(SW_C3 | SW_C2 | SW_C0);
273 if (c & COMP_SNaN) { /* This is the only difference
274 * between un-ordered and
275 * ordinary comparisons */
276 EXCEPTION(EX_Invalid);
277 return control_word & CW_Invalid;
278 }
279 return 1;
280 } else {
281 /* One of the operands is a de-normal */
282 return control_word & CW_Denormal;
283 }
284 } else
285 switch (c) {
286 case COMP_A_lt_B:
287 f = SW_C0;
288 break;
289 case COMP_A_eq_B:
290 f = SW_C3;
291 break;
292 case COMP_A_gt_B:
293 f = 0;
294 break;
295 case COMP_No_Comp:
296 f = SW_C3 | SW_C2 | SW_C0;
297 break;
298#ifdef PARANOID
299 default:
300 EXCEPTION(EX_INTERNAL | 0x123);
301 f = SW_C3 | SW_C2 | SW_C0;
302 break;
303#endif /* PARANOID */
304 }
305 setcc(f);
306 return 1;
307}
308/*---------------------------------------------------------------------------*/
309
310void
311fcom_st()
312{
313 /* fcom st(i) */
314 compare_st_st(FPU_rm);
315}
316
317
318void
319fcompst()
320{
321 /* fcomp st(i) */
322 if (compare_st_st(FPU_rm))
323 pop();
324}
325
326
327void
328fcompp()
329{
330 /* fcompp */
331 if (FPU_rm != 1)
332 return Un_impl();
333 if (compare_st_st(1)) {
334 pop();
335 FPU_st0_ptr = &st(0);
336 pop();
337 }
338}
339
340
341void
342fucom_()
343{
344 /* fucom st(i) */
345 compare_u_st_st(FPU_rm);
346
347}
348
349
350void
351fucomp()
352{
353 /* fucomp st(i) */
354 if (compare_u_st_st(FPU_rm))
355 pop();
356}
357
358
359void
360fucompp()
361{
362 /* fucompp */
363 if (FPU_rm == 1) {
364 if (compare_u_st_st(1)) {
365 pop();
366 FPU_st0_ptr = &st(0);
367 pop();
368 }
369 } else
370 Un_impl();
371}