0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include "fpu_system.h"
0019 #include "exception.h"
0020 #include "fpu_emu.h"
0021 #include "control_w.h"
0022 #include "status_w.h"
0023
0024 static int compare(FPU_REG const *b, int tagb)
0025 {
0026 int diff, exp0, expb;
0027 u_char st0_tag;
0028 FPU_REG *st0_ptr;
0029 FPU_REG x, y;
0030 u_char st0_sign, signb = getsign(b);
0031
0032 st0_ptr = &st(0);
0033 st0_tag = FPU_gettag0();
0034 st0_sign = getsign(st0_ptr);
0035
0036 if (tagb == TAG_Special)
0037 tagb = FPU_Special(b);
0038 if (st0_tag == TAG_Special)
0039 st0_tag = FPU_Special(st0_ptr);
0040
0041 if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
0042 || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
0043 if (st0_tag == TAG_Zero) {
0044 if (tagb == TAG_Zero)
0045 return COMP_A_eq_B;
0046 if (tagb == TAG_Valid)
0047 return ((signb ==
0048 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
0049 if (tagb == TW_Denormal)
0050 return ((signb ==
0051 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
0052 | COMP_Denormal;
0053 } else if (tagb == TAG_Zero) {
0054 if (st0_tag == TAG_Valid)
0055 return ((st0_sign ==
0056 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
0057 if (st0_tag == TW_Denormal)
0058 return ((st0_sign ==
0059 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
0060 | COMP_Denormal;
0061 }
0062
0063 if (st0_tag == TW_Infinity) {
0064 if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
0065 return ((st0_sign ==
0066 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
0067 else if (tagb == TW_Denormal)
0068 return ((st0_sign ==
0069 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
0070 | COMP_Denormal;
0071 else if (tagb == TW_Infinity) {
0072
0073 return (st0_sign == signb) ? COMP_A_eq_B :
0074 ((st0_sign ==
0075 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
0076 }
0077
0078 } else if (tagb == TW_Infinity) {
0079 if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
0080 return ((signb ==
0081 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
0082 if (st0_tag == TW_Denormal)
0083 return ((signb ==
0084 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
0085 | COMP_Denormal;
0086
0087 }
0088
0089
0090
0091 if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
0092 int signalling = 0, unsupported = 0;
0093 if (st0_tag == TW_NaN) {
0094 signalling =
0095 (st0_ptr->sigh & 0xc0000000) == 0x80000000;
0096 unsupported = !((exponent(st0_ptr) == EXP_OVER)
0097 && (st0_ptr->
0098 sigh & 0x80000000));
0099 }
0100 if (tagb == TW_NaN) {
0101 signalling |=
0102 (b->sigh & 0xc0000000) == 0x80000000;
0103 unsupported |= !((exponent(b) == EXP_OVER)
0104 && (b->sigh & 0x80000000));
0105 }
0106 if (signalling || unsupported)
0107 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
0108 else
0109
0110 return COMP_No_Comp | COMP_NaN;
0111 }
0112
0113 EXCEPTION(EX_Invalid);
0114 }
0115
0116 if (st0_sign != signb) {
0117 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
0118 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
0119 COMP_Denormal : 0);
0120 }
0121
0122 if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) {
0123 FPU_to_exp16(st0_ptr, &x);
0124 FPU_to_exp16(b, &y);
0125 st0_ptr = &x;
0126 b = &y;
0127 exp0 = exponent16(st0_ptr);
0128 expb = exponent16(b);
0129 } else {
0130 exp0 = exponent(st0_ptr);
0131 expb = exponent(b);
0132 }
0133
0134 #ifdef PARANOID
0135 if (!(st0_ptr->sigh & 0x80000000))
0136 EXCEPTION(EX_Invalid);
0137 if (!(b->sigh & 0x80000000))
0138 EXCEPTION(EX_Invalid);
0139 #endif
0140
0141 diff = exp0 - expb;
0142 if (diff == 0) {
0143 diff = st0_ptr->sigh - b->sigh;
0144
0145 if (diff == 0) {
0146 diff = st0_ptr->sigl > b->sigl;
0147 if (diff == 0)
0148 diff = -(st0_ptr->sigl < b->sigl);
0149 }
0150 }
0151
0152 if (diff > 0) {
0153 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
0154 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
0155 COMP_Denormal : 0);
0156 }
0157 if (diff < 0) {
0158 return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
0159 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
0160 COMP_Denormal : 0);
0161 }
0162
0163 return COMP_A_eq_B
0164 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
0165 COMP_Denormal : 0);
0166
0167 }
0168
0169
0170 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
0171 {
0172 int f, c;
0173
0174 c = compare(loaded_data, loaded_tag);
0175
0176 if (c & COMP_NaN) {
0177 EXCEPTION(EX_Invalid);
0178 f = SW_C3 | SW_C2 | SW_C0;
0179 } else
0180 switch (c & 7) {
0181 case COMP_A_lt_B:
0182 f = SW_C0;
0183 break;
0184 case COMP_A_eq_B:
0185 f = SW_C3;
0186 break;
0187 case COMP_A_gt_B:
0188 f = 0;
0189 break;
0190 case COMP_No_Comp:
0191 f = SW_C3 | SW_C2 | SW_C0;
0192 break;
0193 default:
0194 #ifdef PARANOID
0195 EXCEPTION(EX_INTERNAL | 0x121);
0196 #endif
0197 f = SW_C3 | SW_C2 | SW_C0;
0198 break;
0199 }
0200 setcc(f);
0201 if (c & COMP_Denormal) {
0202 return denormal_operand() < 0;
0203 }
0204 return 0;
0205 }
0206
0207 static int compare_st_st(int nr)
0208 {
0209 int f, c;
0210 FPU_REG *st_ptr;
0211
0212 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
0213 setcc(SW_C3 | SW_C2 | SW_C0);
0214
0215 EXCEPTION(EX_StackUnder);
0216 return !(control_word & CW_Invalid);
0217 }
0218
0219 st_ptr = &st(nr);
0220 c = compare(st_ptr, FPU_gettagi(nr));
0221 if (c & COMP_NaN) {
0222 setcc(SW_C3 | SW_C2 | SW_C0);
0223 EXCEPTION(EX_Invalid);
0224 return !(control_word & CW_Invalid);
0225 } else
0226 switch (c & 7) {
0227 case COMP_A_lt_B:
0228 f = SW_C0;
0229 break;
0230 case COMP_A_eq_B:
0231 f = SW_C3;
0232 break;
0233 case COMP_A_gt_B:
0234 f = 0;
0235 break;
0236 case COMP_No_Comp:
0237 f = SW_C3 | SW_C2 | SW_C0;
0238 break;
0239 default:
0240 #ifdef PARANOID
0241 EXCEPTION(EX_INTERNAL | 0x122);
0242 #endif
0243 f = SW_C3 | SW_C2 | SW_C0;
0244 break;
0245 }
0246 setcc(f);
0247 if (c & COMP_Denormal) {
0248 return denormal_operand() < 0;
0249 }
0250 return 0;
0251 }
0252
0253 static int compare_i_st_st(int nr)
0254 {
0255 int f, c;
0256 FPU_REG *st_ptr;
0257
0258 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
0259 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
0260
0261 EXCEPTION(EX_StackUnder);
0262 return !(control_word & CW_Invalid);
0263 }
0264
0265 partial_status &= ~SW_C0;
0266 st_ptr = &st(nr);
0267 c = compare(st_ptr, FPU_gettagi(nr));
0268 if (c & COMP_NaN) {
0269 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
0270 EXCEPTION(EX_Invalid);
0271 return !(control_word & CW_Invalid);
0272 }
0273
0274 switch (c & 7) {
0275 case COMP_A_lt_B:
0276 f = X86_EFLAGS_CF;
0277 break;
0278 case COMP_A_eq_B:
0279 f = X86_EFLAGS_ZF;
0280 break;
0281 case COMP_A_gt_B:
0282 f = 0;
0283 break;
0284 case COMP_No_Comp:
0285 f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
0286 break;
0287 default:
0288 #ifdef PARANOID
0289 EXCEPTION(EX_INTERNAL | 0x122);
0290 #endif
0291 f = 0;
0292 break;
0293 }
0294 FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
0295 if (c & COMP_Denormal) {
0296 return denormal_operand() < 0;
0297 }
0298 return 0;
0299 }
0300
0301 static int compare_u_st_st(int nr)
0302 {
0303 int f = 0, c;
0304 FPU_REG *st_ptr;
0305
0306 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
0307 setcc(SW_C3 | SW_C2 | SW_C0);
0308
0309 EXCEPTION(EX_StackUnder);
0310 return !(control_word & CW_Invalid);
0311 }
0312
0313 st_ptr = &st(nr);
0314 c = compare(st_ptr, FPU_gettagi(nr));
0315 if (c & COMP_NaN) {
0316 setcc(SW_C3 | SW_C2 | SW_C0);
0317 if (c & COMP_SNaN) {
0318
0319 EXCEPTION(EX_Invalid);
0320 return !(control_word & CW_Invalid);
0321 }
0322 return 0;
0323 } else
0324 switch (c & 7) {
0325 case COMP_A_lt_B:
0326 f = SW_C0;
0327 break;
0328 case COMP_A_eq_B:
0329 f = SW_C3;
0330 break;
0331 case COMP_A_gt_B:
0332 f = 0;
0333 break;
0334 case COMP_No_Comp:
0335 f = SW_C3 | SW_C2 | SW_C0;
0336 break;
0337 #ifdef PARANOID
0338 default:
0339 EXCEPTION(EX_INTERNAL | 0x123);
0340 f = SW_C3 | SW_C2 | SW_C0;
0341 break;
0342 #endif
0343 }
0344 setcc(f);
0345 if (c & COMP_Denormal) {
0346 return denormal_operand() < 0;
0347 }
0348 return 0;
0349 }
0350
0351 static int compare_ui_st_st(int nr)
0352 {
0353 int f = 0, c;
0354 FPU_REG *st_ptr;
0355
0356 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
0357 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
0358
0359 EXCEPTION(EX_StackUnder);
0360 return !(control_word & CW_Invalid);
0361 }
0362
0363 partial_status &= ~SW_C0;
0364 st_ptr = &st(nr);
0365 c = compare(st_ptr, FPU_gettagi(nr));
0366 if (c & COMP_NaN) {
0367 FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF);
0368 if (c & COMP_SNaN) {
0369
0370 EXCEPTION(EX_Invalid);
0371 return !(control_word & CW_Invalid);
0372 }
0373 return 0;
0374 }
0375
0376 switch (c & 7) {
0377 case COMP_A_lt_B:
0378 f = X86_EFLAGS_CF;
0379 break;
0380 case COMP_A_eq_B:
0381 f = X86_EFLAGS_ZF;
0382 break;
0383 case COMP_A_gt_B:
0384 f = 0;
0385 break;
0386 case COMP_No_Comp:
0387 f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
0388 break;
0389 #ifdef PARANOID
0390 default:
0391 EXCEPTION(EX_INTERNAL | 0x123);
0392 f = 0;
0393 break;
0394 #endif
0395 }
0396 FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
0397 if (c & COMP_Denormal) {
0398 return denormal_operand() < 0;
0399 }
0400 return 0;
0401 }
0402
0403
0404
0405 void fcom_st(void)
0406 {
0407
0408 compare_st_st(FPU_rm);
0409 }
0410
0411 void fcompst(void)
0412 {
0413
0414 if (!compare_st_st(FPU_rm))
0415 FPU_pop();
0416 }
0417
0418 void fcompp(void)
0419 {
0420
0421 if (FPU_rm != 1) {
0422 FPU_illegal();
0423 return;
0424 }
0425 if (!compare_st_st(1))
0426 poppop();
0427 }
0428
0429 void fucom_(void)
0430 {
0431
0432 compare_u_st_st(FPU_rm);
0433
0434 }
0435
0436 void fucomp(void)
0437 {
0438
0439 if (!compare_u_st_st(FPU_rm))
0440 FPU_pop();
0441 }
0442
0443 void fucompp(void)
0444 {
0445
0446 if (FPU_rm == 1) {
0447 if (!compare_u_st_st(1))
0448 poppop();
0449 } else
0450 FPU_illegal();
0451 }
0452
0453
0454
0455 void fcomi_(void)
0456 {
0457
0458 compare_i_st_st(FPU_rm);
0459 }
0460
0461 void fcomip(void)
0462 {
0463
0464 if (!compare_i_st_st(FPU_rm))
0465 FPU_pop();
0466 }
0467
0468 void fucomi_(void)
0469 {
0470
0471 compare_ui_st_st(FPU_rm);
0472 }
0473
0474 void fucomip(void)
0475 {
0476
0477 if (!compare_ui_st_st(FPU_rm))
0478 FPU_pop();
0479 }