0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/compiler.h>
0011
0012 #include "ieee754sp.h"
0013
0014 int ieee754sp_class(union ieee754sp x)
0015 {
0016 COMPXSP;
0017 EXPLODEXSP;
0018 return xc;
0019 }
0020
0021 static inline int ieee754sp_isnan(union ieee754sp x)
0022 {
0023 return ieee754_class_nan(ieee754sp_class(x));
0024 }
0025
0026 static inline int ieee754sp_issnan(union ieee754sp x)
0027 {
0028 int qbit;
0029
0030 assert(ieee754sp_isnan(x));
0031 qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1);
0032 return ieee754_csr.nan2008 ^ qbit;
0033 }
0034
0035
0036
0037
0038
0039
0040 union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r)
0041 {
0042 assert(ieee754sp_issnan(r));
0043
0044 ieee754_setcx(IEEE754_INVALID_OPERATION);
0045 if (ieee754_csr.nan2008) {
0046 SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
0047 } else {
0048 SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1);
0049 if (!ieee754sp_isnan(r))
0050 SPMANT(r) |= SP_MBIT(SP_FBITS - 2);
0051 }
0052
0053 return r;
0054 }
0055
0056 static unsigned int ieee754sp_get_rounding(int sn, unsigned int xm)
0057 {
0058
0059
0060 if (xm & (SP_MBIT(3) - 1)) {
0061 switch (ieee754_csr.rm) {
0062 case FPU_CSR_RZ:
0063 break;
0064 case FPU_CSR_RN:
0065 xm += 0x3 + ((xm >> 3) & 1);
0066
0067 break;
0068 case FPU_CSR_RU:
0069 if (!sn)
0070 xm += 0x8;
0071 break;
0072 case FPU_CSR_RD:
0073 if (sn)
0074 xm += 0x8;
0075 break;
0076 }
0077 }
0078 return xm;
0079 }
0080
0081
0082
0083
0084
0085
0086
0087 union ieee754sp ieee754sp_format(int sn, int xe, unsigned int xm)
0088 {
0089 assert(xm);
0090
0091 assert((xm >> (SP_FBITS + 1 + 3)) == 0);
0092 assert(xm & (SP_HIDDEN_BIT << 3));
0093
0094 if (xe < SP_EMIN) {
0095
0096 int es = SP_EMIN - xe;
0097
0098 if (ieee754_csr.nod) {
0099 ieee754_setcx(IEEE754_UNDERFLOW);
0100 ieee754_setcx(IEEE754_INEXACT);
0101
0102 switch(ieee754_csr.rm) {
0103 case FPU_CSR_RN:
0104 case FPU_CSR_RZ:
0105 return ieee754sp_zero(sn);
0106 case FPU_CSR_RU:
0107 if (sn == 0)
0108 return ieee754sp_min(0);
0109 else
0110 return ieee754sp_zero(1);
0111 case FPU_CSR_RD:
0112 if (sn == 0)
0113 return ieee754sp_zero(0);
0114 else
0115 return ieee754sp_min(1);
0116 }
0117 }
0118
0119 if (xe == SP_EMIN - 1 &&
0120 ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3))
0121 {
0122
0123 ieee754_setcx(IEEE754_INEXACT);
0124 xm = ieee754sp_get_rounding(sn, xm);
0125 xm >>= 1;
0126
0127 xm &= ~(SP_MBIT(3) - 1);
0128 xe++;
0129 } else {
0130
0131
0132 xm = XSPSRS(xm, es);
0133 xe += es;
0134 assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
0135 assert(xe == SP_EMIN);
0136 }
0137 }
0138 if (xm & (SP_MBIT(3) - 1)) {
0139 ieee754_setcx(IEEE754_INEXACT);
0140 if ((xm & (SP_HIDDEN_BIT << 3)) == 0) {
0141 ieee754_setcx(IEEE754_UNDERFLOW);
0142 }
0143
0144
0145
0146 xm = ieee754sp_get_rounding(sn, xm);
0147
0148
0149 if (xm >> (SP_FBITS + 1 + 3)) {
0150
0151 xm >>= 1;
0152 xe++;
0153 }
0154 }
0155
0156 xm >>= 3;
0157
0158 assert((xm >> (SP_FBITS + 1)) == 0);
0159 assert(xe >= SP_EMIN);
0160
0161 if (xe > SP_EMAX) {
0162 ieee754_setcx(IEEE754_OVERFLOW);
0163 ieee754_setcx(IEEE754_INEXACT);
0164
0165 switch (ieee754_csr.rm) {
0166 case FPU_CSR_RN:
0167 return ieee754sp_inf(sn);
0168 case FPU_CSR_RZ:
0169 return ieee754sp_max(sn);
0170 case FPU_CSR_RU:
0171 if (sn == 0)
0172 return ieee754sp_inf(0);
0173 else
0174 return ieee754sp_max(1);
0175 case FPU_CSR_RD:
0176 if (sn == 0)
0177 return ieee754sp_max(0);
0178 else
0179 return ieee754sp_inf(1);
0180 }
0181 }
0182
0183
0184 if ((xm & SP_HIDDEN_BIT) == 0) {
0185
0186 assert(xe == SP_EMIN);
0187 if (ieee754_csr.mx & IEEE754_UNDERFLOW)
0188 ieee754_setcx(IEEE754_UNDERFLOW);
0189 return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
0190 } else {
0191 assert((xm >> (SP_FBITS + 1)) == 0);
0192 assert(xm & SP_HIDDEN_BIT);
0193
0194 return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
0195 }
0196 }