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 { 42 b = &st(0); 43 st0_ptr = b; 44 tagb = FPU_gettag0(); 45 if ( flags & LOADED ) 46 { 47 a = (FPU_REG *)rm; 48 taga = flags & 0x0f; 49 } 50 else 51 { 52 a = &st(rm); 53 st_ptr = a; 54 taga = FPU_gettagi(rm); 55 } 56 } 57 else 58 { 59 a = &st(0); 60 st0_ptr = a; 61 taga = FPU_gettag0(); 62 if ( flags & LOADED ) 63 { 64 b = (FPU_REG *)rm; 65 tagb = flags & 0x0f; 66 } 67 else 68 { 69 b = &st(rm); 70 st_ptr = b; 71 tagb = FPU_gettagi(rm); 72 } 73 } 74 75 signa = getsign(a); 76 signb = getsign(b); 77 78 sign = signa ^ signb; 79 80 dest = &st(deststnr); 81 saved_sign = getsign(dest); 82 83 if ( !(taga | tagb) ) 84 { 85 /* Both regs Valid, this should be the most common case. */ 86 reg_copy(a, &x); 87 reg_copy(b, &y); 88 setpositive(&x); 89 setpositive(&y); 90 tag = FPU_u_div(&x, &y, dest, control_w, sign); 91 92 if ( tag < 0 ) 93 return tag; 94 95 FPU_settagi(deststnr, tag); 96 return tag; 97 } 98 99 if ( taga == TAG_Special ) 100 taga = FPU_Special(a); 101 if ( tagb == TAG_Special ) 102 tagb = FPU_Special(b); 103 104 if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) 105 || ((taga == TW_Denormal) && (tagb == TAG_Valid)) 106 || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) 107 { 108 if ( denormal_operand() < 0 ) 109 return FPU_Exception; 110 111 FPU_to_exp16(a, &x); 112 FPU_to_exp16(b, &y); 113 tag = FPU_u_div(&x, &y, dest, control_w, sign); 114 if ( tag < 0 ) 115 return tag; 116 117 FPU_settagi(deststnr, tag); 118 return tag; 119 } 120 else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) ) 121 { 122 if ( tagb != TAG_Zero ) 123 { 124 /* Want to find Zero/Valid */ 125 if ( tagb == TW_Denormal ) 126 { 127 if ( denormal_operand() < 0 ) 128 return FPU_Exception; 129 } 130 131 /* The result is zero. */ 132 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); 133 setsign(dest, sign); 134 return TAG_Zero; 135 } 136 /* We have an exception condition, either 0/0 or Valid/Zero. */ 137 if ( taga == TAG_Zero ) 138 { 139 /* 0/0 */ 140 return arith_invalid(deststnr); 141 } 142 /* Valid/Zero */ 143 return FPU_divide_by_zero(deststnr, sign); 144 } 145 /* Must have infinities, NaNs, etc */ 146 else if ( (taga == TW_NaN) || (tagb == TW_NaN) ) 147 { 148 if ( flags & LOADED ) 149 return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr); 150 151 if ( flags & DEST_RM ) 152 { 153 int tag; 154 tag = FPU_gettag0(); 155 if ( tag == TAG_Special ) 156 tag = FPU_Special(st0_ptr); 157 return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm)); 158 } 159 else 160 { 161 int tag; 162 tag = FPU_gettagi(rm); 163 if ( tag == TAG_Special ) 164 tag = FPU_Special(&st(rm)); 165 return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm)); 166 } 167 } 168 else if (taga == TW_Infinity) 169 { 170 if (tagb == TW_Infinity) 171 { 172 /* infinity/infinity */ 173 return arith_invalid(deststnr); 174 } 175 else 176 { 177 /* tagb must be Valid or Zero */ 178 if ( (tagb == TW_Denormal) && (denormal_operand() < 0) ) 179 return FPU_Exception; 180 181 /* Infinity divided by Zero or Valid does 182 not raise and exception, but returns Infinity */ 183 FPU_copy_to_regi(a, TAG_Special, deststnr); 184 setsign(dest, sign); 185 return taga; 186 } 187 } 188 else if (tagb == TW_Infinity) 189 { 190 if ( (taga == TW_Denormal) && (denormal_operand() < 0) ) 191 return FPU_Exception; 192 193 /* The result is zero. */ 194 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); 195 setsign(dest, sign); 196 return TAG_Zero; 197 } 198 #ifdef PARANOID 199 else 200 { 201 EXCEPTION(EX_INTERNAL|0x102); 202 return FPU_Exception; 203 } 204 #endif /* PARANOID */ 205 206 return 0; 207 } 208