You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
2.7 KiB
128 lines
2.7 KiB
#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
|
|
}
|
|
|
|
|