Use new NaN discipline
[riscv-isa-sim.git] / hwacha / cvt16.cc
1 #include "cvt16.h"
2
3 #define H_BIAS (UINT16_C(0xf))
4 #define H_F_MASK (UINT16_C(0x03FF))
5 #define H_E_MASK (UINT16_C(0x7C00))
6 #define H_E_SHIFT (10)
7 #define H_S_MASK (UINT16_C(0x8000))
8
9 #define H_QNAN (H_F_MASK)
10
11 #define S_BIAS (UINT32_C(0x7F))
12 #define S_F_MASK (UINT32_C(0x007fffff))
13 #define S_E_MASK (UINT32_C(0x7f800000))
14 #define S_E_SHIFT (23)
15 #define S_S_MASK (UINT32_C(0x80000000))
16
17 #define S_QNAN (S_F_MASK)
18
19 #define PAD (S_E_SHIFT - H_E_SHIFT)
20
21 uint_fast32_t cvt_hs(uint_fast16_t x)
22 {
23 #define MSB (UINT32_C(0x00800000))
24 uint_fast32_t frac, exp, sign;
25 frac = (x & H_F_MASK) << PAD;
26 exp = (x & H_E_MASK);
27 sign = (x & H_S_MASK);
28
29 switch (exp) {
30 case 0:
31 if (frac) { /* Denormal */
32 exp = S_BIAS - 14;
33 /* Adjust fraction for implicit leading 1-bit */
34 for (; !(frac & MSB); frac <<= 1, exp--);
35 frac &= ~(MSB);
36 exp <<= S_E_SHIFT;
37 }
38 break;
39
40 case H_E_MASK: /* Infinity and NaN */
41 exp = S_E_MASK;
42 if (frac) { /* Set padding bits for NaN */
43 frac |= (1 << PAD) - 1;
44 }
45 break;
46 default:
47 exp += (S_BIAS - H_BIAS) << H_E_SHIFT; /* Re-bias */
48 exp <<= PAD;
49 }
50 return (sign << 16) | exp | frac;
51 #undef MSB
52 }
53
54 enum riscv_rm {
55 RNE = 0, /* Round to nearest; ties to even */
56 RTZ = 1, /* Round towards zero (truncate) */
57 RDN = 2, /* Round towards negative infinity (down) */
58 RUP = 3, /* Round towards positive infinity (up) */
59 RMM = 4, /* Round to nearest; ties to max magnitude */
60 };
61
62 /*
63 * LSB : frac[13]
64 * Guard bit (G): frac[12]
65 * Round bit (R): frac[11]
66 * Sticky bit (S): OR of frac[10..0]
67 *
68 * RTZ:
69 * truncate
70 * RUP:
71 * 000 : exact
72 * else : round up
73 * RDN:
74 * 000 : exact
75 * else : round down
76 * RNE:
77 * 0xx : round down
78 * 100 : tie; round up if LSB is 1
79 * 101 : round up
80 * 110 : round up
81 * 111 : round up
82 */
83 uint_fast16_t cvt_sh(uint_fast32_t x, int rm)
84 {
85 #define MSB UINT16_C(0x0400)
86 uint_fast32_t frac, exp, sign;
87 int e;
88 sign = (x & S_S_MASK) >> 16;
89 exp = (x & S_E_MASK);
90 if (exp && exp != S_E_MASK) {
91 int inc;
92 inc = 0;
93 switch (rm) {
94 case RNE:
95 /* Round up if G is set and either R, S,
96 or the bit before G is non-zero */
97 inc = (x & 0x1000) && (x & 0x2fff);
98 break;
99 case RUP:
100 inc = ((x & 0x1fff) != 0) && (!sign);
101 break;
102 case RDN:
103 inc = ((x & 0x1fff) != 0) && sign;
104 break;
105 }
106 x += inc << PAD;
107 exp = (x & S_E_MASK);
108 }
109 frac = (x & S_F_MASK) >> PAD;
110
111 e = (exp >> S_E_SHIFT) - S_BIAS;
112 if (e < -24) { /* Round to zero */
113 return sign;
114 } else if (e < -14) { /* Denormal */
115 frac = (frac | MSB) >> (-e - 14);
116 return sign | frac;
117 } else if (e < 16) {
118 exp = (e + H_BIAS) << H_E_SHIFT;
119 } else if (e < 127) { /* Round to infinity */
120 exp = H_E_MASK;
121 frac = 0;
122 } else {
123 /* Infinity and NaN */
124 }
125 return sign | exp | frac;
126 #undef MSB
127 }
128