|
|
1.1 root 1: /*---------------------------------------------------------------------------+
2: | reg_compare.c |
3: | |
4: | Compare two floating point registers |
5: | |
6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
7: | Australia. E-mail [email protected] |
8: | |
9: | |
10: +---------------------------------------------------------------------------*/
11:
12: /*---------------------------------------------------------------------------+
13: | compare() is the core FPU_REG comparison function |
14: +---------------------------------------------------------------------------*/
15:
16: #include "fpu_system.h"
17: #include "exception.h"
18: #include "fpu_emu.h"
19: #include "status_w.h"
20:
21:
22: int emCompare(FPU_REG *b)
23: {
24: int diff;
25:
26: if ( FPU_st0_ptr->tag | b->tag )
27: {
28: if ( FPU_st0_ptr->tag == TW_Zero )
29: {
30: if ( b->tag == TW_Zero ) return COMP_A_EQ_B;
31: if ( b->tag == TW_Valid )
32: {
33: return (b->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
34: }
35: }
36: else if ( b->tag == TW_Zero )
37: {
38: if ( FPU_st0_ptr->tag == TW_Valid )
39: {
40: return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
41: }
42: }
43:
44: if ( FPU_st0_ptr->tag == TW_Infinity )
45: {
46: if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
47: {
48: return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
49: }
50: else if ( b->tag == TW_Infinity )
51: {
52: /* The 80486 book says that infinities can be equal! */
53: return (FPU_st0_ptr->sign == b->sign) ? COMP_A_EQ_B :
54: ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B);
55: }
56: /* Fall through to the NaN code */
57: }
58: else if ( b->tag == TW_Infinity )
59: {
60: if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
61: {
62: return (b->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B;
63: }
64: /* Fall through to the NaN code */
65: }
66:
67: /* The only possibility now should be that one of the arguments
68: is a NaN */
69: if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
70: {
71: if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
72: || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
73: /* At least one arg is a signaling NaN */
74: return COMP_NOCOMP | COMP_SNAN | COMP_NAN;
75: else
76: /* Neither is a signaling NaN */
77: return COMP_NOCOMP | COMP_NAN;
78: }
79:
80: EXCEPTION(EX_Invalid);
81: }
82:
83: #ifdef PARANOID
84: if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
85: if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
86: #endif PARANOID
87:
88: if (FPU_st0_ptr->sign != b->sign)
89: return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B;
90:
91: diff = FPU_st0_ptr->exp - b->exp;
92: if ( diff == 0 )
93: {
94: diff = FPU_st0_ptr->sigh - b->sigh;
95: if ( diff == 0 )
96: diff = FPU_st0_ptr->sigl - b->sigl;
97: }
98:
99: if ( diff > 0 )
100: return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_GT_B : COMP_A_LT_B ;
101: if ( diff < 0 )
102: return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_LT_B : COMP_A_GT_B ;
103: return COMP_A_EQ_B;
104:
105: }
106:
107:
108: void compare_st_data(void)
109: {
110: int f;
111: int c = emCompare(&FPU_loaded_data);
112:
113: if (c & COMP_NAN)
114: {
115: EXCEPTION(EX_Invalid);
116: f = SW_C3 | SW_C2 | SW_C0;
117: }
118: else
119: switch (c)
120: {
121: case COMP_A_LT_B:
122: f = SW_C0;
123: break;
124: case COMP_A_EQ_B:
125: f = SW_C3;
126: break;
127: case COMP_A_GT_B:
128: f = 0;
129: break;
130: case COMP_NOCOMP:
131: f = SW_C3 | SW_C2 | SW_C0;
132: break;
133: #ifdef PARANOID
134: default:
135: EXCEPTION(EX_INTERNAL|0x121);
136: f = SW_C3 | SW_C2 | SW_C0;
137: break;
138: #endif PARANOID
139: }
140: setcc(f);
141: }
142:
143:
144: static void compare_st_st(int nr)
145: {
146: int c = emCompare(&st(nr));
147: int f;
148: if (c & COMP_NAN)
149: {
150: EXCEPTION(EX_Invalid);
151: f = SW_C3 | SW_C2 | SW_C0;
152: }
153: else
154: switch (c)
155: {
156: case COMP_A_LT_B:
157: f = SW_C0;
158: break;
159: case COMP_A_EQ_B:
160: f = SW_C3;
161: break;
162: case COMP_A_GT_B:
163: f = 0;
164: break;
165: case COMP_NOCOMP:
166: f = SW_C3 | SW_C2 | SW_C0;
167: break;
168: #ifdef PARANOID
169: default:
170: EXCEPTION(EX_INTERNAL|0x122);
171: f = SW_C3 | SW_C2 | SW_C0;
172: break;
173: #endif PARANOID
174: }
175: setcc(f);
176: }
177:
178:
179: static void compare_u_st_st(int nr)
180: {
181: int f;
182: int c = emCompare(&st(nr));
183: if (c & COMP_NAN)
184: {
185: if (c & COMP_SNAN) /* This is the only difference between
186: un-ordered and ordinary comparisons */
187: EXCEPTION(EX_Invalid);
188: f = SW_C3 | SW_C2 | SW_C0;
189: }
190: else
191: switch (c)
192: {
193: case COMP_A_LT_B:
194: f = SW_C0;
195: break;
196: case COMP_A_EQ_B:
197: f = SW_C3;
198: break;
199: case COMP_A_GT_B:
200: f = 0;
201: break;
202: case COMP_NOCOMP:
203: f = SW_C3 | SW_C2 | SW_C0;
204: break;
205: #ifdef PARANOID
206: default:
207: EXCEPTION(EX_INTERNAL|0x123);
208: f = SW_C3 | SW_C2 | SW_C0;
209: break;
210: #endif PARANOID
211: }
212: setcc(f);
213: }
214:
215: /*---------------------------------------------------------------------------*/
216:
217: void fcom_st()
218: {
219: /* fcom st(i) */
220: compare_st_st(FPU_rm);
221: }
222:
223:
224: void fcompst()
225: {
226: /* fcomp st(i) */
227: compare_st_st(FPU_rm);
228: pop();
229: }
230:
231:
232: void fcompp()
233: {
234: /* fcompp */
235: if (FPU_rm != 1)
236: return Un_impl();
237: compare_st_st(1);
238: pop(); FPU_st0_ptr = &st(0);
239: pop();
240: }
241:
242:
243: void fucom_()
244: {
245: /* fucom st(i) */
246: compare_u_st_st(FPU_rm);
247: }
248:
249:
250: void fucomp()
251: {
252: /* fucomp st(i) */
253: compare_u_st_st(FPU_rm);
254: pop();
255: }
256:
257:
258: void fucompp()
259: {
260: /* fucompp */
261: if (FPU_rm == 1)
262: {
263: compare_u_st_st(1);
264: pop(); FPU_st0_ptr = &st(0);
265: pop();
266: }
267: else
268: Un_impl();
269: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.