Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1126 | savelij | 1 | /* ibmfloat.c */ |
2 | /*****************************************************************************/ |
||
3 | /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ |
||
4 | /* */ |
||
5 | /* AS-Portierung */ |
||
6 | /* */ |
||
7 | /* IBM Floating Point Format */ |
||
8 | /* */ |
||
9 | /*****************************************************************************/ |
||
10 | |||
11 | /***************************************************************************** |
||
12 | * Includes |
||
13 | *****************************************************************************/ |
||
14 | |||
15 | #include "stdinc.h" |
||
16 | #include <math.h> |
||
17 | |||
18 | #include "ieeefloat.h" |
||
19 | #include "errmsg.h" |
||
20 | #include "asmerr.h" |
||
21 | #include "ibmfloat.h" |
||
22 | |||
23 | /*!------------------------------------------------------------------------ |
||
24 | * \fn Double2IBMFloat(Word *pDest, double Src, Boolean ToDouble) |
||
25 | * \brief convert floating point number to IBM single precision format |
||
26 | * \param pDest where to write result (2 words) |
||
27 | * \param Src floating point number to store |
||
28 | * \param ToDouble convert to double precision (64 instead of 32 bits)? |
||
29 | * \return True if conversion was successful |
||
30 | * ------------------------------------------------------------------------ */ |
||
31 | |||
32 | #define DBG_FLOAT 0 |
||
33 | |||
34 | Boolean Double2IBMFloat(Word *pDest, double Src, Boolean ToDouble) |
||
35 | { |
||
36 | Word Sign; |
||
37 | Integer Exponent; |
||
38 | LongWord Mantissa, Fraction; |
||
39 | |||
40 | #if DBG_FLOAT |
||
41 | fprintf(stderr, "(0) %lf\n", Src); |
||
42 | #endif |
||
43 | |||
44 | /* (1) Dissect IEEE number */ |
||
45 | |||
46 | ieee8_dissect(&Sign, &Exponent, &Mantissa, &Fraction, Src); |
||
47 | |||
48 | /* (2) Convert IEEE 2^n exponent to multiple of four since IBM float exponent is to the base of 16: */ |
||
49 | |||
50 | while ((Mantissa & 0x10000000ul) || (Exponent & 3)) |
||
51 | { |
||
52 | if (Mantissa & 1) |
||
53 | Fraction |= 0x1000000ul; |
||
54 | Mantissa >>= 1; |
||
55 | Fraction >>= 1; |
||
56 | Exponent++; |
||
57 | } |
||
58 | #if DBG_FLOAT |
||
59 | fprintf(stderr, "(expo4) %2d * 0x%08x * 2^%d Fraction 0x%08x\n", Sign ? -1 : 1, Mantissa, Exponent, Fraction); |
||
60 | #endif |
||
61 | |||
62 | /* (3) make base-16 exponent explicit */ |
||
63 | |||
64 | Exponent /= 4; |
||
65 | #if DBG_FLOAT |
||
66 | fprintf(stderr, "(exp16) %2d * 0x%08x * 16^%d Fraction 0x%08x\n", Sign ? -1 : 1, Mantissa, Exponent, Fraction); |
||
67 | #endif |
||
68 | |||
69 | /* (2a) Round-to-the-nearest for single precision: */ |
||
70 | |||
71 | if (!ToDouble) |
||
72 | { |
||
73 | Boolean RoundUp; |
||
74 | |||
75 | /* Bits 27..4 of mantissa will make it into dest, so the decision bit is bit 3: */ |
||
76 | |||
77 | if (Mantissa & 0x8) /* fraction is >= 0.5 */ |
||
78 | { |
||
79 | if ((Mantissa & 7) || Fraction) /* fraction is > 0.5 -> round up */ |
||
80 | RoundUp = True; |
||
81 | else /* fraction is 0.5 -> round towards even, i.e. round up if mantissa is odd */ |
||
82 | RoundUp = !!(Mantissa & 0x10); |
||
83 | } |
||
84 | else /* fraction is < 0.5 -> round down */ |
||
85 | RoundUp = False; |
||
86 | #if DBG_FLOAT |
||
87 | fprintf(stderr, "RoundUp %u\n", RoundUp); |
||
88 | #endif |
||
89 | if (RoundUp) |
||
90 | { |
||
91 | Mantissa += 16 - (Mantissa & 15); |
||
92 | Fraction = 0; |
||
93 | if (Mantissa & 0x10000000ul) |
||
94 | { |
||
95 | Mantissa >>= 4; |
||
96 | Exponent++; |
||
97 | } |
||
98 | } |
||
99 | #if DBG_FLOAT |
||
100 | fprintf(stderr, "(round) %2d * 0x%08x * 16^%d Fraction 0x%08x\n", Sign ? -1 : 1, Mantissa, Exponent, Fraction); |
||
101 | #endif |
||
102 | } |
||
103 | |||
104 | /* (3a) Overrange? */ |
||
105 | |||
106 | if (Exponent > 63) |
||
107 | { |
||
108 | WrError(ErrNum_OverRange); |
||
109 | return False; |
||
110 | } |
||
111 | else |
||
112 | { |
||
113 | /* (3b) number that is too small may degenerate to 0: */ |
||
114 | |||
115 | while ((Exponent < -64) && Mantissa) |
||
116 | { |
||
117 | Exponent++; Mantissa >>= 4; |
||
118 | } |
||
119 | if (Exponent < -64) |
||
120 | Exponent = -64; |
||
121 | |||
122 | /* (3c) add bias to exponent */ |
||
123 | |||
124 | Exponent += 64; |
||
125 | |||
126 | /* (3d) store result */ |
||
127 | |||
128 | pDest[0] = (Sign << 15) | ((Exponent << 8) & 0x7f00) | ((Mantissa >> 20) & 0xff); |
||
129 | pDest[1] = (Mantissa >> 4) & 0xffff; |
||
130 | |||
131 | /* IBM format has four mantissa bits more than IEEE double, so the 4 LSBs |
||
132 | remain zero: */ |
||
133 | |||
134 | if (ToDouble) |
||
135 | { |
||
136 | pDest[2] = ((Mantissa & 15) << 12) | ((Fraction >> 12) & 0x0fff); |
||
137 | pDest[3] = (Fraction & 0x0fff) << 4; |
||
138 | } |
||
139 | return True; |
||
140 | } |
||
141 | } |