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