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