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 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