xref: /onnv-gate/usr/src/cmd/fps/fptest/fpu_fsr_test.c (revision 7186:e728311aafb0)
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
fsr_test(struct fps_test_ereport * report)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
test_ieee754_exc_fields(int trapStatus,struct fps_test_ereport * report)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
test_fccn(struct fps_test_ereport * report)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
test_rounding(struct fps_test_ereport * report)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