1 /*---------------------------------------------------------------------------+ 2 | reg_divide.c | 3 | | 4 | Divide one FPU_REG by another and put the result in a destination FPU_REG.| 5 | | 6 | Copyright (C) 1996 | 7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | 8 | E-mail billm@jacobi.maths.monash.edu.au | 9 | | 10 | Return value is the tag of the answer, or-ed with FPU_Exception if | 11 | one was raised, or -1 on internal error. | 12 | | 13 +---------------------------------------------------------------------------*/ 14 15 /*---------------------------------------------------------------------------+ 16 | The destination may be any FPU_REG, including one of the source FPU_REGs. | 17 +---------------------------------------------------------------------------*/ 18 19 #include "exception.h" 20 #include "reg_constant.h" 21 #include "fpu_emu.h" 22 #include "fpu_system.h" 23 24 /* 25 Divide one register by another and put the result into a third register. 26 */ 27 int FPU_div(int flags, int rm, int control_w) 28 { 29 FPU_REG x, y; 30 FPU_REG const *a, *b, *st0_ptr, *st_ptr; 31 FPU_REG *dest; 32 u_char taga, tagb, signa, signb, sign, saved_sign; 33 int tag, deststnr; 34 35 if (flags & DEST_RM) 36 deststnr = rm; 37 else 38 deststnr = 0; 39 40 if (flags & REV) { 41 b = &st(0); 42 st0_ptr = b; 43 tagb = FPU_gettag0(); 44 if (flags & LOADED) { 45 a = (FPU_REG *) rm; 46 taga = flags & 0x0f; 47 } else { 48 a = &st(rm); 49 st_ptr = a; 50 taga = FPU_gettagi(rm); 51 } 52 } else { 53 a = &st(0); 54 st0_ptr = a; 55 taga = FPU_gettag0(); 56 if (flags & LOADED) { 57 b = (FPU_REG *) rm; 58 tagb = flags & 0x0f; 59 } else { 60 b = &st(rm); 61 st_ptr = b; 62 tagb = FPU_gettagi(rm); 63 } 64 } 65 66 signa = getsign(a); 67 signb = getsign(b); 68 69 sign = signa ^ signb; 70 71 dest = &st(deststnr); 72 saved_sign = getsign(dest); 73 74 if (!(taga | tagb)) { 75 /* Both regs Valid, this should be the most common case. */ 76 reg_copy(a, &x); 77 reg_copy(b, &y); 78 setpositive(&x); 79 setpositive(&y); 80 tag = FPU_u_div(&x, &y, dest, control_w, sign); 81 82 if (tag < 0) 83 return tag; 84 85 FPU_settagi(deststnr, tag); 86 return tag; 87 } 88 89 if (taga == TAG_Special) 90 taga = FPU_Special(a); 91 if (tagb == TAG_Special) 92 tagb = FPU_Special(b); 93 94 if (((taga == TAG_Valid) && (tagb == TW_Denormal)) 95 || ((taga == TW_Denormal) && (tagb == TAG_Valid)) 96 || ((taga == TW_Denormal) && (tagb == TW_Denormal))) { 97 if (denormal_operand() < 0) 98 return FPU_Exception; 99 100 FPU_to_exp16(a, &x); 101 FPU_to_exp16(b, &y); 102 tag = FPU_u_div(&x, &y, dest, control_w, sign); 103 if (tag < 0) 104 return tag; 105 106 FPU_settagi(deststnr, tag); 107 return tag; 108 } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) { 109 if (tagb != TAG_Zero) { 110 /* Want to find Zero/Valid */ 111 if (tagb == TW_Denormal) { 112 if (denormal_operand() < 0) 113 return FPU_Exception; 114 } 115 116 /* The result is zero. */ 117 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); 118 setsign(dest, sign); 119 return TAG_Zero; 120 } 121 /* We have an exception condition, either 0/0 or Valid/Zero. */ 122 if (taga == TAG_Zero) { 123 /* 0/0 */ 124 return arith_invalid(deststnr); 125 } 126 /* Valid/Zero */ 127 return FPU_divide_by_zero(deststnr, sign); 128 } 129 /* Must have infinities, NaNs, etc */ 130 else if ((taga == TW_NaN) || (tagb == TW_NaN)) { 131 if (flags & LOADED) 132 return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0, 133 st0_ptr); 134 135 if (flags & DEST_RM) { 136 int tag; 137 tag = FPU_gettag0(); 138 if (tag == TAG_Special) 139 tag = FPU_Special(st0_ptr); 140 return real_2op_NaN(st0_ptr, tag, rm, 141 (flags & REV) ? st0_ptr : &st(rm)); 142 } else { 143 int tag; 144 tag = FPU_gettagi(rm); 145 if (tag == TAG_Special) 146 tag = FPU_Special(&st(rm)); 147 return real_2op_NaN(&st(rm), tag, 0, 148 (flags & REV) ? st0_ptr : &st(rm)); 149 } 150 } else if (taga == TW_Infinity) { 151 if (tagb == TW_Infinity) { 152 /* infinity/infinity */ 153 return arith_invalid(deststnr); 154 } else { 155 /* tagb must be Valid or Zero */ 156 if ((tagb == TW_Denormal) && (denormal_operand() < 0)) 157 return FPU_Exception; 158 159 /* Infinity divided by Zero or Valid does 160 not raise and exception, but returns Infinity */ 161 FPU_copy_to_regi(a, TAG_Special, deststnr); 162 setsign(dest, sign); 163 return taga; 164 } 165 } else if (tagb == TW_Infinity) { 166 if ((taga == TW_Denormal) && (denormal_operand() < 0)) 167 return FPU_Exception; 168 169 /* The result is zero. */ 170 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); 171 setsign(dest, sign); 172 return TAG_Zero; 173 } 174 #ifdef PARANOID 175 else { 176 EXCEPTION(EX_INTERNAL | 0x102); 177 return FPU_Exception; 178 } 179 #endif /* PARANOID */ 180 181 return 0; 182 } 183