Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/parisc/math-emu/sfdiv.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/sfdiv.c $Revision: 1.1 $
26
*
27
* Purpose:
28
* Single Precision Floating-point Divide
29
*
30
* External Interfaces:
31
* sgl_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 "sgl_float.h"
44
45
/*
46
* Single Precision Floating-point Divide
47
*/
48
49
int
50
sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
51
sgl_floating_point * dstptr, unsigned int *status)
52
{
53
register unsigned int opnd1, opnd2, opnd3, result;
54
register int dest_exponent, count;
55
register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
56
boolean is_tiny;
57
58
opnd1 = *srcptr1;
59
opnd2 = *srcptr2;
60
/*
61
* set sign bit of result
62
*/
63
if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
64
else Sgl_setzero(result);
65
/*
66
* check first operand for NaN's or infinity
67
*/
68
if (Sgl_isinfinity_exponent(opnd1)) {
69
if (Sgl_iszero_mantissa(opnd1)) {
70
if (Sgl_isnotnan(opnd2)) {
71
if (Sgl_isinfinity(opnd2)) {
72
/*
73
* invalid since both operands
74
* are infinity
75
*/
76
if (Is_invalidtrap_enabled())
77
return(INVALIDEXCEPTION);
78
Set_invalidflag();
79
Sgl_makequietnan(result);
80
*dstptr = result;
81
return(NOEXCEPTION);
82
}
83
/*
84
* return infinity
85
*/
86
Sgl_setinfinity_exponentmantissa(result);
87
*dstptr = result;
88
return(NOEXCEPTION);
89
}
90
}
91
else {
92
/*
93
* is NaN; signaling or quiet?
94
*/
95
if (Sgl_isone_signaling(opnd1)) {
96
/* trap if INVALIDTRAP enabled */
97
if (Is_invalidtrap_enabled())
98
return(INVALIDEXCEPTION);
99
/* make NaN quiet */
100
Set_invalidflag();
101
Sgl_set_quiet(opnd1);
102
}
103
/*
104
* is second operand a signaling NaN?
105
*/
106
else if (Sgl_is_signalingnan(opnd2)) {
107
/* trap if INVALIDTRAP enabled */
108
if (Is_invalidtrap_enabled())
109
return(INVALIDEXCEPTION);
110
/* make NaN quiet */
111
Set_invalidflag();
112
Sgl_set_quiet(opnd2);
113
*dstptr = opnd2;
114
return(NOEXCEPTION);
115
}
116
/*
117
* return quiet NaN
118
*/
119
*dstptr = opnd1;
120
return(NOEXCEPTION);
121
}
122
}
123
/*
124
* check second operand for NaN's or infinity
125
*/
126
if (Sgl_isinfinity_exponent(opnd2)) {
127
if (Sgl_iszero_mantissa(opnd2)) {
128
/*
129
* return zero
130
*/
131
Sgl_setzero_exponentmantissa(result);
132
*dstptr = result;
133
return(NOEXCEPTION);
134
}
135
/*
136
* is NaN; signaling or quiet?
137
*/
138
if (Sgl_isone_signaling(opnd2)) {
139
/* trap if INVALIDTRAP enabled */
140
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
141
/* make NaN quiet */
142
Set_invalidflag();
143
Sgl_set_quiet(opnd2);
144
}
145
/*
146
* return quiet NaN
147
*/
148
*dstptr = opnd2;
149
return(NOEXCEPTION);
150
}
151
/*
152
* check for division by zero
153
*/
154
if (Sgl_iszero_exponentmantissa(opnd2)) {
155
if (Sgl_iszero_exponentmantissa(opnd1)) {
156
/* invalid since both operands are zero */
157
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
158
Set_invalidflag();
159
Sgl_makequietnan(result);
160
*dstptr = result;
161
return(NOEXCEPTION);
162
}
163
if (Is_divisionbyzerotrap_enabled())
164
return(DIVISIONBYZEROEXCEPTION);
165
Set_divisionbyzeroflag();
166
Sgl_setinfinity_exponentmantissa(result);
167
*dstptr = result;
168
return(NOEXCEPTION);
169
}
170
/*
171
* Generate exponent
172
*/
173
dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
174
175
/*
176
* Generate mantissa
177
*/
178
if (Sgl_isnotzero_exponent(opnd1)) {
179
/* set hidden bit */
180
Sgl_clear_signexponent_set_hidden(opnd1);
181
}
182
else {
183
/* check for zero */
184
if (Sgl_iszero_mantissa(opnd1)) {
185
Sgl_setzero_exponentmantissa(result);
186
*dstptr = result;
187
return(NOEXCEPTION);
188
}
189
/* is denormalized; want to normalize */
190
Sgl_clear_signexponent(opnd1);
191
Sgl_leftshiftby1(opnd1);
192
Sgl_normalize(opnd1,dest_exponent);
193
}
194
/* opnd2 needs to have hidden bit set with msb in hidden bit */
195
if (Sgl_isnotzero_exponent(opnd2)) {
196
Sgl_clear_signexponent_set_hidden(opnd2);
197
}
198
else {
199
/* is denormalized; want to normalize */
200
Sgl_clear_signexponent(opnd2);
201
Sgl_leftshiftby1(opnd2);
202
while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
203
Sgl_leftshiftby8(opnd2);
204
dest_exponent += 8;
205
}
206
if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
207
Sgl_leftshiftby4(opnd2);
208
dest_exponent += 4;
209
}
210
while(Sgl_iszero_hidden(opnd2)) {
211
Sgl_leftshiftby1(opnd2);
212
dest_exponent += 1;
213
}
214
}
215
216
/* Divide the source mantissas */
217
218
/*
219
* A non_restoring divide algorithm is used.
220
*/
221
Sgl_subtract(opnd1,opnd2,opnd1);
222
Sgl_setzero(opnd3);
223
for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
224
Sgl_leftshiftby1(opnd1);
225
Sgl_leftshiftby1(opnd3);
226
if (Sgl_iszero_sign(opnd1)) {
227
Sgl_setone_lowmantissa(opnd3);
228
Sgl_subtract(opnd1,opnd2,opnd1);
229
}
230
else Sgl_addition(opnd1,opnd2,opnd1);
231
}
232
if (count <= SGL_P) {
233
Sgl_leftshiftby1(opnd3);
234
Sgl_setone_lowmantissa(opnd3);
235
Sgl_leftshift(opnd3,SGL_P-count);
236
if (Sgl_iszero_hidden(opnd3)) {
237
Sgl_leftshiftby1(opnd3);
238
dest_exponent--;
239
}
240
}
241
else {
242
if (Sgl_iszero_hidden(opnd3)) {
243
/* need to get one more bit of result */
244
Sgl_leftshiftby1(opnd1);
245
Sgl_leftshiftby1(opnd3);
246
if (Sgl_iszero_sign(opnd1)) {
247
Sgl_setone_lowmantissa(opnd3);
248
Sgl_subtract(opnd1,opnd2,opnd1);
249
}
250
else Sgl_addition(opnd1,opnd2,opnd1);
251
dest_exponent--;
252
}
253
if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
254
stickybit = Sgl_all(opnd1);
255
}
256
inexact = guardbit | stickybit;
257
258
/*
259
* round result
260
*/
261
if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
262
Sgl_clear_signexponent(opnd3);
263
switch (Rounding_mode()) {
264
case ROUNDPLUS:
265
if (Sgl_iszero_sign(result))
266
Sgl_increment_mantissa(opnd3);
267
break;
268
case ROUNDMINUS:
269
if (Sgl_isone_sign(result))
270
Sgl_increment_mantissa(opnd3);
271
break;
272
case ROUNDNEAREST:
273
if (guardbit) {
274
if (stickybit || Sgl_isone_lowmantissa(opnd3))
275
Sgl_increment_mantissa(opnd3);
276
}
277
}
278
if (Sgl_isone_hidden(opnd3)) dest_exponent++;
279
}
280
Sgl_set_mantissa(result,opnd3);
281
282
/*
283
* Test for overflow
284
*/
285
if (dest_exponent >= SGL_INFINITY_EXPONENT) {
286
/* trap if OVERFLOWTRAP enabled */
287
if (Is_overflowtrap_enabled()) {
288
/*
289
* Adjust bias of result
290
*/
291
Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
292
*dstptr = result;
293
if (inexact)
294
if (Is_inexacttrap_enabled())
295
return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
296
else Set_inexactflag();
297
return(OVERFLOWEXCEPTION);
298
}
299
Set_overflowflag();
300
/* set result to infinity or largest number */
301
Sgl_setoverflow(result);
302
inexact = TRUE;
303
}
304
/*
305
* Test for underflow
306
*/
307
else if (dest_exponent <= 0) {
308
/* trap if UNDERFLOWTRAP enabled */
309
if (Is_underflowtrap_enabled()) {
310
/*
311
* Adjust bias of result
312
*/
313
Sgl_setwrapped_exponent(result,dest_exponent,unfl);
314
*dstptr = result;
315
if (inexact)
316
if (Is_inexacttrap_enabled())
317
return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
318
else Set_inexactflag();
319
return(UNDERFLOWEXCEPTION);
320
}
321
322
/* Determine if should set underflow flag */
323
is_tiny = TRUE;
324
if (dest_exponent == 0 && inexact) {
325
switch (Rounding_mode()) {
326
case ROUNDPLUS:
327
if (Sgl_iszero_sign(result)) {
328
Sgl_increment(opnd3);
329
if (Sgl_isone_hiddenoverflow(opnd3))
330
is_tiny = FALSE;
331
Sgl_decrement(opnd3);
332
}
333
break;
334
case ROUNDMINUS:
335
if (Sgl_isone_sign(result)) {
336
Sgl_increment(opnd3);
337
if (Sgl_isone_hiddenoverflow(opnd3))
338
is_tiny = FALSE;
339
Sgl_decrement(opnd3);
340
}
341
break;
342
case ROUNDNEAREST:
343
if (guardbit && (stickybit ||
344
Sgl_isone_lowmantissa(opnd3))) {
345
Sgl_increment(opnd3);
346
if (Sgl_isone_hiddenoverflow(opnd3))
347
is_tiny = FALSE;
348
Sgl_decrement(opnd3);
349
}
350
break;
351
}
352
}
353
354
/*
355
* denormalize result or set to signed zero
356
*/
357
stickybit = inexact;
358
Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
359
360
/* return rounded number */
361
if (inexact) {
362
switch (Rounding_mode()) {
363
case ROUNDPLUS:
364
if (Sgl_iszero_sign(result)) {
365
Sgl_increment(opnd3);
366
}
367
break;
368
case ROUNDMINUS:
369
if (Sgl_isone_sign(result)) {
370
Sgl_increment(opnd3);
371
}
372
break;
373
case ROUNDNEAREST:
374
if (guardbit && (stickybit ||
375
Sgl_isone_lowmantissa(opnd3))) {
376
Sgl_increment(opnd3);
377
}
378
break;
379
}
380
if (is_tiny) Set_underflowflag();
381
}
382
Sgl_set_exponentmantissa(result,opnd3);
383
}
384
else Sgl_set_exponent(result,dest_exponent);
385
*dstptr = result;
386
/* check for inexact */
387
if (inexact) {
388
if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
389
else Set_inexactflag();
390
}
391
return(NOEXCEPTION);
392
}
393
394