Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*---------------------------------------------------------------------------+
0003  |  reg_divide.c                                                             |
0004  |                                                                           |
0005  | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
0006  |                                                                           |
0007  | Copyright (C) 1996                                                        |
0008  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
0009  |                  E-mail   billm@jacobi.maths.monash.edu.au                |
0010  |                                                                           |
0011  |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
0012  |    one was raised, or -1 on internal error.                               |
0013  |                                                                           |
0014  +---------------------------------------------------------------------------*/
0015 
0016 /*---------------------------------------------------------------------------+
0017  | The destination may be any FPU_REG, including one of the source FPU_REGs. |
0018  +---------------------------------------------------------------------------*/
0019 
0020 #include "exception.h"
0021 #include "reg_constant.h"
0022 #include "fpu_emu.h"
0023 #include "fpu_system.h"
0024 
0025 /*
0026   Divide one register by another and put the result into a third register.
0027   */
0028 int FPU_div(int flags, int rm, int control_w)
0029 {
0030     FPU_REG x, y;
0031     FPU_REG const *a, *b, *st0_ptr, *st_ptr;
0032     FPU_REG *dest;
0033     u_char taga, tagb, signa, signb, sign, saved_sign;
0034     int tag, deststnr;
0035 
0036     if (flags & DEST_RM)
0037         deststnr = rm;
0038     else
0039         deststnr = 0;
0040 
0041     if (flags & REV) {
0042         b = &st(0);
0043         st0_ptr = b;
0044         tagb = FPU_gettag0();
0045         if (flags & LOADED) {
0046             a = (FPU_REG *) rm;
0047             taga = flags & 0x0f;
0048         } else {
0049             a = &st(rm);
0050             st_ptr = a;
0051             taga = FPU_gettagi(rm);
0052         }
0053     } else {
0054         a = &st(0);
0055         st0_ptr = a;
0056         taga = FPU_gettag0();
0057         if (flags & LOADED) {
0058             b = (FPU_REG *) rm;
0059             tagb = flags & 0x0f;
0060         } else {
0061             b = &st(rm);
0062             st_ptr = b;
0063             tagb = FPU_gettagi(rm);
0064         }
0065     }
0066 
0067     signa = getsign(a);
0068     signb = getsign(b);
0069 
0070     sign = signa ^ signb;
0071 
0072     dest = &st(deststnr);
0073     saved_sign = getsign(dest);
0074 
0075     if (!(taga | tagb)) {
0076         /* Both regs Valid, this should be the most common case. */
0077         reg_copy(a, &x);
0078         reg_copy(b, &y);
0079         setpositive(&x);
0080         setpositive(&y);
0081         tag = FPU_u_div(&x, &y, dest, control_w, sign);
0082 
0083         if (tag < 0)
0084             return tag;
0085 
0086         FPU_settagi(deststnr, tag);
0087         return tag;
0088     }
0089 
0090     if (taga == TAG_Special)
0091         taga = FPU_Special(a);
0092     if (tagb == TAG_Special)
0093         tagb = FPU_Special(b);
0094 
0095     if (((taga == TAG_Valid) && (tagb == TW_Denormal))
0096         || ((taga == TW_Denormal) && (tagb == TAG_Valid))
0097         || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
0098         if (denormal_operand() < 0)
0099             return FPU_Exception;
0100 
0101         FPU_to_exp16(a, &x);
0102         FPU_to_exp16(b, &y);
0103         tag = FPU_u_div(&x, &y, dest, control_w, sign);
0104         if (tag < 0)
0105             return tag;
0106 
0107         FPU_settagi(deststnr, tag);
0108         return tag;
0109     } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
0110         if (tagb != TAG_Zero) {
0111             /* Want to find Zero/Valid */
0112             if (tagb == TW_Denormal) {
0113                 if (denormal_operand() < 0)
0114                     return FPU_Exception;
0115             }
0116 
0117             /* The result is zero. */
0118             FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
0119             setsign(dest, sign);
0120             return TAG_Zero;
0121         }
0122         /* We have an exception condition, either 0/0 or Valid/Zero. */
0123         if (taga == TAG_Zero) {
0124             /* 0/0 */
0125             return arith_invalid(deststnr);
0126         }
0127         /* Valid/Zero */
0128         return FPU_divide_by_zero(deststnr, sign);
0129     }
0130     /* Must have infinities, NaNs, etc */
0131     else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
0132         if (flags & LOADED)
0133             return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
0134                         st0_ptr);
0135 
0136         if (flags & DEST_RM) {
0137             int tag;
0138             tag = FPU_gettag0();
0139             if (tag == TAG_Special)
0140                 tag = FPU_Special(st0_ptr);
0141             return real_2op_NaN(st0_ptr, tag, rm,
0142                         (flags & REV) ? st0_ptr : &st(rm));
0143         } else {
0144             int tag;
0145             tag = FPU_gettagi(rm);
0146             if (tag == TAG_Special)
0147                 tag = FPU_Special(&st(rm));
0148             return real_2op_NaN(&st(rm), tag, 0,
0149                         (flags & REV) ? st0_ptr : &st(rm));
0150         }
0151     } else if (taga == TW_Infinity) {
0152         if (tagb == TW_Infinity) {
0153             /* infinity/infinity */
0154             return arith_invalid(deststnr);
0155         } else {
0156             /* tagb must be Valid or Zero */
0157             if ((tagb == TW_Denormal) && (denormal_operand() < 0))
0158                 return FPU_Exception;
0159 
0160             /* Infinity divided by Zero or Valid does
0161                not raise and exception, but returns Infinity */
0162             FPU_copy_to_regi(a, TAG_Special, deststnr);
0163             setsign(dest, sign);
0164             return taga;
0165         }
0166     } else if (tagb == TW_Infinity) {
0167         if ((taga == TW_Denormal) && (denormal_operand() < 0))
0168             return FPU_Exception;
0169 
0170         /* The result is zero. */
0171         FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
0172         setsign(dest, sign);
0173         return TAG_Zero;
0174     }
0175 #ifdef PARANOID
0176     else {
0177         EXCEPTION(EX_INTERNAL | 0x102);
0178         return FPU_Exception;
0179     }
0180 #endif /* PARANOID */
0181 
0182     return 0;
0183 }