Home | History | Annotate | Download | only in fptest
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <fp.h>
     30 #include <externs.h>
     31 #include <fps_ereport.h>
     32 
     33 /* Traps enabled or disabled */
     34 #define	T_ENABLED 1
     35 #define	T_DISABLED 0
     36 
     37 static int test_ieee754_exc_fields(int trapStatus,
     38     struct fps_test_ereport *report);
     39 static int test_fccn(struct fps_test_ereport *report);
     40 static int test_rounding(struct fps_test_ereport *report);
     41 
     42 /*
     43  * Test data for testing the IEEE 754 exceptions.
     44  * The first 5 entries are for the 5 FP exception fields of the FSR
     45  */
     46 static struct testws test_ws[] = {
     47 
     48 	/*
     49 	 * a_msw, a_lsw, b_msw,   b_lsw,  instr, fsr_tem0...,  fsr_tem1...,
     50 	 * ecode
     51 	 */
     52 
     53 	{one_sp, nocare, maxm_sp, nocare, op_add_sp,
     54 	FSR_TEM0_NX, FSR_TEM1_NX, E_NX},	/* inexact	 */
     55 	{one_sp, nocare, zero_sp, nocare, op_div_sp,
     56 	FSR_TEM0_DZ, FSR_TEM1_DZ, E_DZ},	/* div/zero */
     57 	{min1_sp, nocare, min1_sp, nocare, op_mul_sp,
     58 	FSR_TEM0_UF, FSR_TEM1_UF, E_UF},	/* unfl,inex */
     59 	{maxm_sp, nocare, maxm_sp, nocare, op_mul_sp,
     60 	FSR_TEM0_OF, FSR_TEM1_OF, E_OF},	/* overflow */
     61 	{zero_sp, nocare, zero_sp, nocare, op_div_sp,
     62 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* not a valid */
     63 
     64 	{maxn_sp, nocare, maxn_sp, nocare, op_add_sp,
     65 	FSR_TEM0_OF_NX, FSR_CEXC_OF, E_OF},	/* 5-ovfl,inex */
     66 	{maxn_sp, nocare, maxn_sp, nocare, op_mul_sp,
     67 	FSR_TEM0_OF_NX, FSR_CEXC_OF, E_OF},	/* 5-ovfl,inex */
     68 	{maxn_msw, maxn_lsw, maxn_msw, maxn_lsw, op_mul_dp,
     69 	FSR_TEM0_OF_NX, FSR_CEXC_OF, E_OF},
     70 	{one_msw, one_lsw, zero_msw, zero_lsw, op_div_dp,
     71 	FSR_TEM1_DZ, FSR_TEM1_DZ, E_DZ},
     72 	{one_sp, nocare, nn_sp, nocare, op_add_sp,
     73 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
     74 
     75 	{one_msw, one_lsw, nn_msw, nn_lsw, op_add_dp,
     76 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
     77 	{one_sp, nocare, nn_sp, nocare, op_mul_sp,
     78 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
     79 	{one_msw, one_lsw, nn_msw, nn_lsw, op_mul_dp,
     80 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
     81 	{maxd_sp, nocare, two_sp, nocare, op_div_sp,
     82 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 8-a-denorm */
     83 	{maxd_msw, maxd_lsw, two_msw, two_lsw, op_div_dp,
     84 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
     85 
     86 	{min1_sp, nocare, pi_4_sp, nocare, op_mul_sp,
     87 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 7-unfl,inex */
     88 	{maxd_sp, nocare, half_sp, nocare, op_mul_sp,
     89 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 8 -a-denorm */
     90 	{maxd_msw, maxd_lsw, half_msw, half_lsw, op_mul_dp,
     91 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
     92 	{half_sp, nocare, maxd_sp, nocare, op_mul_sp,
     93 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 9 -b-denorm */
     94 	{half_msw, half_lsw, maxd_msw, maxd_lsw, op_mul_dp,
     95 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
     96 
     97 	{min1_msw, min1_lsw, pi_4_msw, pi_4_lsw, op_mul_dp,
     98 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
     99 	{nan_sp, nocare, zero_sp, nocare, op_add_sp,
    100 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 12-a-nan */
    101 	{nan_msw, nan_lsw, zero_msw, zero_lsw, op_add_dp,
    102 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    103 	{zero_sp, nocare, nan_sp, nocare, op_add_sp,
    104 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 13 -b-nan */
    105 	{zero_sp, nocare, nan_msw, nan_lsw, op_add_dp,
    106 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    107 
    108 	{nan_sp, nocare, nan_sp, nocare, op_add_sp,
    109 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 14 -ab-nan */
    110 	{nan_msw, nan_lsw, nan_msw, nan_lsw, op_add_dp,
    111 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    112 	{nan_sp, nocare, zero_sp, nocare, op_mul_sp,
    113 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 11-a-nan */
    114 	{nan_msw, nan_lsw, zero_msw, zero_lsw, op_mul_dp,
    115 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    116 	{zero_sp, nocare, nan_sp, nocare, op_mul_sp,
    117 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 13-b-nan */
    118 
    119 	{zero_sp, nocare, nan_msw, nan_lsw, op_mul_dp,
    120 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    121 	{nan_sp, nocare, nan_sp, nocare, op_mul_sp,
    122 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 14-ab-nan */
    123 	{nan_msw, nan_lsw, nan_msw, nan_lsw, op_mul_dp,
    124 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    125 
    126 	/* More IEEE 754 exceptions */
    127 
    128 	/* (+inf) + (-inf) */
    129 	{p_inf_sp, nocare, n_inf_sp, nocare, op_add_sp,
    130 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    131 	{p_inf_msw, p_inf_lsw, n_inf_msw, n_inf_lsw, op_add_dp,
    132 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    133 
    134 	/* (0) * (+inf) */
    135 	{zero_sp, nocare, p_inf_sp, nocare, op_mul_sp,
    136 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    137 	{zero_msw, zero_lsw, p_inf_msw, p_inf_lsw, op_mul_dp,
    138 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    139 
    140 	/* (0) * (-inf) */
    141 	{zero_sp, nocare, n_inf_sp, nocare, op_mul_sp,
    142 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    143 	{zero_msw, zero_lsw, n_inf_msw, n_inf_lsw, op_mul_dp,
    144 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    145 
    146 	/* (+inf) / (+inf) */
    147 	{p_inf_sp, nocare, p_inf_sp, nocare, op_div_sp,
    148 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    149 	{p_inf_msw, p_inf_lsw, p_inf_msw, p_inf_lsw, op_div_dp,
    150 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    151 
    152 	/* (+inf) / (-inf) */
    153 	{p_inf_sp, nocare, n_inf_sp, nocare, op_div_sp,
    154 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    155 	{p_inf_msw, p_inf_lsw, n_inf_msw, n_inf_lsw, op_div_dp,
    156 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    157 
    158 	/* sqrt(-1) */
    159 	{m_one_sp, nocare, nocare, nocare, op_fsqrts,
    160 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    161 	{m_one_msw, m_one_lsw, nocare, nocare, op_fsqrtd,
    162 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
    163 
    164 
    165 {00, 00, 000, 000, 0000, 0x0, 0x0, 0x0}};
    166 
    167 /* Data used in test_fccn() */
    168 
    169 /* No. of fccn fields in the FSR */
    170 #define	N_FCCN 4
    171 
    172 #define	FSR_FCC0_MASK ((uint64_t)FSR_FCC)
    173 #define	FSR_FCC1_MASK ((uint64_t)FSR_FCC1 << 32)
    174 #define	FSR_FCC2_MASK ((uint64_t)FSR_FCC2 << 32)
    175 #define	FSR_FCC3_MASK ((uint64_t)FSR_FCC3 << 32)
    176 
    177 /*
    178  * No. of bits to shift a fcc field to the right so that its value occupies
    179  * the least significant bits
    180  */
    181 #define	FSR_FCC0_SRL_N 10
    182 #define	FSR_FCC1_SRL_N 32
    183 #define	FSR_FCC2_SRL_N 34
    184 #define	FSR_FCC3_SRL_N 36
    185 
    186 static uint64_t fccMasks[] =
    187 {
    188 	FSR_FCC0_MASK,
    189 	FSR_FCC1_MASK,
    190 	FSR_FCC2_MASK,
    191 	FSR_FCC3_MASK
    192 };
    193 
    194 static unsigned int fccShifts[] =
    195 {
    196 	FSR_FCC0_SRL_N,
    197 	FSR_FCC1_SRL_N,
    198 	FSR_FCC2_SRL_N,
    199 	FSR_FCC3_SRL_N
    200 };
    201 
    202 
    203 /*
    204  * Data structure for the fccn test data. We are using only single-precision
    205  * comparisions
    206  */
    207 typedef struct {
    208 	char			*testId;
    209 	unsigned int	val1;	/* Operand 1 */
    210 	unsigned int	val2;	/* Operand 2 */
    211 
    212 	/* The value of the fcc field after the FP operation */
    213 	unsigned int	fccVal;
    214 }FccData;
    215 
    216 static FccData  fccData[] =
    217 {
    218 	{"test-0", 0xc0980000, 0xc0980000, 0},	/* -ve = -ve */
    219 	{"test-1", 0x40980000, 0x40980000, 0},	/* +ve = +ve */
    220 
    221 	{"test-2", 0xc0980000, 0x40980000, 1},	/* -ve < +ve */
    222 	{"test-3", 0xc0980000, 0xc094cccd, 1},	/* -ve < -ve */
    223 	{"test-4", 0x40980000, 0x40983958, 1},	/* +ve < +ve */
    224 
    225 	{"test-5", 0x40980000, 0xc0980000, 2},	/* +ve > -ve */
    226 	{"test-6", 0x40983958, 0x40980000, 2},	/* +ve > +ve */
    227 	{"test-7", 0xc094cccd, 0xc0980000, 2},	/* -ve > -ve */
    228 
    229 	{"test-8", 0xc094cccd, nan_sp, 3},	/* +ve ? NaN */
    230 	{"test-9", nan_sp, 0xc094cccd, 3},	/* -ve ? NaN */
    231 	{"test-10", nan_sp, nan_sp, 3},	/* NaN ? NaN */
    232 
    233 };
    234 
    235 #define	N_FCCDATA  (sizeof (fccData) / sizeof (FccData))
    236 
    237 /* Data used in test_rounding() */
    238 #define	FOUR_SP			0x40800000U
    239 #define	THREE_SP		0x40400000U
    240 #define	FOUR_DP_MSW		0x40100000U
    241 #define	FOUR_DP_LSW		0x00000000U
    242 #define	THREE_DP_MSW	0x40080000U
    243 #define	THREE_DP_LSW	0x00000000U
    244 #define	FSR_RD_MASK_Z	0xFFFFFFFF3FFFFFFFUL
    245 
    246 /* No. of IEEE 754 rounding modes */
    247 #define	N_RD_MODES		4
    248 
    249 /* Data structure for the rounding test data */
    250 typedef struct {
    251 	char			*test_id;
    252 	unsigned int	operand1_msw;
    253 	unsigned int	operand1_lsw;
    254 	unsigned int	operand2_msw;
    255 	unsigned int	operand2_lsw;
    256 	unsigned int	operation;
    257 	uint64_t	    result_r2n;	/* Round to Nearest */
    258 	uint64_t	    result_r2z;	/* Round to Zero */
    259 	uint64_t	    result_r2pinf;	/* Round to +infinity */
    260 	uint64_t	    result_r2ninf;	/* Round to -infinity */
    261 
    262 }	RoundingData;
    263 
    264 
    265 /* Strings for rounding modes */
    266 static char	*rndModes[] =
    267 {
    268 	"Round to Nearest",
    269 	"Round to Zero",
    270 	"Round to +infinity",
    271 	"Round to -infinity",
    272 };
    273 
    274 /* Rounding test data */
    275 static RoundingData r_data[] =
    276 {
    277 	/* 4/3 SP */
    278 	{"Test-0",
    279 		FOUR_SP,
    280 		nocare,
    281 		THREE_SP,
    282 		nocare,
    283 		op_div_sp,
    284 		0x3faaaaab,
    285 		0x3faaaaaa,
    286 		0x3faaaaab,
    287 	0x3faaaaaa},
    288 
    289 	/* 4/3 DP */
    290 	{"Test-1",
    291 		FOUR_DP_MSW,
    292 		FOUR_DP_LSW,
    293 		THREE_DP_MSW,
    294 		THREE_DP_LSW,
    295 		op_div_dp,
    296 		0x3ff5555555555555,
    297 		0x3ff5555555555555,
    298 		0x3ff5555555555556,
    299 	0x3ff5555555555555},
    300 
    301 	{"Test-2",
    302 		0xc0600018,
    303 		nocare,
    304 		0xc1700009,
    305 		nocare,
    306 		op_add_sp,
    307 		0xc1940008,
    308 		0xc1940007,
    309 		0xc1940007,
    310 	0xc1940008},
    311 
    312 	{"Test-3",
    313 		0x880c0000,
    314 		0x00000018,
    315 		0x882e0000,
    316 		0x00000009,
    317 		op_add_dp,
    318 		0x8832800000000008,
    319 		0x8832800000000007,
    320 		0x8832800000000007,
    321 	0x8832800000000008},
    322 
    323 	/* 4/3 (DP) and convert to SP */
    324 	{"Test-4",
    325 		FOUR_DP_MSW,
    326 		FOUR_DP_LSW,
    327 		THREE_DP_MSW,
    328 		THREE_DP_LSW,
    329 		op_div_dp_c2sp,
    330 		0x3faaaaab,
    331 		0x3faaaaaa,
    332 		0x3faaaaab,
    333 	0x3faaaaaa},
    334 
    335 	/*
    336 	 * Convert a 64-bit *signed* integer to a single- precison FP number.
    337 	 * The 64-bit signed number used here, 0x0x882e000000000009, is
    338 	 * -0x77d1fffffffffff7 i.e -8633963435622662135.
    339 	 */
    340 	{"Test-5",
    341 		0x882e0000,
    342 		0x00000009,
    343 		nocare,
    344 		nocare,
    345 		op_fxtos,
    346 		0xdeefa400,
    347 		0xdeefa3ff,
    348 		0xdeefa3ff,
    349 	0xdeefa400}
    350 
    351 };
    352 
    353 #define	R_DATA_N  (sizeof (r_data)/sizeof (RoundingData))
    354 
    355 /*
    356  * fsr_test(struct fps_test_ereport *report) is the high level
    357  * caller of the functions that test the different fields of
    358  * the FSR. If an error is found, relevant data is stored in
    359  * report.
    360  */
    361 int
    362 fsr_test(struct fps_test_ereport *report)
    363 {
    364 	if (test_ieee754_exc_fields(T_DISABLED, report) != FPU_OK)
    365 		return (FPU_FOROFFLINE);
    366 
    367 	if (test_ieee754_exc_fields(T_ENABLED, report) != FPU_OK)
    368 		return (FPU_FOROFFLINE);
    369 
    370 	if (test_fccn(report) != FPU_OK)
    371 		return (FPU_FOROFFLINE);
    372 
    373 	if (test_rounding(report) != FPU_OK)
    374 		return (FPU_FOROFFLINE);
    375 
    376 	return (FPU_OK);
    377 }
    378 
    379 /*
    380  * test_ieee754_exc_fields(int trapStatus,
    381  * struct fps_test_ereport *report)tests the FSR.cexc,
    382  * and FSR.aexc fields. It can operate in two modes: traps
    383  * enabled and traps disabled.
    384  *
    385  * In the T_DISABLED (FSR.TEM=0) mode, it checks if the
    386  * FSR.cexc and FSR.aexc fields have been set correctly.
    387  *
    388  * In the T_ENABLED mode, it check if the
    389  * appropriate trap has been raised and the FSR.cexc field has the correct
    390  * value.
    391  *
    392  * If an error is found, relevant data is stored in report.
    393  */
    394 static int
    395 test_ieee754_exc_fields(int trapStatus, struct fps_test_ereport *report)
    396 {
    397 	char err_data[MAX_INFO_SIZE];
    398 	int i;
    399 	int rval;
    400 	uint64_t expected;
    401 	uint64_t observed;
    402 	uint64_t prev_fsr;
    403 	uint64_t result_fsr;
    404 	uint64_t t_fsr;
    405 	unsigned long alsw;
    406 	unsigned long amsw;
    407 	unsigned long blsw;
    408 	unsigned long bmsw;
    409 	unsigned long exc_bits;
    410 	unsigned long operation;
    411 
    412 	rval = FPU_OK;
    413 	prev_fsr = get_fsr();
    414 
    415 	for (i = 0; test_ws[i].instr != 0; i++) {
    416 		if (trapStatus == T_DISABLED) {
    417 			set_fsr(prev_fsr & 0xFFFFFFFFF07FFC00);
    418 		} else {
    419 			t_fsr = prev_fsr & 0xFFFFFFFFF07FFC1F;
    420 			t_fsr |= 0x000000000F800000;
    421 			set_fsr(t_fsr);
    422 		}
    423 
    424 		trap_flag = trap_flag | TRAP_SOLICITED;
    425 
    426 		amsw = test_ws[i].a_msw;
    427 		alsw = test_ws[i].a_lsw;
    428 		bmsw = test_ws[i].b_msw;
    429 		blsw = test_ws[i].b_lsw;
    430 		operation = test_ws[i].instr;
    431 
    432 		if (trapStatus == T_DISABLED)
    433 			exc_bits = test_ws[i].fsr_tem0_ieee754_exc;
    434 		else
    435 			exc_bits = test_ws[i].fsr_tem1_ieee754_exc;
    436 
    437 		result_fsr = 0;
    438 		fsr_at_trap = 0;
    439 
    440 		switch (operation) {
    441 		case op_add_sp:
    442 			result_fsr = wadd_sp(amsw, bmsw);
    443 			break;
    444 		case op_add_dp:
    445 			result_fsr = wadd_dp(amsw, alsw, bmsw, blsw);
    446 			break;
    447 		case op_div_sp:
    448 			result_fsr = wdiv_sp(amsw, bmsw);
    449 			break;
    450 		case op_div_dp:
    451 			result_fsr = wdiv_dp(amsw, alsw, bmsw, blsw);
    452 			break;
    453 		case op_mul_sp:
    454 			result_fsr = wmult_sp(amsw, bmsw);
    455 			break;
    456 		case op_mul_dp:
    457 			result_fsr = wmult_dp(amsw, alsw, bmsw, blsw);
    458 			break;
    459 		case op_fsqrts:
    460 			result_fsr = wsqrt_sp(amsw);
    461 			break;
    462 		case op_fsqrtd:
    463 			result_fsr = wsqrt_dp(((uint64_t)amsw << 32)
    464 			    | alsw);
    465 			break;
    466 		default:
    467 			break;
    468 		}
    469 
    470 		if (trapStatus == T_ENABLED) {
    471 			if (!trap_flag) {
    472 				result_fsr = fsr_at_trap;
    473 			} else {
    474 				rval = FPU_FOROFFLINE;
    475 				observed = 1;
    476 				expected = 0;
    477 				(void) snprintf(err_data, sizeof (err_data),
    478 				    "test: %d", i);
    479 				setup_fps_test_struct(IS_EREPORT_INFO,
    480 				    report, 6305, &observed, &expected,
    481 				    1, 1, err_data);
    482 			}
    483 		}
    484 		if ((result_fsr & exc_bits) != exc_bits) {
    485 			rval = FPU_FOROFFLINE;
    486 			observed = (uint64_t)(result_fsr & exc_bits);
    487 			expected = (uint64_t)exc_bits;
    488 			(void) snprintf(err_data, sizeof (err_data),
    489 			    "test: %d, trapStatus: %d", i, trapStatus);
    490 			setup_fps_test_struct(IS_EREPORT_INFO, report,
    491 			    6308, &observed, &expected, 1, 1, err_data);
    492 		}
    493 	}
    494 
    495 	set_fsr(prev_fsr);
    496 
    497 	return (rval);
    498 }
    499 
    500 /*
    501  * test_fccn(struct fps_test_ereport *report)
    502  * test the fcc0, fcc1, fcc2, and fcc3 fields of the FSR. Single-
    503  * precision comparision operations are done using the test data given
    504  * in fccData[], and the resultant value in the fccN field is compared
    505  * against the value in fccData. Each test data is used with all the
    506  * four fcc fields.
    507  *
    508  * If an error is found, relevant data is stored in report.
    509  */
    510 static int
    511 test_fccn(struct fps_test_ereport *report)
    512 {
    513 	char err_data[MAX_INFO_SIZE];
    514 	int fcc;
    515 	int i;
    516 	int rval;
    517 	uint64_t expected;
    518 	uint64_t fcc_mask;
    519 	uint64_t observed;
    520 	uint64_t prev_fsr;
    521 	uint64_t result_fsr;
    522 	unsigned int shiftBits;
    523 
    524 #ifdef __lint
    525 	uint64_t des_fcc;
    526 	uint64_t res_fcc;
    527 #else
    528 	unsigned int des_fcc;
    529 	unsigned int res_fcc;
    530 #endif
    531 
    532 	prev_fsr = get_fsr();
    533 	rval = FPU_OK;
    534 	set_fsr(prev_fsr & 0xFFFFFFFFF07FFC00);
    535 
    536 	for (fcc = 0; fcc < N_FCCN; fcc++) {
    537 		fcc_mask = fccMasks[fcc];
    538 		shiftBits = fccShifts[fcc];
    539 
    540 		for (i = 0; i < N_FCCDATA; i++) {
    541 			des_fcc = fccData[i].fccVal;
    542 
    543 			result_fsr = fcmps_fcc(fccData[i].val1,
    544 			    fccData[i].val2, fcc);
    545 
    546 			res_fcc = ((result_fsr & fcc_mask)
    547 			    >> shiftBits);
    548 
    549 			if (res_fcc != des_fcc) {
    550 				rval = FPU_FOROFFLINE;
    551 				expected = (uint64_t)des_fcc;
    552 				observed = (uint64_t)res_fcc;
    553 				(void) snprintf(err_data, sizeof (err_data),
    554 				    "FSR.fcc: %d, FCC ID: %s"
    555 				    "\nExpected: %lld"
    556 				    "\nObserved: %lld",
    557 				    fcc, fccData[i].testId, des_fcc,
    558 				    res_fcc);
    559 				setup_fps_test_struct(IS_EREPORT_INFO,
    560 				    report, 6310, &observed, &expected,
    561 				    1, 1, err_data);
    562 				continue;
    563 			}
    564 		}
    565 	}
    566 
    567 	set_fsr(prev_fsr);
    568 
    569 	return (rval);
    570 }
    571 
    572 /*
    573  * test_rounding(struct fps_test_ereport *report)
    574  * tests the 4 IEEE 754 rounding modes.
    575  * If an error is found, relevant data is stored
    576  * in report.
    577  */
    578 static int
    579 test_rounding(struct fps_test_ereport *report)
    580 {
    581 	char err_data[MAX_INFO_SIZE];
    582 	int i;
    583 	int rval;
    584 	uint64_t des_res;
    585 	uint64_t expected;
    586 	uint64_t fsr_rd_masked;
    587 	uint64_t gsr_im_z;
    588 	uint64_t observed;
    589 	uint64_t oprnd;
    590 	uint64_t oprnd1;
    591 	uint64_t oprnd2;
    592 	uint64_t prev_fsr;
    593 	uint64_t prev_gsr;
    594 	uint64_t rd;
    595 	uint64_t result;
    596 	uint64_t rmode;
    597 
    598 	rval = FPU_OK;
    599 	prev_fsr = get_fsr();
    600 	fsr_rd_masked = prev_fsr & FSR_RD_MASK_Z;
    601 	prev_gsr = get_gsr();
    602 	gsr_im_z = prev_gsr & GSR_IM_ZERO;
    603 
    604 	for (i = 0; i < R_DATA_N; i++) {
    605 		for (rd = 0; rd < N_RD_MODES; rd++) {
    606 			rmode = rd << 30;
    607 
    608 			if (rd == 0)
    609 				des_res = r_data[i].result_r2n;
    610 			else if (rd == 1)
    611 				des_res = r_data[i].result_r2z;
    612 			else if (rd == 2)
    613 				des_res = r_data[i].result_r2pinf;
    614 			else if (rd == 3)
    615 				des_res = r_data[i].result_r2ninf;
    616 
    617 			switch (r_data[i].operation) {
    618 			case op_add_sp:
    619 				set_gsr(gsr_im_z);
    620 				set_fsr(fsr_rd_masked | rmode);
    621 				result = add_sp(r_data[i].operand1_msw,
    622 				    r_data[i].operand2_msw);
    623 
    624 				break;
    625 			case op_add_dp:
    626 				oprnd1 =
    627 				    ((uint64_t)r_data[i].operand1_msw
    628 				    << 32) | r_data[i].operand1_lsw;
    629 
    630 				oprnd2 =
    631 				    ((uint64_t)r_data[i].operand2_msw
    632 				    << 32) | r_data[i].operand2_lsw;
    633 
    634 				set_gsr(gsr_im_z);
    635 				set_fsr(fsr_rd_masked | rmode);
    636 				result = add_dp(oprnd1, oprnd2);
    637 
    638 				break;
    639 			case op_div_sp:
    640 				set_gsr(gsr_im_z);
    641 				set_fsr(fsr_rd_masked | rmode);
    642 				result = div_sp(r_data[i].operand1_msw,
    643 				    r_data[i].operand2_msw);
    644 
    645 				break;
    646 			case op_div_dp:
    647 				oprnd1 =
    648 				    ((uint64_t)r_data[i].operand1_msw
    649 				    << 32) | r_data[i].operand1_lsw;
    650 
    651 				oprnd2 =
    652 				    ((uint64_t)r_data[i].operand2_msw
    653 				    << 32) | r_data[i].operand2_lsw;
    654 
    655 				set_gsr(gsr_im_z);
    656 				set_fsr(fsr_rd_masked | rmode);
    657 				result = div_dp(oprnd1, oprnd2);
    658 
    659 				break;
    660 			case op_div_dp_c2sp:
    661 				oprnd1 =
    662 				    ((uint64_t)r_data[i].operand1_msw
    663 				    << 32) | r_data[i].operand1_lsw;
    664 
    665 				oprnd2 =
    666 				    ((uint64_t)r_data[i].operand2_msw
    667 				    << 32) | r_data[i].operand2_lsw;
    668 
    669 				set_gsr(gsr_im_z);
    670 				set_fsr(fsr_rd_masked | rmode);
    671 				result = div_dp(oprnd1, oprnd2);
    672 				result = convert_dp_sp(result);
    673 
    674 				break;
    675 			case op_fxtos:
    676 				oprnd =
    677 				    ((uint64_t)r_data[i].operand1_msw
    678 				    << 32) | r_data[i].operand1_lsw;
    679 				set_gsr(gsr_im_z);
    680 				set_fsr(fsr_rd_masked | rmode);
    681 				result = long_float_s(oprnd);
    682 
    683 				break;
    684 			default:
    685 				break;
    686 			}
    687 
    688 			if (result != des_res) {
    689 				expected = (uint64_t)des_res;
    690 				observed = (uint64_t)result;
    691 				(void) snprintf(err_data, sizeof (err_data),
    692 				    "FSR.RD: %d, %s, TestID: %s"
    693 				    "\nExpected: %lld\nObserved: %lld",
    694 				    rd, rndModes[rd], r_data[i].test_id,
    695 				    des_res, result);
    696 				setup_fps_test_struct(IS_EREPORT_INFO,
    697 				    report, 6309, &observed, &expected,
    698 				    1, 1, err_data);
    699 				rval = FPU_FOROFFLINE;
    700 			}
    701 		}
    702 	}
    703 
    704 	set_gsr(prev_gsr);
    705 	set_fsr(prev_fsr);
    706 
    707 	return (rval);
    708 }
    709