1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 1988,2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* Utility functions for Sparc FPU simulator. */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h> 32*0Sstevel@tonic-gate #include <sys/fpu/globals.h> 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate void 35*0Sstevel@tonic-gate _fp_read_vfreg( 36*0Sstevel@tonic-gate FPU_REGS_TYPE *pf, /* Old freg value. */ 37*0Sstevel@tonic-gate uint_t n, /* Want to read register n. */ 38*0Sstevel@tonic-gate fp_simd_type *pfpsd) 39*0Sstevel@tonic-gate { 40*0Sstevel@tonic-gate *pf = pfpsd->fp_current_pfregs->fpu_fr.fpu_regs[n]; 41*0Sstevel@tonic-gate } 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate void 44*0Sstevel@tonic-gate _fp_write_vfreg( 45*0Sstevel@tonic-gate FPU_REGS_TYPE *pf, /* New freg value. */ 46*0Sstevel@tonic-gate uint_t n, /* Want to read register n. */ 47*0Sstevel@tonic-gate fp_simd_type *pfpsd) 48*0Sstevel@tonic-gate { 49*0Sstevel@tonic-gate pfpsd->fp_current_pfregs->fpu_fr.fpu_regs[n] = *pf; 50*0Sstevel@tonic-gate } 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate void 53*0Sstevel@tonic-gate _fp_read_vdreg( 54*0Sstevel@tonic-gate FPU_DREGS_TYPE *pd, /* Old dreg value. */ 55*0Sstevel@tonic-gate uint_t n, /* Want to read register n. */ 56*0Sstevel@tonic-gate fp_simd_type *pfpsd) 57*0Sstevel@tonic-gate { 58*0Sstevel@tonic-gate *pd = pfpsd->fp_current_pfregs->fpu_fr.fpu_dregs[n]; 59*0Sstevel@tonic-gate } 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate void 62*0Sstevel@tonic-gate _fp_write_vdreg( 63*0Sstevel@tonic-gate FPU_DREGS_TYPE *pd, /* New dreg value. */ 64*0Sstevel@tonic-gate uint_t n, /* Want to read register n. */ 65*0Sstevel@tonic-gate fp_simd_type *pfpsd) 66*0Sstevel@tonic-gate { 67*0Sstevel@tonic-gate pfpsd->fp_current_pfregs->fpu_fr.fpu_dregs[n] = *pd; 68*0Sstevel@tonic-gate } 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate /* 71*0Sstevel@tonic-gate * Normalize a number. Does not affect zeros, infs, or NaNs. 72*0Sstevel@tonic-gate * The number will be normalized to 113 bit extended: 73*0Sstevel@tonic-gate * 0x0001####, 0x########, 0x########, 0x########. 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate void 76*0Sstevel@tonic-gate fpu_normalize(unpacked *pu) 77*0Sstevel@tonic-gate { 78*0Sstevel@tonic-gate uint_t U, u0, u1, u2, u3, m, n, k; 79*0Sstevel@tonic-gate u0 = pu->significand[0]; 80*0Sstevel@tonic-gate u1 = pu->significand[1]; 81*0Sstevel@tonic-gate u2 = pu->significand[2]; 82*0Sstevel@tonic-gate u3 = pu->significand[3]; 83*0Sstevel@tonic-gate if ((*pu).fpclass == fp_normal) { 84*0Sstevel@tonic-gate if ((u0|u1|u2|u3) == 0) { 85*0Sstevel@tonic-gate (*pu).fpclass = fp_zero; 86*0Sstevel@tonic-gate return; 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate while (u0 == 0) { 89*0Sstevel@tonic-gate u0 = u1; u1 = u2; u2 = u3; u3 = 0; 90*0Sstevel@tonic-gate (*pu).exponent = (*pu).exponent - 32; 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate if (u0 >= 0x20000) { /* u3 should be zero */ 93*0Sstevel@tonic-gate n = 1; U = u0 >> 1; 94*0Sstevel@tonic-gate while (U >= 0x20000) { 95*0Sstevel@tonic-gate U >>= 1; 96*0Sstevel@tonic-gate n += 1; 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate m = (1 << n)-1; 99*0Sstevel@tonic-gate k = 32-n; 100*0Sstevel@tonic-gate (*pu).exponent += n; 101*0Sstevel@tonic-gate u3 = ((u2&m)<<k)|(u3>>n); 102*0Sstevel@tonic-gate u2 = ((u1&m)<<k)|(u2>>n); 103*0Sstevel@tonic-gate u1 = ((u0&m)<<k)|(u1>>n); 104*0Sstevel@tonic-gate u0 = U; 105*0Sstevel@tonic-gate } else if (u0 < 0x10000) { 106*0Sstevel@tonic-gate n = 1; U = u0 << 1; 107*0Sstevel@tonic-gate while (U < 0x10000) { 108*0Sstevel@tonic-gate U <<= 1; 109*0Sstevel@tonic-gate n += 1; 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate k = 32-n; 112*0Sstevel@tonic-gate m = -(1 << k); 113*0Sstevel@tonic-gate (*pu).exponent -= n; 114*0Sstevel@tonic-gate u0 = (u0<<n)|((u1&m)>>k); 115*0Sstevel@tonic-gate u1 = (u1<<n)|((u2&m)>>k); 116*0Sstevel@tonic-gate u2 = (u2<<n)|((u3&m)>>k); 117*0Sstevel@tonic-gate u3 = (u3<<n); 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate pu->significand[0] = u0; 120*0Sstevel@tonic-gate pu->significand[1] = u1; 121*0Sstevel@tonic-gate pu->significand[2] = u2; 122*0Sstevel@tonic-gate pu->significand[3] = u3; 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate /* 127*0Sstevel@tonic-gate * Right shift significand sticky by n bits. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate void 130*0Sstevel@tonic-gate fpu_rightshift(unpacked *pu, int n) 131*0Sstevel@tonic-gate { 132*0Sstevel@tonic-gate uint_t m, k, j, u0, u1, u2, u3; 133*0Sstevel@tonic-gate if (n > 113) { /* drastic */ 134*0Sstevel@tonic-gate if (((*pu).significand[0] | (*pu).significand[1] 135*0Sstevel@tonic-gate | (*pu).significand[2] | (*pu).significand[3]) == 0) { 136*0Sstevel@tonic-gate /* really zero */ 137*0Sstevel@tonic-gate pu->fpclass = fp_zero; 138*0Sstevel@tonic-gate return; 139*0Sstevel@tonic-gate } else { 140*0Sstevel@tonic-gate pu->rounded = 0; 141*0Sstevel@tonic-gate pu->sticky = 1; 142*0Sstevel@tonic-gate pu->significand[3] = 0; 143*0Sstevel@tonic-gate pu->significand[2] = 0; 144*0Sstevel@tonic-gate pu->significand[1] = 0; 145*0Sstevel@tonic-gate pu->significand[0] = 0; 146*0Sstevel@tonic-gate return; 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate while (n >= 32) { /* big shift */ 150*0Sstevel@tonic-gate pu->sticky |= pu->rounded | (pu->significand[3]&0x7fffffff); 151*0Sstevel@tonic-gate pu->rounded = (*pu).significand[3] >> 31; 152*0Sstevel@tonic-gate (*pu).significand[3] = (*pu).significand[2]; 153*0Sstevel@tonic-gate (*pu).significand[2] = (*pu).significand[1]; 154*0Sstevel@tonic-gate (*pu).significand[1] = (*pu).significand[0]; 155*0Sstevel@tonic-gate (*pu).significand[0] = 0; 156*0Sstevel@tonic-gate n -= 32; 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate if (n > 0) { /* small shift */ 159*0Sstevel@tonic-gate u0 = pu->significand[0]; 160*0Sstevel@tonic-gate u1 = pu->significand[1]; 161*0Sstevel@tonic-gate u2 = pu->significand[2]; 162*0Sstevel@tonic-gate u3 = pu->significand[3]; 163*0Sstevel@tonic-gate m = (1<<n)-1; 164*0Sstevel@tonic-gate k = 32 - n; 165*0Sstevel@tonic-gate j = (1<<(n-1))-1; 166*0Sstevel@tonic-gate pu->sticky |= pu->rounded | (u3&j); 167*0Sstevel@tonic-gate pu->rounded = (u3&m)>>(n-1); 168*0Sstevel@tonic-gate pu->significand[3] = ((u2&m)<<k)|(u3>>n); 169*0Sstevel@tonic-gate pu->significand[2] = ((u1&m)<<k)|(u2>>n); 170*0Sstevel@tonic-gate pu->significand[1] = ((u0&m)<<k)|(u1>>n); 171*0Sstevel@tonic-gate pu->significand[0] = u0>>n; 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* 177*0Sstevel@tonic-gate * Set the exception bit in the current exception register. 178*0Sstevel@tonic-gate */ 179*0Sstevel@tonic-gate void 180*0Sstevel@tonic-gate fpu_set_exception(pfpsd, ex) 181*0Sstevel@tonic-gate fp_simd_type *pfpsd; /* Pointer to simulator data */ 182*0Sstevel@tonic-gate enum fp_exception_type ex; 183*0Sstevel@tonic-gate { 184*0Sstevel@tonic-gate pfpsd->fp_current_exceptions |= 1 << (int)ex; 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * Set invalid exception and error nan in *pu 189*0Sstevel@tonic-gate */ 190*0Sstevel@tonic-gate void 191*0Sstevel@tonic-gate fpu_error_nan(pfpsd, pu) 192*0Sstevel@tonic-gate fp_simd_type *pfpsd; /* Pointer to simulator data */ 193*0Sstevel@tonic-gate unpacked *pu; 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate fpu_set_exception(pfpsd, fp_invalid); 196*0Sstevel@tonic-gate pu->sign = 0; 197*0Sstevel@tonic-gate pu->significand[0] = 0x7fffffff; 198*0Sstevel@tonic-gate pu->significand[1] = 0xffffffffUL; 199*0Sstevel@tonic-gate pu->significand[2] = 0xffffffffUL; 200*0Sstevel@tonic-gate pu->significand[3] = 0xffffffffUL; 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* 204*0Sstevel@tonic-gate * the following fpu_add3wc should be inlined as 205*0Sstevel@tonic-gate * .inline _fpu_add3wc, 3 206*0Sstevel@tonic-gate * ld [%o1], %o4 ! sum = x 207*0Sstevel@tonic-gate * addcc -1, %o3, %g0 ! restore last carry in cc reg 208*0Sstevel@tonic-gate * addxcc %o4, %o2, %o4 ! sum = sum + y + last carry 209*0Sstevel@tonic-gate * st %o4, [%o0] ! *z = sum 210*0Sstevel@tonic-gate * addx %g0, %g0, %o0 ! return new carry 211*0Sstevel@tonic-gate * .end 212*0Sstevel@tonic-gate */ 213*0Sstevel@tonic-gate uint_t 214*0Sstevel@tonic-gate fpu_add3wc(uint_t *z, uint_t x, uint_t y, uint_t carry) 215*0Sstevel@tonic-gate { /* *z = x + y + carry, set carry; */ 216*0Sstevel@tonic-gate if (carry == 0) { 217*0Sstevel@tonic-gate *z = x+y; 218*0Sstevel@tonic-gate return (*z < y); 219*0Sstevel@tonic-gate } else { 220*0Sstevel@tonic-gate *z = x+y+1; 221*0Sstevel@tonic-gate return (*z <= y); 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate /* 226*0Sstevel@tonic-gate * The following fpu_sub3wc should be inlined as 227*0Sstevel@tonic-gate * .inline _fpu_sub3wc, 3 228*0Sstevel@tonic-gate * ld [%o1], %o4 ! sum = *x 229*0Sstevel@tonic-gate * addcc -1, %o3, %g0 ! restore last carry in cc reg 230*0Sstevel@tonic-gate * subxcc %o4, %o2, %o4 ! sum = sum - y - last carry 231*0Sstevel@tonic-gate * st %o4, [%o0] ! *x = sum 232*0Sstevel@tonic-gate * addx %g0, %g0, %o0 ! return new carry 233*0Sstevel@tonic-gate * .end 234*0Sstevel@tonic-gate */ 235*0Sstevel@tonic-gate uint_t 236*0Sstevel@tonic-gate fpu_sub3wc(uint_t *z, uint_t x, uint_t y, uint_t carry) 237*0Sstevel@tonic-gate { /* *z = x - y - carry, set carry; */ 238*0Sstevel@tonic-gate if (carry == 0) { 239*0Sstevel@tonic-gate *z = x-y; 240*0Sstevel@tonic-gate return (*z > x); 241*0Sstevel@tonic-gate } else { 242*0Sstevel@tonic-gate *z = x-y-1; 243*0Sstevel@tonic-gate return (*z >= x); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * the following fpu_neg2wc should be inlined as 249*0Sstevel@tonic-gate * .inline _fpu_neg2wc, 2 250*0Sstevel@tonic-gate * ld [%o1], %o3 ! tmp = *x 251*0Sstevel@tonic-gate * addcc -1, %o2, %g0 ! restore last carry in cc reg 252*0Sstevel@tonic-gate * subxcc %g0, %o3, %o3 ! sum = 0 - tmp - last carry 253*0Sstevel@tonic-gate * st %o3, [%o0] ! *x = sum 254*0Sstevel@tonic-gate * addx %g0, %g0, %o0 ! return new carry 255*0Sstevel@tonic-gate * .end 256*0Sstevel@tonic-gate */ 257*0Sstevel@tonic-gate uint_t 258*0Sstevel@tonic-gate fpu_neg2wc(uint_t *z, uint_t x, uint_t carry) 259*0Sstevel@tonic-gate { /* *x = 0 - *x - carry, set carry; */ 260*0Sstevel@tonic-gate if (carry == 0) { 261*0Sstevel@tonic-gate *z = -x; 262*0Sstevel@tonic-gate return ((*z) != 0); 263*0Sstevel@tonic-gate } else { 264*0Sstevel@tonic-gate *z = -x-1; 265*0Sstevel@tonic-gate return (1); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate int 270*0Sstevel@tonic-gate fpu_cmpli(uint_t *x, uint_t *y, int n) 271*0Sstevel@tonic-gate { /* compare two uint_t array */ 272*0Sstevel@tonic-gate int i; 273*0Sstevel@tonic-gate i = 0; 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate while (i < n) { 276*0Sstevel@tonic-gate if (x[i] > y[i]) 277*0Sstevel@tonic-gate return (1); 278*0Sstevel@tonic-gate else if (x[i] < y[i]) 279*0Sstevel@tonic-gate return (-1); 280*0Sstevel@tonic-gate i++; 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate return (0); 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate #ifdef DEBUG 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate #include <sys/cmn_err.h> 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* 290*0Sstevel@tonic-gate * Print out unpacked record. 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate void 293*0Sstevel@tonic-gate display_unpacked(pu) 294*0Sstevel@tonic-gate unpacked *pu; 295*0Sstevel@tonic-gate { 296*0Sstevel@tonic-gate (void) printf(" unpacked "); 297*0Sstevel@tonic-gate if (pu->sign) 298*0Sstevel@tonic-gate (void) printf("-"); 299*0Sstevel@tonic-gate else 300*0Sstevel@tonic-gate (void) printf("+"); 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate switch (pu->fpclass) { 303*0Sstevel@tonic-gate case fp_zero: 304*0Sstevel@tonic-gate (void) printf("0 "); 305*0Sstevel@tonic-gate break; 306*0Sstevel@tonic-gate case fp_normal: 307*0Sstevel@tonic-gate (void) printf("normal"); 308*0Sstevel@tonic-gate break; 309*0Sstevel@tonic-gate case fp_infinity: 310*0Sstevel@tonic-gate (void) printf("Inf "); 311*0Sstevel@tonic-gate break; 312*0Sstevel@tonic-gate case fp_quiet: 313*0Sstevel@tonic-gate case fp_signaling: 314*0Sstevel@tonic-gate (void) printf("nan "); 315*0Sstevel@tonic-gate break; 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate (void) printf(" %X %X %X %X (%X, %X) exponent %X \n", 318*0Sstevel@tonic-gate pu->significand[0], pu->significand[1], pu->significand[2], 319*0Sstevel@tonic-gate pu->significand[3], (pu->rounded != 0), 320*0Sstevel@tonic-gate (pu->sticky != 0), pu->exponent); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate #endif 323