Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*---------------------------------------------------------------------------+
0003  |  reg_compare.c                                                            |
0004  |                                                                           |
0005  | Compare two floating point registers                                      |
0006  |                                                                           |
0007  | Copyright (C) 1992,1993,1994,1997                                         |
0008  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
0009  |                  E-mail   billm@suburbia.net                              |
0010  |                                                                           |
0011  |                                                                           |
0012  +---------------------------------------------------------------------------*/
0013 
0014 /*---------------------------------------------------------------------------+
0015  | compare() is the core FPU_REG comparison function                         |
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                 /* The 80486 book says that infinities can be equal! */
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             /* Fall through to the NaN code */
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             /* Fall through to the NaN code */
0087         }
0088 
0089         /* The only possibility now should be that one of the arguments
0090            is a NaN */
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                 /* Neither is a signaling NaN */
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 /* PARANOID */
0140 
0141     diff = exp0 - expb;
0142     if (diff == 0) {
0143         diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
0144                            identical */
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 /* This function requires that st(0) is not empty */
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 /* PARANOID */
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         /* Stack fault */
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 /* PARANOID */
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         /* Stack fault */
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 /* PARANOID */
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         /* Stack fault */
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) {    /* This is the only difference between
0318                        un-ordered and ordinary comparisons */
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 /* PARANOID */
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         /* Stack fault */
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) {    /* This is the only difference between
0369                        un-ordered and ordinary comparisons */
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 /* PARANOID */
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     /* fcom st(i) */
0408     compare_st_st(FPU_rm);
0409 }
0410 
0411 void fcompst(void)
0412 {
0413     /* fcomp st(i) */
0414     if (!compare_st_st(FPU_rm))
0415         FPU_pop();
0416 }
0417 
0418 void fcompp(void)
0419 {
0420     /* fcompp */
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     /* fucom st(i) */
0432     compare_u_st_st(FPU_rm);
0433 
0434 }
0435 
0436 void fucomp(void)
0437 {
0438     /* fucomp st(i) */
0439     if (!compare_u_st_st(FPU_rm))
0440         FPU_pop();
0441 }
0442 
0443 void fucompp(void)
0444 {
0445     /* fucompp */
0446     if (FPU_rm == 1) {
0447         if (!compare_u_st_st(1))
0448             poppop();
0449     } else
0450         FPU_illegal();
0451 }
0452 
0453 /* P6+ compare-to-EFLAGS ops */
0454 
0455 void fcomi_(void)
0456 {
0457     /* fcomi st(i) */
0458     compare_i_st_st(FPU_rm);
0459 }
0460 
0461 void fcomip(void)
0462 {
0463     /* fcomip st(i) */
0464     if (!compare_i_st_st(FPU_rm))
0465         FPU_pop();
0466 }
0467 
0468 void fucomi_(void)
0469 {
0470     /* fucomi st(i) */
0471     compare_ui_st_st(FPU_rm);
0472 }
0473 
0474 void fucomip(void)
0475 {
0476     /* fucomip st(i) */
0477     if (!compare_ui_st_st(FPU_rm))
0478         FPU_pop();
0479 }