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