Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/parisc/math-emu/dfdiv.c
10817 views
1
/*
2
* Linux/PA-RISC Project (http://www.parisc-linux.org/)
3
*
4
* Floating-point emulation code
5
* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2, or (at your option)
10
* any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
*/
21
/*
22
* BEGIN_DESC
23
*
24
* File:
25
* @(#) pa/spmath/dfdiv.c $Revision: 1.1 $
26
*
27
* Purpose:
28
* Double Precision Floating-point Divide
29
*
30
* External Interfaces:
31
* dbl_fdiv(srcptr1,srcptr2,dstptr,status)
32
*
33
* Internal Interfaces:
34
*
35
* Theory:
36
* <<please update with a overview of the operation of this file>>
37
*
38
* END_DESC
39
*/
40
41
42
#include "float.h"
43
#include "dbl_float.h"
44
45
/*
46
* Double Precision Floating-point Divide
47
*/
48
49
int
50
dbl_fdiv (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
51
dbl_floating_point * dstptr, unsigned int *status)
52
{
53
register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
54
register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
55
register int dest_exponent, count;
56
register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
57
boolean is_tiny;
58
59
Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
60
Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
61
/*
62
* set sign bit of result
63
*/
64
if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
65
Dbl_setnegativezerop1(resultp1);
66
else Dbl_setzerop1(resultp1);
67
/*
68
* check first operand for NaN's or infinity
69
*/
70
if (Dbl_isinfinity_exponent(opnd1p1)) {
71
if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
72
if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
73
if (Dbl_isinfinity(opnd2p1,opnd2p2)) {
74
/*
75
* invalid since both operands
76
* are infinity
77
*/
78
if (Is_invalidtrap_enabled())
79
return(INVALIDEXCEPTION);
80
Set_invalidflag();
81
Dbl_makequietnan(resultp1,resultp2);
82
Dbl_copytoptr(resultp1,resultp2,dstptr);
83
return(NOEXCEPTION);
84
}
85
/*
86
* return infinity
87
*/
88
Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
89
Dbl_copytoptr(resultp1,resultp2,dstptr);
90
return(NOEXCEPTION);
91
}
92
}
93
else {
94
/*
95
* is NaN; signaling or quiet?
96
*/
97
if (Dbl_isone_signaling(opnd1p1)) {
98
/* trap if INVALIDTRAP enabled */
99
if (Is_invalidtrap_enabled())
100
return(INVALIDEXCEPTION);
101
/* make NaN quiet */
102
Set_invalidflag();
103
Dbl_set_quiet(opnd1p1);
104
}
105
/*
106
* is second operand a signaling NaN?
107
*/
108
else if (Dbl_is_signalingnan(opnd2p1)) {
109
/* trap if INVALIDTRAP enabled */
110
if (Is_invalidtrap_enabled())
111
return(INVALIDEXCEPTION);
112
/* make NaN quiet */
113
Set_invalidflag();
114
Dbl_set_quiet(opnd2p1);
115
Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
116
return(NOEXCEPTION);
117
}
118
/*
119
* return quiet NaN
120
*/
121
Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
122
return(NOEXCEPTION);
123
}
124
}
125
/*
126
* check second operand for NaN's or infinity
127
*/
128
if (Dbl_isinfinity_exponent(opnd2p1)) {
129
if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
130
/*
131
* return zero
132
*/
133
Dbl_setzero_exponentmantissa(resultp1,resultp2);
134
Dbl_copytoptr(resultp1,resultp2,dstptr);
135
return(NOEXCEPTION);
136
}
137
/*
138
* is NaN; signaling or quiet?
139
*/
140
if (Dbl_isone_signaling(opnd2p1)) {
141
/* trap if INVALIDTRAP enabled */
142
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
143
/* make NaN quiet */
144
Set_invalidflag();
145
Dbl_set_quiet(opnd2p1);
146
}
147
/*
148
* return quiet NaN
149
*/
150
Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
151
return(NOEXCEPTION);
152
}
153
/*
154
* check for division by zero
155
*/
156
if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
157
if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
158
/* invalid since both operands are zero */
159
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
160
Set_invalidflag();
161
Dbl_makequietnan(resultp1,resultp2);
162
Dbl_copytoptr(resultp1,resultp2,dstptr);
163
return(NOEXCEPTION);
164
}
165
if (Is_divisionbyzerotrap_enabled())
166
return(DIVISIONBYZEROEXCEPTION);
167
Set_divisionbyzeroflag();
168
Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
169
Dbl_copytoptr(resultp1,resultp2,dstptr);
170
return(NOEXCEPTION);
171
}
172
/*
173
* Generate exponent
174
*/
175
dest_exponent = Dbl_exponent(opnd1p1) - Dbl_exponent(opnd2p1) + DBL_BIAS;
176
177
/*
178
* Generate mantissa
179
*/
180
if (Dbl_isnotzero_exponent(opnd1p1)) {
181
/* set hidden bit */
182
Dbl_clear_signexponent_set_hidden(opnd1p1);
183
}
184
else {
185
/* check for zero */
186
if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
187
Dbl_setzero_exponentmantissa(resultp1,resultp2);
188
Dbl_copytoptr(resultp1,resultp2,dstptr);
189
return(NOEXCEPTION);
190
}
191
/* is denormalized, want to normalize */
192
Dbl_clear_signexponent(opnd1p1);
193
Dbl_leftshiftby1(opnd1p1,opnd1p2);
194
Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
195
}
196
/* opnd2 needs to have hidden bit set with msb in hidden bit */
197
if (Dbl_isnotzero_exponent(opnd2p1)) {
198
Dbl_clear_signexponent_set_hidden(opnd2p1);
199
}
200
else {
201
/* is denormalized; want to normalize */
202
Dbl_clear_signexponent(opnd2p1);
203
Dbl_leftshiftby1(opnd2p1,opnd2p2);
204
while (Dbl_iszero_hiddenhigh7mantissa(opnd2p1)) {
205
dest_exponent+=8;
206
Dbl_leftshiftby8(opnd2p1,opnd2p2);
207
}
208
if (Dbl_iszero_hiddenhigh3mantissa(opnd2p1)) {
209
dest_exponent+=4;
210
Dbl_leftshiftby4(opnd2p1,opnd2p2);
211
}
212
while (Dbl_iszero_hidden(opnd2p1)) {
213
dest_exponent++;
214
Dbl_leftshiftby1(opnd2p1,opnd2p2);
215
}
216
}
217
218
/* Divide the source mantissas */
219
220
/*
221
* A non-restoring divide algorithm is used.
222
*/
223
Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
224
Dbl_setzero(opnd3p1,opnd3p2);
225
for (count=1; count <= DBL_P && (opnd1p1 || opnd1p2); count++) {
226
Dbl_leftshiftby1(opnd1p1,opnd1p2);
227
Dbl_leftshiftby1(opnd3p1,opnd3p2);
228
if (Dbl_iszero_sign(opnd1p1)) {
229
Dbl_setone_lowmantissap2(opnd3p2);
230
Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
231
}
232
else {
233
Twoword_add(opnd1p1, opnd1p2, opnd2p1, opnd2p2);
234
}
235
}
236
if (count <= DBL_P) {
237
Dbl_leftshiftby1(opnd3p1,opnd3p2);
238
Dbl_setone_lowmantissap2(opnd3p2);
239
Dbl_leftshift(opnd3p1,opnd3p2,(DBL_P-count));
240
if (Dbl_iszero_hidden(opnd3p1)) {
241
Dbl_leftshiftby1(opnd3p1,opnd3p2);
242
dest_exponent--;
243
}
244
}
245
else {
246
if (Dbl_iszero_hidden(opnd3p1)) {
247
/* need to get one more bit of result */
248
Dbl_leftshiftby1(opnd1p1,opnd1p2);
249
Dbl_leftshiftby1(opnd3p1,opnd3p2);
250
if (Dbl_iszero_sign(opnd1p1)) {
251
Dbl_setone_lowmantissap2(opnd3p2);
252
Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
253
}
254
else {
255
Twoword_add(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
256
}
257
dest_exponent--;
258
}
259
if (Dbl_iszero_sign(opnd1p1)) guardbit = TRUE;
260
stickybit = Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2);
261
}
262
inexact = guardbit | stickybit;
263
264
/*
265
* round result
266
*/
267
if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
268
Dbl_clear_signexponent(opnd3p1);
269
switch (Rounding_mode()) {
270
case ROUNDPLUS:
271
if (Dbl_iszero_sign(resultp1))
272
Dbl_increment(opnd3p1,opnd3p2);
273
break;
274
case ROUNDMINUS:
275
if (Dbl_isone_sign(resultp1))
276
Dbl_increment(opnd3p1,opnd3p2);
277
break;
278
case ROUNDNEAREST:
279
if (guardbit && (stickybit ||
280
Dbl_isone_lowmantissap2(opnd3p2))) {
281
Dbl_increment(opnd3p1,opnd3p2);
282
}
283
}
284
if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
285
}
286
Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
287
288
/*
289
* Test for overflow
290
*/
291
if (dest_exponent >= DBL_INFINITY_EXPONENT) {
292
/* trap if OVERFLOWTRAP enabled */
293
if (Is_overflowtrap_enabled()) {
294
/*
295
* Adjust bias of result
296
*/
297
Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
298
Dbl_copytoptr(resultp1,resultp2,dstptr);
299
if (inexact)
300
if (Is_inexacttrap_enabled())
301
return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
302
else Set_inexactflag();
303
return(OVERFLOWEXCEPTION);
304
}
305
Set_overflowflag();
306
/* set result to infinity or largest number */
307
Dbl_setoverflow(resultp1,resultp2);
308
inexact = TRUE;
309
}
310
/*
311
* Test for underflow
312
*/
313
else if (dest_exponent <= 0) {
314
/* trap if UNDERFLOWTRAP enabled */
315
if (Is_underflowtrap_enabled()) {
316
/*
317
* Adjust bias of result
318
*/
319
Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
320
Dbl_copytoptr(resultp1,resultp2,dstptr);
321
if (inexact)
322
if (Is_inexacttrap_enabled())
323
return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
324
else Set_inexactflag();
325
return(UNDERFLOWEXCEPTION);
326
}
327
328
/* Determine if should set underflow flag */
329
is_tiny = TRUE;
330
if (dest_exponent == 0 && inexact) {
331
switch (Rounding_mode()) {
332
case ROUNDPLUS:
333
if (Dbl_iszero_sign(resultp1)) {
334
Dbl_increment(opnd3p1,opnd3p2);
335
if (Dbl_isone_hiddenoverflow(opnd3p1))
336
is_tiny = FALSE;
337
Dbl_decrement(opnd3p1,opnd3p2);
338
}
339
break;
340
case ROUNDMINUS:
341
if (Dbl_isone_sign(resultp1)) {
342
Dbl_increment(opnd3p1,opnd3p2);
343
if (Dbl_isone_hiddenoverflow(opnd3p1))
344
is_tiny = FALSE;
345
Dbl_decrement(opnd3p1,opnd3p2);
346
}
347
break;
348
case ROUNDNEAREST:
349
if (guardbit && (stickybit ||
350
Dbl_isone_lowmantissap2(opnd3p2))) {
351
Dbl_increment(opnd3p1,opnd3p2);
352
if (Dbl_isone_hiddenoverflow(opnd3p1))
353
is_tiny = FALSE;
354
Dbl_decrement(opnd3p1,opnd3p2);
355
}
356
break;
357
}
358
}
359
360
/*
361
* denormalize result or set to signed zero
362
*/
363
stickybit = inexact;
364
Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
365
stickybit,inexact);
366
367
/* return rounded number */
368
if (inexact) {
369
switch (Rounding_mode()) {
370
case ROUNDPLUS:
371
if (Dbl_iszero_sign(resultp1)) {
372
Dbl_increment(opnd3p1,opnd3p2);
373
}
374
break;
375
case ROUNDMINUS:
376
if (Dbl_isone_sign(resultp1)) {
377
Dbl_increment(opnd3p1,opnd3p2);
378
}
379
break;
380
case ROUNDNEAREST:
381
if (guardbit && (stickybit ||
382
Dbl_isone_lowmantissap2(opnd3p2))) {
383
Dbl_increment(opnd3p1,opnd3p2);
384
}
385
break;
386
}
387
if (is_tiny) Set_underflowflag();
388
}
389
Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
390
}
391
else Dbl_set_exponent(resultp1,dest_exponent);
392
Dbl_copytoptr(resultp1,resultp2,dstptr);
393
394
/* check for inexact */
395
if (inexact) {
396
if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
397
else Set_inexactflag();
398
}
399
return(NOEXCEPTION);
400
}
401
402