Linux Audio

Check our new training course

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