1 // SPDX-License-Identifier: GPL-2.0
2 /*---------------------------------------------------------------------------+
5 | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
8 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9 | E-mail billm@jacobi.maths.monash.edu.au |
11 | Return value is the tag of the answer, or-ed with FPU_Exception if |
12 | one was raised, or -1 on internal error. |
14 +---------------------------------------------------------------------------*/
16 /*---------------------------------------------------------------------------+
17 | The destination may be any FPU_REG, including one of the source FPU_REGs. |
18 +---------------------------------------------------------------------------*/
20 #include "exception.h"
21 #include "reg_constant.h"
23 #include "fpu_system.h"
26 Divide one register by another and put the result into a third register.
28 int FPU_div(int flags
, int rm
, int control_w
)
31 FPU_REG
const *a
, *b
, *st0_ptr
, *st_ptr
;
33 u_char taga
, tagb
, signa
, signb
, sign
, saved_sign
;
51 taga
= FPU_gettagi(rm
);
63 tagb
= FPU_gettagi(rm
);
73 saved_sign
= getsign(dest
);
76 /* Both regs Valid, this should be the most common case. */
81 tag
= FPU_u_div(&x
, &y
, dest
, control_w
, sign
);
86 FPU_settagi(deststnr
, tag
);
90 if (taga
== TAG_Special
)
91 taga
= FPU_Special(a
);
92 if (tagb
== TAG_Special
)
93 tagb
= FPU_Special(b
);
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)
103 tag
= FPU_u_div(&x
, &y
, dest
, control_w
, sign
);
107 FPU_settagi(deststnr
, 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
;
117 /* The result is zero. */
118 FPU_copy_to_regi(&CONST_Z
, TAG_Zero
, deststnr
);
122 /* We have an exception condition, either 0/0 or Valid/Zero. */
123 if (taga
== TAG_Zero
) {
125 return arith_invalid(deststnr
);
128 return FPU_divide_by_zero(deststnr
, sign
);
130 /* Must have infinities, NaNs, etc */
131 else if ((taga
== TW_NaN
) || (tagb
== TW_NaN
)) {
133 return real_2op_NaN((FPU_REG
*) rm
, flags
& 0x0f, 0,
136 if (flags
& DEST_RM
) {
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
));
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
));
151 } else if (taga
== TW_Infinity
) {
152 if (tagb
== TW_Infinity
) {
153 /* infinity/infinity */
154 return arith_invalid(deststnr
);
156 /* tagb must be Valid or Zero */
157 if ((tagb
== TW_Denormal
) && (denormal_operand() < 0))
158 return FPU_Exception
;
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
);
166 } else if (tagb
== TW_Infinity
) {
167 if ((taga
== TW_Denormal
) && (denormal_operand() < 0))
168 return FPU_Exception
;
170 /* The result is zero. */
171 FPU_copy_to_regi(&CONST_Z
, TAG_Zero
, deststnr
);
177 EXCEPTION(EX_INTERNAL
| 0x102);
178 return FPU_Exception
;
180 #endif /* PARANOID */