root/arch/x86/math-emu/reg_divide.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. FPU_div

   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   */
  28 int 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 }

/* [<][>][^][v][top][bottom][index][help] */