Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Feb 10-13, 2025
Register
Loading...
v3.1
  1/*---------------------------------------------------------------------------+
  2 |  reg_compare.c                                                            |
  3 |                                                                           |
  4 | Compare two floating point registers                                      |
  5 |                                                                           |
  6 | Copyright (C) 1992,1993,1994,1997                                         |
  7 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8 |                  E-mail   billm@suburbia.net                              |
  9 |                                                                           |
 10 |                                                                           |
 11 +---------------------------------------------------------------------------*/
 12
 13/*---------------------------------------------------------------------------+
 14 | compare() is the core FPU_REG comparison function                         |
 15 +---------------------------------------------------------------------------*/
 16
 17#include "fpu_system.h"
 18#include "exception.h"
 19#include "fpu_emu.h"
 20#include "control_w.h"
 21#include "status_w.h"
 22
 23static int compare(FPU_REG const *b, int tagb)
 24{
 25	int diff, exp0, expb;
 26	u_char st0_tag;
 27	FPU_REG *st0_ptr;
 28	FPU_REG x, y;
 29	u_char st0_sign, signb = getsign(b);
 30
 31	st0_ptr = &st(0);
 32	st0_tag = FPU_gettag0();
 33	st0_sign = getsign(st0_ptr);
 34
 35	if (tagb == TAG_Special)
 36		tagb = FPU_Special(b);
 37	if (st0_tag == TAG_Special)
 38		st0_tag = FPU_Special(st0_ptr);
 39
 40	if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
 41	    || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
 42		if (st0_tag == TAG_Zero) {
 43			if (tagb == TAG_Zero)
 44				return COMP_A_eq_B;
 45			if (tagb == TAG_Valid)
 46				return ((signb ==
 47					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
 48			if (tagb == TW_Denormal)
 49				return ((signb ==
 50					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 51				    | COMP_Denormal;
 52		} else if (tagb == TAG_Zero) {
 53			if (st0_tag == TAG_Valid)
 54				return ((st0_sign ==
 55					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 56			if (st0_tag == TW_Denormal)
 57				return ((st0_sign ==
 58					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 59				    | COMP_Denormal;
 60		}
 61
 62		if (st0_tag == TW_Infinity) {
 63			if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
 64				return ((st0_sign ==
 65					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 66			else if (tagb == TW_Denormal)
 67				return ((st0_sign ==
 68					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 69				    | COMP_Denormal;
 70			else if (tagb == TW_Infinity) {
 71				/* The 80486 book says that infinities can be equal! */
 72				return (st0_sign == signb) ? COMP_A_eq_B :
 73				    ((st0_sign ==
 74				      SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 75			}
 76			/* Fall through to the NaN code */
 77		} else if (tagb == TW_Infinity) {
 78			if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
 79				return ((signb ==
 80					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
 81			if (st0_tag == TW_Denormal)
 82				return ((signb ==
 83					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 84				    | COMP_Denormal;
 85			/* Fall through to the NaN code */
 86		}
 87
 88		/* The only possibility now should be that one of the arguments
 89		   is a NaN */
 90		if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
 91			int signalling = 0, unsupported = 0;
 92			if (st0_tag == TW_NaN) {
 93				signalling =
 94				    (st0_ptr->sigh & 0xc0000000) == 0x80000000;
 95				unsupported = !((exponent(st0_ptr) == EXP_OVER)
 96						&& (st0_ptr->
 97						    sigh & 0x80000000));
 98			}
 99			if (tagb == TW_NaN) {
100				signalling |=
101				    (b->sigh & 0xc0000000) == 0x80000000;
102				unsupported |= !((exponent(b) == EXP_OVER)
103						 && (b->sigh & 0x80000000));
104			}
105			if (signalling || unsupported)
106				return COMP_No_Comp | COMP_SNaN | COMP_NaN;
107			else
108				/* Neither is a signaling NaN */
109				return COMP_No_Comp | COMP_NaN;
110		}
111
112		EXCEPTION(EX_Invalid);
113	}
114
115	if (st0_sign != signb) {
116		return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
117		    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
118		       COMP_Denormal : 0);
119	}
120
121	if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) {
122		FPU_to_exp16(st0_ptr, &x);
123		FPU_to_exp16(b, &y);
124		st0_ptr = &x;
125		b = &y;
126		exp0 = exponent16(st0_ptr);
127		expb = exponent16(b);
128	} else {
129		exp0 = exponent(st0_ptr);
130		expb = exponent(b);
131	}
132
133#ifdef PARANOID
134	if (!(st0_ptr->sigh & 0x80000000))
135		EXCEPTION(EX_Invalid);
136	if (!(b->sigh & 0x80000000))
137		EXCEPTION(EX_Invalid);
138#endif /* PARANOID */
139
140	diff = exp0 - expb;
141	if (diff == 0) {
142		diff = st0_ptr->sigh - b->sigh;	/* Works only if ms bits are
143						   identical */
144		if (diff == 0) {
145			diff = st0_ptr->sigl > b->sigl;
146			if (diff == 0)
147				diff = -(st0_ptr->sigl < b->sigl);
148		}
149	}
150
151	if (diff > 0) {
152		return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
153		    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
154		       COMP_Denormal : 0);
155	}
156	if (diff < 0) {
157		return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
158		    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
159		       COMP_Denormal : 0);
160	}
161
162	return COMP_A_eq_B
163	    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164	       COMP_Denormal : 0);
165
166}
167
168/* This function requires that st(0) is not empty */
169int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
170{
171	int f = 0, c;
172
173	c = compare(loaded_data, loaded_tag);
174
175	if (c & COMP_NaN) {
176		EXCEPTION(EX_Invalid);
177		f = SW_C3 | SW_C2 | SW_C0;
178	} else
179		switch (c & 7) {
180		case COMP_A_lt_B:
181			f = SW_C0;
182			break;
183		case COMP_A_eq_B:
184			f = SW_C3;
185			break;
186		case COMP_A_gt_B:
187			f = 0;
188			break;
189		case COMP_No_Comp:
190			f = SW_C3 | SW_C2 | SW_C0;
191			break;
192#ifdef PARANOID
193		default:
194			EXCEPTION(EX_INTERNAL | 0x121);
195			f = SW_C3 | SW_C2 | SW_C0;
196			break;
197#endif /* PARANOID */
198		}
199	setcc(f);
200	if (c & COMP_Denormal) {
201		return denormal_operand() < 0;
202	}
203	return 0;
204}
205
206static int compare_st_st(int nr)
207{
208	int f = 0, c;
209	FPU_REG *st_ptr;
210
211	if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
212		setcc(SW_C3 | SW_C2 | SW_C0);
213		/* Stack fault */
214		EXCEPTION(EX_StackUnder);
215		return !(control_word & CW_Invalid);
216	}
217
218	st_ptr = &st(nr);
219	c = compare(st_ptr, FPU_gettagi(nr));
220	if (c & COMP_NaN) {
221		setcc(SW_C3 | SW_C2 | SW_C0);
222		EXCEPTION(EX_Invalid);
223		return !(control_word & CW_Invalid);
224	} else
225		switch (c & 7) {
226		case COMP_A_lt_B:
227			f = SW_C0;
228			break;
229		case COMP_A_eq_B:
230			f = SW_C3;
231			break;
232		case COMP_A_gt_B:
233			f = 0;
234			break;
235		case COMP_No_Comp:
236			f = SW_C3 | SW_C2 | SW_C0;
237			break;
238#ifdef PARANOID
239		default:
240			EXCEPTION(EX_INTERNAL | 0x122);
241			f = SW_C3 | SW_C2 | SW_C0;
242			break;
243#endif /* PARANOID */
244		}
245	setcc(f);
246	if (c & COMP_Denormal) {
247		return denormal_operand() < 0;
248	}
249	return 0;
250}
251
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252static int compare_u_st_st(int nr)
253{
254	int f = 0, c;
255	FPU_REG *st_ptr;
256
257	if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
258		setcc(SW_C3 | SW_C2 | SW_C0);
259		/* Stack fault */
260		EXCEPTION(EX_StackUnder);
261		return !(control_word & CW_Invalid);
262	}
263
264	st_ptr = &st(nr);
265	c = compare(st_ptr, FPU_gettagi(nr));
266	if (c & COMP_NaN) {
267		setcc(SW_C3 | SW_C2 | SW_C0);
268		if (c & COMP_SNaN) {	/* This is the only difference between
269					   un-ordered and ordinary comparisons */
270			EXCEPTION(EX_Invalid);
271			return !(control_word & CW_Invalid);
272		}
273		return 0;
274	} else
275		switch (c & 7) {
276		case COMP_A_lt_B:
277			f = SW_C0;
278			break;
279		case COMP_A_eq_B:
280			f = SW_C3;
281			break;
282		case COMP_A_gt_B:
283			f = 0;
284			break;
285		case COMP_No_Comp:
286			f = SW_C3 | SW_C2 | SW_C0;
287			break;
288#ifdef PARANOID
289		default:
290			EXCEPTION(EX_INTERNAL | 0x123);
291			f = SW_C3 | SW_C2 | SW_C0;
292			break;
293#endif /* PARANOID */
294		}
295	setcc(f);
296	if (c & COMP_Denormal) {
297		return denormal_operand() < 0;
298	}
299	return 0;
300}
301
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302/*---------------------------------------------------------------------------*/
303
304void fcom_st(void)
305{
306	/* fcom st(i) */
307	compare_st_st(FPU_rm);
308}
309
310void fcompst(void)
311{
312	/* fcomp st(i) */
313	if (!compare_st_st(FPU_rm))
314		FPU_pop();
315}
316
317void fcompp(void)
318{
319	/* fcompp */
320	if (FPU_rm != 1) {
321		FPU_illegal();
322		return;
323	}
324	if (!compare_st_st(1))
325		poppop();
326}
327
328void fucom_(void)
329{
330	/* fucom st(i) */
331	compare_u_st_st(FPU_rm);
332
333}
334
335void fucomp(void)
336{
337	/* fucomp st(i) */
338	if (!compare_u_st_st(FPU_rm))
339		FPU_pop();
340}
341
342void fucompp(void)
343{
344	/* fucompp */
345	if (FPU_rm == 1) {
346		if (!compare_u_st_st(1))
347			poppop();
348	} else
349		FPU_illegal();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350}
v4.10.11
  1/*---------------------------------------------------------------------------+
  2 |  reg_compare.c                                                            |
  3 |                                                                           |
  4 | Compare two floating point registers                                      |
  5 |                                                                           |
  6 | Copyright (C) 1992,1993,1994,1997                                         |
  7 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8 |                  E-mail   billm@suburbia.net                              |
  9 |                                                                           |
 10 |                                                                           |
 11 +---------------------------------------------------------------------------*/
 12
 13/*---------------------------------------------------------------------------+
 14 | compare() is the core FPU_REG comparison function                         |
 15 +---------------------------------------------------------------------------*/
 16
 17#include "fpu_system.h"
 18#include "exception.h"
 19#include "fpu_emu.h"
 20#include "control_w.h"
 21#include "status_w.h"
 22
 23static int compare(FPU_REG const *b, int tagb)
 24{
 25	int diff, exp0, expb;
 26	u_char st0_tag;
 27	FPU_REG *st0_ptr;
 28	FPU_REG x, y;
 29	u_char st0_sign, signb = getsign(b);
 30
 31	st0_ptr = &st(0);
 32	st0_tag = FPU_gettag0();
 33	st0_sign = getsign(st0_ptr);
 34
 35	if (tagb == TAG_Special)
 36		tagb = FPU_Special(b);
 37	if (st0_tag == TAG_Special)
 38		st0_tag = FPU_Special(st0_ptr);
 39
 40	if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
 41	    || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
 42		if (st0_tag == TAG_Zero) {
 43			if (tagb == TAG_Zero)
 44				return COMP_A_eq_B;
 45			if (tagb == TAG_Valid)
 46				return ((signb ==
 47					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
 48			if (tagb == TW_Denormal)
 49				return ((signb ==
 50					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 51				    | COMP_Denormal;
 52		} else if (tagb == TAG_Zero) {
 53			if (st0_tag == TAG_Valid)
 54				return ((st0_sign ==
 55					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 56			if (st0_tag == TW_Denormal)
 57				return ((st0_sign ==
 58					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 59				    | COMP_Denormal;
 60		}
 61
 62		if (st0_tag == TW_Infinity) {
 63			if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
 64				return ((st0_sign ==
 65					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 66			else if (tagb == TW_Denormal)
 67				return ((st0_sign ==
 68					 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 69				    | COMP_Denormal;
 70			else if (tagb == TW_Infinity) {
 71				/* The 80486 book says that infinities can be equal! */
 72				return (st0_sign == signb) ? COMP_A_eq_B :
 73				    ((st0_sign ==
 74				      SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 75			}
 76			/* Fall through to the NaN code */
 77		} else if (tagb == TW_Infinity) {
 78			if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
 79				return ((signb ==
 80					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
 81			if (st0_tag == TW_Denormal)
 82				return ((signb ==
 83					 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 84				    | COMP_Denormal;
 85			/* Fall through to the NaN code */
 86		}
 87
 88		/* The only possibility now should be that one of the arguments
 89		   is a NaN */
 90		if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
 91			int signalling = 0, unsupported = 0;
 92			if (st0_tag == TW_NaN) {
 93				signalling =
 94				    (st0_ptr->sigh & 0xc0000000) == 0x80000000;
 95				unsupported = !((exponent(st0_ptr) == EXP_OVER)
 96						&& (st0_ptr->
 97						    sigh & 0x80000000));
 98			}
 99			if (tagb == TW_NaN) {
100				signalling |=
101				    (b->sigh & 0xc0000000) == 0x80000000;
102				unsupported |= !((exponent(b) == EXP_OVER)
103						 && (b->sigh & 0x80000000));
104			}
105			if (signalling || unsupported)
106				return COMP_No_Comp | COMP_SNaN | COMP_NaN;
107			else
108				/* Neither is a signaling NaN */
109				return COMP_No_Comp | COMP_NaN;
110		}
111
112		EXCEPTION(EX_Invalid);
113	}
114
115	if (st0_sign != signb) {
116		return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
117		    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
118		       COMP_Denormal : 0);
119	}
120
121	if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) {
122		FPU_to_exp16(st0_ptr, &x);
123		FPU_to_exp16(b, &y);
124		st0_ptr = &x;
125		b = &y;
126		exp0 = exponent16(st0_ptr);
127		expb = exponent16(b);
128	} else {
129		exp0 = exponent(st0_ptr);
130		expb = exponent(b);
131	}
132
133#ifdef PARANOID
134	if (!(st0_ptr->sigh & 0x80000000))
135		EXCEPTION(EX_Invalid);
136	if (!(b->sigh & 0x80000000))
137		EXCEPTION(EX_Invalid);
138#endif /* PARANOID */
139
140	diff = exp0 - expb;
141	if (diff == 0) {
142		diff = st0_ptr->sigh - b->sigh;	/* Works only if ms bits are
143						   identical */
144		if (diff == 0) {
145			diff = st0_ptr->sigl > b->sigl;
146			if (diff == 0)
147				diff = -(st0_ptr->sigl < b->sigl);
148		}
149	}
150
151	if (diff > 0) {
152		return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
153		    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
154		       COMP_Denormal : 0);
155	}
156	if (diff < 0) {
157		return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
158		    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
159		       COMP_Denormal : 0);
160	}
161
162	return COMP_A_eq_B
163	    | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164	       COMP_Denormal : 0);
165
166}
167
168/* This function requires that st(0) is not empty */
169int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
170{
171	int f = 0, c;
172
173	c = compare(loaded_data, loaded_tag);
174
175	if (c & COMP_NaN) {
176		EXCEPTION(EX_Invalid);
177		f = SW_C3 | SW_C2 | SW_C0;
178	} else
179		switch (c & 7) {
180		case COMP_A_lt_B:
181			f = SW_C0;
182			break;
183		case COMP_A_eq_B:
184			f = SW_C3;
185			break;
186		case COMP_A_gt_B:
187			f = 0;
188			break;
189		case COMP_No_Comp:
190			f = SW_C3 | SW_C2 | SW_C0;
191			break;
192#ifdef PARANOID
193		default:
194			EXCEPTION(EX_INTERNAL | 0x121);
195			f = SW_C3 | SW_C2 | SW_C0;
196			break;
197#endif /* PARANOID */
198		}
199	setcc(f);
200	if (c & COMP_Denormal) {
201		return denormal_operand() < 0;
202	}
203	return 0;
204}
205
206static int compare_st_st(int nr)
207{
208	int f = 0, c;
209	FPU_REG *st_ptr;
210
211	if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
212		setcc(SW_C3 | SW_C2 | SW_C0);
213		/* Stack fault */
214		EXCEPTION(EX_StackUnder);
215		return !(control_word & CW_Invalid);
216	}
217
218	st_ptr = &st(nr);
219	c = compare(st_ptr, FPU_gettagi(nr));
220	if (c & COMP_NaN) {
221		setcc(SW_C3 | SW_C2 | SW_C0);
222		EXCEPTION(EX_Invalid);
223		return !(control_word & CW_Invalid);
224	} else
225		switch (c & 7) {
226		case COMP_A_lt_B:
227			f = SW_C0;
228			break;
229		case COMP_A_eq_B:
230			f = SW_C3;
231			break;
232		case COMP_A_gt_B:
233			f = 0;
234			break;
235		case COMP_No_Comp:
236			f = SW_C3 | SW_C2 | SW_C0;
237			break;
238#ifdef PARANOID
239		default:
240			EXCEPTION(EX_INTERNAL | 0x122);
241			f = SW_C3 | SW_C2 | SW_C0;
242			break;
243#endif /* PARANOID */
244		}
245	setcc(f);
246	if (c & COMP_Denormal) {
247		return denormal_operand() < 0;
248	}
249	return 0;
250}
251
252static int compare_i_st_st(int nr)
253{
254	int f, c;
255	FPU_REG *st_ptr;
256
257	if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
258		FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
259		/* Stack fault */
260		EXCEPTION(EX_StackUnder);
261		return !(control_word & CW_Invalid);
262	}
263
264	partial_status &= ~SW_C0;
265	st_ptr = &st(nr);
266	c = compare(st_ptr, FPU_gettagi(nr));
267	if (c & COMP_NaN) {
268		FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
269		EXCEPTION(EX_Invalid);
270		return !(control_word & CW_Invalid);
271	}
272
273	switch (c & 7) {
274	case COMP_A_lt_B:
275		f = X86_EFLAGS_CF;
276		break;
277	case COMP_A_eq_B:
278		f = X86_EFLAGS_ZF;
279		break;
280	case COMP_A_gt_B:
281		f = 0;
282		break;
283	case COMP_No_Comp:
284		f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
285		break;
286#ifdef PARANOID
287	default:
288		EXCEPTION(EX_INTERNAL | 0x122);
289		f = 0;
290		break;
291#endif /* PARANOID */
292	}
293	FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
294	if (c & COMP_Denormal) {
295		return denormal_operand() < 0;
296	}
297	return 0;
298}
299
300static int compare_u_st_st(int nr)
301{
302	int f = 0, c;
303	FPU_REG *st_ptr;
304
305	if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
306		setcc(SW_C3 | SW_C2 | SW_C0);
307		/* Stack fault */
308		EXCEPTION(EX_StackUnder);
309		return !(control_word & CW_Invalid);
310	}
311
312	st_ptr = &st(nr);
313	c = compare(st_ptr, FPU_gettagi(nr));
314	if (c & COMP_NaN) {
315		setcc(SW_C3 | SW_C2 | SW_C0);
316		if (c & COMP_SNaN) {	/* This is the only difference between
317					   un-ordered and ordinary comparisons */
318			EXCEPTION(EX_Invalid);
319			return !(control_word & CW_Invalid);
320		}
321		return 0;
322	} else
323		switch (c & 7) {
324		case COMP_A_lt_B:
325			f = SW_C0;
326			break;
327		case COMP_A_eq_B:
328			f = SW_C3;
329			break;
330		case COMP_A_gt_B:
331			f = 0;
332			break;
333		case COMP_No_Comp:
334			f = SW_C3 | SW_C2 | SW_C0;
335			break;
336#ifdef PARANOID
337		default:
338			EXCEPTION(EX_INTERNAL | 0x123);
339			f = SW_C3 | SW_C2 | SW_C0;
340			break;
341#endif /* PARANOID */
342		}
343	setcc(f);
344	if (c & COMP_Denormal) {
345		return denormal_operand() < 0;
346	}
347	return 0;
348}
349
350static int compare_ui_st_st(int nr)
351{
352	int f = 0, c;
353	FPU_REG *st_ptr;
354
355	if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
356		FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
357		/* Stack fault */
358		EXCEPTION(EX_StackUnder);
359		return !(control_word & CW_Invalid);
360	}
361
362	partial_status &= ~SW_C0;
363	st_ptr = &st(nr);
364	c = compare(st_ptr, FPU_gettagi(nr));
365	if (c & COMP_NaN) {
366		FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
367		if (c & COMP_SNaN) {	/* This is the only difference between
368					   un-ordered and ordinary comparisons */
369			EXCEPTION(EX_Invalid);
370			return !(control_word & CW_Invalid);
371		}
372		return 0;
373	}
374
375	switch (c & 7) {
376	case COMP_A_lt_B:
377		f = X86_EFLAGS_CF;
378		break;
379	case COMP_A_eq_B:
380		f = X86_EFLAGS_ZF;
381		break;
382	case COMP_A_gt_B:
383		f = 0;
384		break;
385	case COMP_No_Comp:
386		f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
387		break;
388#ifdef PARANOID
389	default:
390		EXCEPTION(EX_INTERNAL | 0x123);
391		f = 0;
392		break;
393#endif /* PARANOID */
394	}
395	FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
396	if (c & COMP_Denormal) {
397		return denormal_operand() < 0;
398	}
399	return 0;
400}
401
402/*---------------------------------------------------------------------------*/
403
404void fcom_st(void)
405{
406	/* fcom st(i) */
407	compare_st_st(FPU_rm);
408}
409
410void fcompst(void)
411{
412	/* fcomp st(i) */
413	if (!compare_st_st(FPU_rm))
414		FPU_pop();
415}
416
417void fcompp(void)
418{
419	/* fcompp */
420	if (FPU_rm != 1) {
421		FPU_illegal();
422		return;
423	}
424	if (!compare_st_st(1))
425		poppop();
426}
427
428void fucom_(void)
429{
430	/* fucom st(i) */
431	compare_u_st_st(FPU_rm);
432
433}
434
435void fucomp(void)
436{
437	/* fucomp st(i) */
438	if (!compare_u_st_st(FPU_rm))
439		FPU_pop();
440}
441
442void fucompp(void)
443{
444	/* fucompp */
445	if (FPU_rm == 1) {
446		if (!compare_u_st_st(1))
447			poppop();
448	} else
449		FPU_illegal();
450}
451
452/* P6+ compare-to-EFLAGS ops */
453
454void fcomi_(void)
455{
456	/* fcomi st(i) */
457	compare_i_st_st(FPU_rm);
458}
459
460void fcomip(void)
461{
462	/* fcomip st(i) */
463	if (!compare_i_st_st(FPU_rm))
464		FPU_pop();
465}
466
467void fucomi_(void)
468{
469	/* fucomi st(i) */
470	compare_ui_st_st(FPU_rm);
471}
472
473void fucomip(void)
474{
475	/* fucomip st(i) */
476	if (!compare_ui_st_st(FPU_rm))
477		FPU_pop();
478}