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