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