Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/math-emu/reg_compare.c
10820 views
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 [email protected] |
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
23
static 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 */
169
int 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
206
static 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
252
static 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
304
void fcom_st(void)
305
{
306
/* fcom st(i) */
307
compare_st_st(FPU_rm);
308
}
309
310
void fcompst(void)
311
{
312
/* fcomp st(i) */
313
if (!compare_st_st(FPU_rm))
314
FPU_pop();
315
}
316
317
void 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
328
void fucom_(void)
329
{
330
/* fucom st(i) */
331
compare_u_st_st(FPU_rm);
332
333
}
334
335
void fucomp(void)
336
{
337
/* fucomp st(i) */
338
if (!compare_u_st_st(FPU_rm))
339
FPU_pop();
340
}
341
342
void 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
}
351
352