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