162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* IEEE754 floating point arithmetic 362306a36Sopenharmony_ci * single precision square root 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci/* 662306a36Sopenharmony_ci * MIPS floating point support 762306a36Sopenharmony_ci * Copyright (C) 1994-2000 Algorithmics Ltd. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "ieee754sp.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ciunion ieee754sp ieee754sp_sqrt(union ieee754sp x) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci int ix, s, q, m, t, i; 1562306a36Sopenharmony_ci unsigned int r; 1662306a36Sopenharmony_ci COMPXSP; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci /* take care of Inf and NaN */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci EXPLODEXSP; 2162306a36Sopenharmony_ci ieee754_clearcx(); 2262306a36Sopenharmony_ci FLUSHXSP; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci /* x == INF or NAN? */ 2562306a36Sopenharmony_ci switch (xc) { 2662306a36Sopenharmony_ci case IEEE754_CLASS_SNAN: 2762306a36Sopenharmony_ci return ieee754sp_nanxcpt(x); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci case IEEE754_CLASS_QNAN: 3062306a36Sopenharmony_ci /* sqrt(Nan) = Nan */ 3162306a36Sopenharmony_ci return x; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci case IEEE754_CLASS_ZERO: 3462306a36Sopenharmony_ci /* sqrt(0) = 0 */ 3562306a36Sopenharmony_ci return x; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci case IEEE754_CLASS_INF: 3862306a36Sopenharmony_ci if (xs) { 3962306a36Sopenharmony_ci /* sqrt(-Inf) = Nan */ 4062306a36Sopenharmony_ci ieee754_setcx(IEEE754_INVALID_OPERATION); 4162306a36Sopenharmony_ci return ieee754sp_indef(); 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci /* sqrt(+Inf) = Inf */ 4462306a36Sopenharmony_ci return x; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci case IEEE754_CLASS_DNORM: 4762306a36Sopenharmony_ci case IEEE754_CLASS_NORM: 4862306a36Sopenharmony_ci if (xs) { 4962306a36Sopenharmony_ci /* sqrt(-x) = Nan */ 5062306a36Sopenharmony_ci ieee754_setcx(IEEE754_INVALID_OPERATION); 5162306a36Sopenharmony_ci return ieee754sp_indef(); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ix = x.bits; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* normalize x */ 5962306a36Sopenharmony_ci m = (ix >> 23); 6062306a36Sopenharmony_ci if (m == 0) { /* subnormal x */ 6162306a36Sopenharmony_ci for (i = 0; (ix & 0x00800000) == 0; i++) 6262306a36Sopenharmony_ci ix <<= 1; 6362306a36Sopenharmony_ci m -= i - 1; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci m -= 127; /* unbias exponent */ 6662306a36Sopenharmony_ci ix = (ix & 0x007fffff) | 0x00800000; 6762306a36Sopenharmony_ci if (m & 1) /* odd m, double x to make it even */ 6862306a36Sopenharmony_ci ix += ix; 6962306a36Sopenharmony_ci m >>= 1; /* m = [m/2] */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* generate sqrt(x) bit by bit */ 7262306a36Sopenharmony_ci ix += ix; 7362306a36Sopenharmony_ci s = 0; 7462306a36Sopenharmony_ci q = 0; /* q = sqrt(x) */ 7562306a36Sopenharmony_ci r = 0x01000000; /* r = moving bit from right to left */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci while (r != 0) { 7862306a36Sopenharmony_ci t = s + r; 7962306a36Sopenharmony_ci if (t <= ix) { 8062306a36Sopenharmony_ci s = t + r; 8162306a36Sopenharmony_ci ix -= t; 8262306a36Sopenharmony_ci q += r; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci ix += ix; 8562306a36Sopenharmony_ci r >>= 1; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (ix != 0) { 8962306a36Sopenharmony_ci ieee754_setcx(IEEE754_INEXACT); 9062306a36Sopenharmony_ci switch (ieee754_csr.rm) { 9162306a36Sopenharmony_ci case FPU_CSR_RU: 9262306a36Sopenharmony_ci q += 2; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case FPU_CSR_RN: 9562306a36Sopenharmony_ci q += (q & 1); 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci ix = (q >> 1) + 0x3f000000; 10062306a36Sopenharmony_ci ix += (m << 23); 10162306a36Sopenharmony_ci x.bits = ix; 10262306a36Sopenharmony_ci return x; 10362306a36Sopenharmony_ci} 104