Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     23 
     24 /*
     25  * Copyright (c) 1988 by Sun Microsystems, Inc.
     26  */
     27 
     28 /* Pack procedures for Sparc FPU simulator. */
     29 
     30 #include "_Qquad.h"
     31 #include "_Qglobals.h"
     32 
     33 PRIVATE int
     34 overflow_to_infinity(sign)
     35 	int             sign;
     36 
     37 /* Returns 1 if overflow should go to infinity, 0 if to max finite. */
     38 
     39 {
     40 	int             inf;
     41 
     42 	switch (fp_direction) {
     43 	case fp_nearest:
     44 		inf = 1;
     45 		break;
     46 	case fp_tozero:
     47 		inf = 0;
     48 		break;
     49 	case fp_positive:
     50 		inf = !sign;
     51 		break;
     52 	case fp_negative:
     53 		inf = sign;
     54 		break;
     55 	}
     56 	return (inf);
     57 }
     58 
     59 PRIVATE void
     60 round(pu)
     61 	unpacked       *pu;
     62 
     63 /* Round according to current rounding mode.	 */
     64 
     65 {
     66 	int             increment;	/* boolean to indicate round up */
     67 	int sr;
     68 	sr = pu->sticky|pu->rounded;
     69 
     70 	if (sr == 0)
     71 		return;
     72 	fpu_set_exception(fp_inexact);
     73 	switch (fp_direction) {
     74 	case fp_nearest:
     75 		increment = pu->rounded;
     76 		break;
     77 	case fp_tozero:
     78 		increment = 0;
     79 		break;
     80 	case fp_positive:
     81 		increment = (pu->sign == 0) & (sr != 0);
     82 		break;
     83 	case fp_negative:
     84 		increment = (pu->sign != 0) & (sr != 0);
     85 		break;
     86 	}
     87 	if (increment) {
     88 	    pu->significand[3]++;
     89 	    if (pu->significand[3] == 0) {
     90 		pu->significand[2]++;
     91 		if (pu->significand[2] == 0) {
     92 		    pu->significand[1]++;
     93 		    if (pu->significand[1] == 0) {
     94 			pu->significand[0]++;	/* rounding carried out */
     95 			if( pu->significand[0] == 0x20000) {
     96 			    pu->exponent++;
     97 			    pu->significand[0] = 0x10000;
     98 			}
     99 		    }
    100 		}
    101 	    }
    102 	}
    103 	if ((fp_direction == fp_nearest) &&
    104 		(pu->sticky == 0) && increment!=0) {	/* ambiguous case */
    105 		pu->significand[3] &= 0xfffffffe;	/* force round to even */
    106 	}
    107 }
    108 
    109 PRIVATE void
    110 packinteger(pu, px)
    111 	unpacked       *pu;	/* unpacked result */
    112 	int            *px;	/* packed integer */
    113 {
    114 	switch (pu->fpclass) {
    115 	case fp_zero:
    116 		*px = 0;
    117 		break;
    118 	case fp_normal:
    119 		if (pu->exponent >= 32)
    120 			goto overflow;
    121 		fpu_rightshift(pu, 112 - pu->exponent);
    122 		round(pu);
    123 		if (pu->significand[3] >= 0x80000000)
    124 			if ((pu->sign == 0)||(pu->significand[3] > 0x80000000))
    125 				goto overflow;
    126 		*px = pu->significand[3];
    127 		if (pu->sign)
    128 			*px = -*px;
    129 		break;
    130 	case fp_infinity:
    131 	case fp_quiet:
    132 	case fp_signaling:
    133 overflow:
    134 		if (pu->sign)
    135 			*px = 0x80000000;
    136 		else
    137 			*px = 0x7fffffff;
    138 		_fp_current_exceptions &= ~(1 << (int) fp_inexact);
    139 		fpu_set_exception(fp_invalid);
    140 		break;
    141 	}
    142 }
    143 
    144 PRIVATE void
    145 packsingle(pu, px)
    146 	unpacked       *pu;	/* unpacked result */
    147 	single_type    *px;	/* packed single */
    148 {
    149 	px->sign = pu->sign;
    150 	switch (pu->fpclass) {
    151 	case fp_zero:
    152 		px->exponent = 0;
    153 		px->significand = 0;
    154 		break;
    155 	case fp_infinity:
    156 infinity:
    157 		px->exponent = 0xff;
    158 		px->significand = 0;
    159 		break;
    160 	case fp_quiet:
    161 	case fp_signaling:
    162 		fpu_rightshift(pu, 113-24);
    163 		px->exponent = 0xff;
    164 		px->significand = 0x400000|(0x3fffff&pu->significand[3]);
    165 		break;
    166 	case fp_normal:
    167 		fpu_rightshift(pu, 113-24);
    168 		pu->exponent += SINGLE_BIAS;
    169 		if (pu->exponent <= 0) {
    170 			px->exponent = 0;
    171 			fpu_rightshift(pu, 1 - pu->exponent);
    172 			round(pu);
    173 			if (pu->significand[3] == 0x800000) {	/* rounded
    174 								 * back up to
    175 								 * normal */
    176 				px->exponent = 1;
    177 				px->significand = 0;
    178 				return;
    179 			}
    180 			if (_fp_current_exceptions & (1 << fp_inexact))
    181 				fpu_set_exception(fp_underflow);
    182 			px->significand = 0x7fffff & pu->significand[3];
    183 			return;
    184 		}
    185 		round(pu);
    186 		if (pu->significand[3] == 0x1000000) {	/* rounding overflow */
    187 			pu->significand[3] = 0x800000;
    188 			pu->exponent += 1;
    189 		}
    190 		if (pu->exponent >= 0xff) {
    191 			fpu_set_exception(fp_overflow);
    192 			fpu_set_exception(fp_inexact);
    193 			if (overflow_to_infinity(pu->sign))
    194 				goto infinity;
    195 			px->exponent = 0xfe;
    196 			px->significand = 0x7fffff;
    197 			return;
    198 		}
    199 		px->exponent = pu->exponent;
    200 		px->significand = 0x7fffff & pu->significand[3];
    201 	}
    202 }
    203 
    204 PRIVATE void
    205 packdouble(pu, px, py)
    206 	unpacked       *pu;	/* unpacked result */
    207 	double_type    *px;	/* packed double */
    208 	unsigned       *py;
    209 {
    210 	px->sign = pu->sign;
    211 	switch (pu->fpclass) {
    212 	case fp_zero:
    213 		px->exponent = 0;
    214 		px->significand = 0;
    215 		*py = 0;
    216 		break;
    217 	case fp_infinity:
    218 infinity:
    219 		px->exponent = 0x7ff;
    220 		px->significand = 0;
    221 		*py = 0;
    222 		break;
    223 	case fp_quiet:
    224 	case fp_signaling:
    225 		fpu_rightshift(pu, 113-53);
    226 		px->exponent = 0x7ff;
    227 		px->significand = 0x80000 | (0x7ffff & pu->significand[2]);
    228 		*py = pu->significand[3];
    229 		break;
    230 	case fp_normal:
    231 		fpu_rightshift(pu, 113-53);
    232 		pu->exponent += DOUBLE_BIAS;
    233 		if (pu->exponent <= 0) {	/* underflow */
    234 			px->exponent = 0;
    235 			fpu_rightshift(pu, 1 - pu->exponent);
    236 			round(pu);
    237 			if (pu->significand[2] == 0x100000) {	/* rounded
    238 								 * back up to
    239 								 * normal */
    240 				px->exponent = 1;
    241 				px->significand = 0;
    242 				*py = 0;
    243 				return;
    244 			}
    245 			if (_fp_current_exceptions & (1 << fp_inexact))
    246 				fpu_set_exception(fp_underflow);
    247 			px->exponent = 0;
    248 			px->significand = 0xfffff & pu->significand[2];
    249 			*py = pu->significand[3];
    250 			return;
    251 		}
    252 		round(pu);
    253 		if (pu->significand[2] == 0x200000) {	/* rounding overflow */
    254 			pu->significand[2] = 0x100000;
    255 			pu->exponent += 1;
    256 		}
    257 		if (pu->exponent >= 0x7ff) {	/* overflow */
    258 			fpu_set_exception(fp_overflow);
    259 			fpu_set_exception(fp_inexact);
    260 			if (overflow_to_infinity(pu->sign))
    261 				goto infinity;
    262 			px->exponent = 0x7fe;
    263 			px->significand = 0xfffff;
    264 			*py = 0xffffffff;
    265 			return;
    266 		}
    267 		px->exponent = pu->exponent;
    268 		px->significand = 0xfffff & pu->significand[2];
    269 		*py = pu->significand[3];
    270 		break;
    271 	}
    272 }
    273 
    274 PRIVATE void
    275 packextended(pu, px, py, pz, pw)
    276 	unpacked       *pu;	/* unpacked result */
    277 	extended_type  *px;	/* packed extended */
    278 	unsigned       *py, *pz, *pw;
    279 {
    280 	px->sign = pu->sign;
    281 	switch (pu->fpclass) {
    282 	case fp_zero:
    283 		px->exponent = 0;
    284 		px->significand = 0;
    285 		*pz = 0;
    286 		*py = 0;
    287 		*pw = 0;
    288 		break;
    289 	case fp_infinity:
    290 infinity:
    291 		px->exponent = 0x7fff;
    292 		px->significand = 0;
    293 		*pz = 0;
    294 		*py = 0;
    295 		*pw = 0;
    296 		break;
    297 	case fp_quiet:
    298 	case fp_signaling:
    299 		px->exponent = 0x7fff;
    300 		px->significand = 0x8000 | pu->significand[0];	/* Insure quiet
    301 								 * nan. */
    302 		*py = pu->significand[1];
    303 		*pz = pu->significand[2];
    304 		*pw = pu->significand[3];
    305 		break;
    306 	case fp_normal:
    307 		pu->exponent += EXTENDED_BIAS;
    308 		if (pu->exponent <= 0) {	/* underflow */
    309 			fpu_rightshift(pu, 1-pu->exponent);
    310 			round(pu);
    311 			if (pu->significand[0] < 0x00010000) {	/* not rounded
    312 								 * back up
    313 								 * to normal */
    314 				if (_fp_current_exceptions & (1 << fp_inexact))
    315 					fpu_set_exception(fp_underflow);
    316 				px->exponent = 0;
    317 			} else
    318 				px->exponent = 1;
    319 			px->significand = pu->significand[0];
    320 			*py = pu->significand[1];
    321 			*pz = pu->significand[2];
    322 			*pw = pu->significand[3];
    323 			return;
    324 		}
    325 		round(pu);	/* rounding overflow handled in round() */
    326 		if (pu->exponent >= 0x7fff) {	/* overflow */
    327 			fpu_set_exception(fp_overflow);
    328 			fpu_set_exception(fp_inexact);
    329 			if (overflow_to_infinity(pu->sign))
    330 				goto infinity;
    331 			px->exponent = 0x7ffe;	/* overflow to max norm */
    332 			px->significand = 0xffff;
    333 			*py = 0xffffffff;
    334 			*pz = 0xffffffff;
    335 			*pw = 0xffffffff;
    336 			return;
    337 		}
    338 		px->exponent = pu->exponent;
    339 		px->significand = pu->significand[0];
    340 		*py = pu->significand[1];
    341 		*pz = pu->significand[2];
    342 		*pw = pu->significand[3];
    343 		break;
    344 	}
    345 }
    346 
    347 void
    348 _fp_pack(pu, n, type)
    349 	unpacked       *pu;	/* unpacked operand */
    350 	int 		*n;	/* output result's address */
    351 	enum fp_op_type type;	/* type of datum */
    352 
    353 {
    354 	switch (type) {
    355 	case fp_op_integer:
    356 		{
    357 			packinteger(pu, n);
    358 			break;
    359 		}
    360 	case fp_op_single:
    361 		{
    362 			single_type     x;
    363 			packsingle(pu, &x);
    364 			n[0] = *(int*)&x;
    365 			break;
    366 		}
    367 	case fp_op_double:
    368 		{
    369 			double_type     x;
    370 			double		t=1.0;
    371 			int		i0,i1;
    372 			if((*(int*)&t)!=0) {i0=0;i1=1;} else {i0=1;i1=0;}
    373 			packdouble(pu, &x,&n[i1]);
    374 			n[i0] = *(int*)&x;
    375 			break;
    376 		}
    377 	case fp_op_extended:
    378 		{
    379 			extended_type   x;
    380 			unsigned        y, z, w;
    381 			unpacked        u;
    382 			int		k;
    383 			switch (fp_precision) {	/* Implement extended
    384 						 * rounding precision mode. */
    385 			case fp_single:
    386 				{
    387 					single_type     tx;
    388 					packsingle(pu, &tx);
    389 					pu = &u;
    390 					unpacksingle(pu, tx);
    391 					break;
    392 				}
    393 			case fp_double:
    394 				{
    395 					double_type     tx;
    396 					unsigned        ty;
    397 					packdouble(pu, &tx, &ty);
    398 					pu = &u;
    399 					unpackdouble(pu, tx, ty);
    400 					break;
    401 				}
    402 			case fp_precision_3:	/* rounded to 64 bits */
    403 				{
    404 					k = pu->exponent+ EXTENDED_BIAS;
    405 					if(k>=0) k = 113-64;
    406 					else     k = 113-64-k;
    407 					fpu_rightshift(pu,113-64);
    408 					round(pu);
    409 					pu->sticky=pu->rounded=0;
    410 					pu->exponent += k;
    411 					fpu_normalize(pu);
    412 					break;
    413 				}
    414 			}
    415 			{
    416 			int		i0,i1,i2,i3;
    417 			double t = 1.0;
    418 			if((*(int*)&t)!=0) {i0=0;i1=1;i2=2;i3=3;}
    419 			else {i0=3;i1=2;i2=1;i3=0;}
    420 			packextended(pu, &x, &n[i1], &n[i2], &n[i3]);
    421 			n[i0] = *(int*)&x;
    422 			}
    423 
    424 			break;
    425 		}
    426 	}
    427 }
    428 
    429