xref: /onnv-gate/usr/src/cmd/fps/fptest/fpu_fsr_test.c (revision 7186:e728311aafb0)
16429Svs195195 /*
26429Svs195195  * CDDL HEADER START
36429Svs195195  *
46429Svs195195  * The contents of this file are subject to the terms of the
56429Svs195195  * Common Development and Distribution License (the "License").
66429Svs195195  * You may not use this file except in compliance with the License.
76429Svs195195  *
86429Svs195195  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96429Svs195195  * or http://www.opensolaris.org/os/licensing.
106429Svs195195  * See the License for the specific language governing permissions
116429Svs195195  * and limitations under the License.
126429Svs195195  *
136429Svs195195  * When distributing Covered Code, include this CDDL HEADER in each
146429Svs195195  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156429Svs195195  * If applicable, add the following below this CDDL HEADER, with the
166429Svs195195  * fields enclosed by brackets "[]" replaced with your own identifying
176429Svs195195  * information: Portions Copyright [yyyy] [name of copyright owner]
186429Svs195195  *
196429Svs195195  * CDDL HEADER END
206429Svs195195  */
216429Svs195195 
226429Svs195195 /*
236491Sia112686  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
246429Svs195195  * Use is subject to license terms.
256429Svs195195  */
266429Svs195195 
276429Svs195195 #pragma ident	"%Z%%M%	%I%	%E% SMI"
286429Svs195195 
296429Svs195195 #include <fp.h>
306429Svs195195 #include <externs.h>
316429Svs195195 #include <fps_ereport.h>
326429Svs195195 
336429Svs195195 /* Traps enabled or disabled */
346429Svs195195 #define	T_ENABLED 1
356429Svs195195 #define	T_DISABLED 0
366429Svs195195 
376429Svs195195 static int test_ieee754_exc_fields(int trapStatus,
386429Svs195195     struct fps_test_ereport *report);
396429Svs195195 static int test_fccn(struct fps_test_ereport *report);
406429Svs195195 static int test_rounding(struct fps_test_ereport *report);
416429Svs195195 
426429Svs195195 /*
436429Svs195195  * Test data for testing the IEEE 754 exceptions.
446429Svs195195  * The first 5 entries are for the 5 FP exception fields of the FSR
456429Svs195195  */
466429Svs195195 static struct testws test_ws[] = {
476429Svs195195 
486429Svs195195 	/*
496429Svs195195 	 * a_msw, a_lsw, b_msw,   b_lsw,  instr, fsr_tem0...,  fsr_tem1...,
506429Svs195195 	 * ecode
516429Svs195195 	 */
526429Svs195195 
536429Svs195195 	{one_sp, nocare, maxm_sp, nocare, op_add_sp,
546429Svs195195 	FSR_TEM0_NX, FSR_TEM1_NX, E_NX},	/* inexact	 */
556429Svs195195 	{one_sp, nocare, zero_sp, nocare, op_div_sp,
566429Svs195195 	FSR_TEM0_DZ, FSR_TEM1_DZ, E_DZ},	/* div/zero */
576429Svs195195 	{min1_sp, nocare, min1_sp, nocare, op_mul_sp,
586429Svs195195 	FSR_TEM0_UF, FSR_TEM1_UF, E_UF},	/* unfl,inex */
596429Svs195195 	{maxm_sp, nocare, maxm_sp, nocare, op_mul_sp,
606429Svs195195 	FSR_TEM0_OF, FSR_TEM1_OF, E_OF},	/* overflow */
616429Svs195195 	{zero_sp, nocare, zero_sp, nocare, op_div_sp,
626429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* not a valid */
636429Svs195195 
646429Svs195195 	{maxn_sp, nocare, maxn_sp, nocare, op_add_sp,
656429Svs195195 	FSR_TEM0_OF_NX, FSR_CEXC_OF, E_OF},	/* 5-ovfl,inex */
666429Svs195195 	{maxn_sp, nocare, maxn_sp, nocare, op_mul_sp,
676429Svs195195 	FSR_TEM0_OF_NX, FSR_CEXC_OF, E_OF},	/* 5-ovfl,inex */
686429Svs195195 	{maxn_msw, maxn_lsw, maxn_msw, maxn_lsw, op_mul_dp,
696429Svs195195 	FSR_TEM0_OF_NX, FSR_CEXC_OF, E_OF},
706429Svs195195 	{one_msw, one_lsw, zero_msw, zero_lsw, op_div_dp,
716429Svs195195 	FSR_TEM1_DZ, FSR_TEM1_DZ, E_DZ},
726429Svs195195 	{one_sp, nocare, nn_sp, nocare, op_add_sp,
736429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
746429Svs195195 
756429Svs195195 	{one_msw, one_lsw, nn_msw, nn_lsw, op_add_dp,
766429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
776429Svs195195 	{one_sp, nocare, nn_sp, nocare, op_mul_sp,
786429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
796429Svs195195 	{one_msw, one_lsw, nn_msw, nn_lsw, op_mul_dp,
806429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
816429Svs195195 	{maxd_sp, nocare, two_sp, nocare, op_div_sp,
826429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 8-a-denorm */
836429Svs195195 	{maxd_msw, maxd_lsw, two_msw, two_lsw, op_div_dp,
846429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
856429Svs195195 
866429Svs195195 	{min1_sp, nocare, pi_4_sp, nocare, op_mul_sp,
876429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 7-unfl,inex */
886429Svs195195 	{maxd_sp, nocare, half_sp, nocare, op_mul_sp,
896429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 8 -a-denorm */
906429Svs195195 	{maxd_msw, maxd_lsw, half_msw, half_lsw, op_mul_dp,
916429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
926429Svs195195 	{half_sp, nocare, maxd_sp, nocare, op_mul_sp,
936429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},	/* 9 -b-denorm */
946429Svs195195 	{half_msw, half_lsw, maxd_msw, maxd_lsw, op_mul_dp,
956429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
966429Svs195195 
976429Svs195195 	{min1_msw, min1_lsw, pi_4_msw, pi_4_lsw, op_mul_dp,
986429Svs195195 	FSR_TEM0_UF_NX, FSR_CEXC_UF, E_UF},
996429Svs195195 	{nan_sp, nocare, zero_sp, nocare, op_add_sp,
1006429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 12-a-nan */
1016429Svs195195 	{nan_msw, nan_lsw, zero_msw, zero_lsw, op_add_dp,
1026429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1036429Svs195195 	{zero_sp, nocare, nan_sp, nocare, op_add_sp,
1046429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 13 -b-nan */
1056429Svs195195 	{zero_sp, nocare, nan_msw, nan_lsw, op_add_dp,
1066429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1076429Svs195195 
1086429Svs195195 	{nan_sp, nocare, nan_sp, nocare, op_add_sp,
1096429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 14 -ab-nan */
1106429Svs195195 	{nan_msw, nan_lsw, nan_msw, nan_lsw, op_add_dp,
1116429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1126429Svs195195 	{nan_sp, nocare, zero_sp, nocare, op_mul_sp,
1136429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 11-a-nan */
1146429Svs195195 	{nan_msw, nan_lsw, zero_msw, zero_lsw, op_mul_dp,
1156429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1166429Svs195195 	{zero_sp, nocare, nan_sp, nocare, op_mul_sp,
1176429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 13-b-nan */
1186429Svs195195 
1196429Svs195195 	{zero_sp, nocare, nan_msw, nan_lsw, op_mul_dp,
1206429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1216429Svs195195 	{nan_sp, nocare, nan_sp, nocare, op_mul_sp,
1226429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},	/* 14-ab-nan */
1236429Svs195195 	{nan_msw, nan_lsw, nan_msw, nan_lsw, op_mul_dp,
1246429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1256429Svs195195 
1266429Svs195195 	/* More IEEE 754 exceptions */
1276429Svs195195 
1286429Svs195195 	/* (+inf) + (-inf) */
1296429Svs195195 	{p_inf_sp, nocare, n_inf_sp, nocare, op_add_sp,
1306429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1316429Svs195195 	{p_inf_msw, p_inf_lsw, n_inf_msw, n_inf_lsw, op_add_dp,
1326429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1336429Svs195195 
1346429Svs195195 	/* (0) * (+inf) */
1356429Svs195195 	{zero_sp, nocare, p_inf_sp, nocare, op_mul_sp,
1366429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1376429Svs195195 	{zero_msw, zero_lsw, p_inf_msw, p_inf_lsw, op_mul_dp,
1386429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1396429Svs195195 
1406429Svs195195 	/* (0) * (-inf) */
1416429Svs195195 	{zero_sp, nocare, n_inf_sp, nocare, op_mul_sp,
1426429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1436429Svs195195 	{zero_msw, zero_lsw, n_inf_msw, n_inf_lsw, op_mul_dp,
1446429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1456429Svs195195 
1466429Svs195195 	/* (+inf) / (+inf) */
1476429Svs195195 	{p_inf_sp, nocare, p_inf_sp, nocare, op_div_sp,
1486429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1496429Svs195195 	{p_inf_msw, p_inf_lsw, p_inf_msw, p_inf_lsw, op_div_dp,
1506429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1516429Svs195195 
1526429Svs195195 	/* (+inf) / (-inf) */
1536429Svs195195 	{p_inf_sp, nocare, n_inf_sp, nocare, op_div_sp,
1546429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1556429Svs195195 	{p_inf_msw, p_inf_lsw, n_inf_msw, n_inf_lsw, op_div_dp,
1566429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1576429Svs195195 
1586429Svs195195 	/* sqrt(-1) */
1596429Svs195195 	{m_one_sp, nocare, nocare, nocare, op_fsqrts,
1606429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1616429Svs195195 	{m_one_msw, m_one_lsw, nocare, nocare, op_fsqrtd,
1626429Svs195195 	FSR_TEM0_NV, FSR_TEM1_NV, E_NV},
1636429Svs195195 
1646429Svs195195 
1656429Svs195195 {00, 00, 000, 000, 0000, 0x0, 0x0, 0x0}};
1666429Svs195195 
1676429Svs195195 /* Data used in test_fccn() */
1686429Svs195195 
1696429Svs195195 /* No. of fccn fields in the FSR */
1706429Svs195195 #define	N_FCCN 4
1716429Svs195195 
1726429Svs195195 #define	FSR_FCC0_MASK ((uint64_t)FSR_FCC)
1736429Svs195195 #define	FSR_FCC1_MASK ((uint64_t)FSR_FCC1 << 32)
1746429Svs195195 #define	FSR_FCC2_MASK ((uint64_t)FSR_FCC2 << 32)
1756429Svs195195 #define	FSR_FCC3_MASK ((uint64_t)FSR_FCC3 << 32)
1766429Svs195195 
1776429Svs195195 /*
1786429Svs195195  * No. of bits to shift a fcc field to the right so that its value occupies
1796429Svs195195  * the least significant bits
1806429Svs195195  */
1816429Svs195195 #define	FSR_FCC0_SRL_N 10
1826429Svs195195 #define	FSR_FCC1_SRL_N 32
1836429Svs195195 #define	FSR_FCC2_SRL_N 34
1846429Svs195195 #define	FSR_FCC3_SRL_N 36
1856429Svs195195 
1866429Svs195195 static uint64_t fccMasks[] =
1876429Svs195195 {
1886429Svs195195 	FSR_FCC0_MASK,
1896429Svs195195 	FSR_FCC1_MASK,
1906429Svs195195 	FSR_FCC2_MASK,
1916429Svs195195 	FSR_FCC3_MASK
1926429Svs195195 };
1936429Svs195195 
1946429Svs195195 static unsigned int fccShifts[] =
1956429Svs195195 {
1966429Svs195195 	FSR_FCC0_SRL_N,
1976429Svs195195 	FSR_FCC1_SRL_N,
1986429Svs195195 	FSR_FCC2_SRL_N,
1996429Svs195195 	FSR_FCC3_SRL_N
2006429Svs195195 };
2016429Svs195195 
2026429Svs195195 
2036429Svs195195 /*
2046429Svs195195  * Data structure for the fccn test data. We are using only single-precision
2056429Svs195195  * comparisions
2066429Svs195195  */
2076429Svs195195 typedef struct {
2086429Svs195195 	char			*testId;
2096429Svs195195 	unsigned int	val1;	/* Operand 1 */
2106429Svs195195 	unsigned int	val2;	/* Operand 2 */
2116429Svs195195 
2126429Svs195195 	/* The value of the fcc field after the FP operation */
2136429Svs195195 	unsigned int	fccVal;
2146429Svs195195 }FccData;
2156429Svs195195 
2166429Svs195195 static FccData  fccData[] =
2176429Svs195195 {
2186429Svs195195 	{"test-0", 0xc0980000, 0xc0980000, 0},	/* -ve = -ve */
2196429Svs195195 	{"test-1", 0x40980000, 0x40980000, 0},	/* +ve = +ve */
2206429Svs195195 
2216429Svs195195 	{"test-2", 0xc0980000, 0x40980000, 1},	/* -ve < +ve */
2226429Svs195195 	{"test-3", 0xc0980000, 0xc094cccd, 1},	/* -ve < -ve */
2236429Svs195195 	{"test-4", 0x40980000, 0x40983958, 1},	/* +ve < +ve */
2246429Svs195195 
2256429Svs195195 	{"test-5", 0x40980000, 0xc0980000, 2},	/* +ve > -ve */
2266429Svs195195 	{"test-6", 0x40983958, 0x40980000, 2},	/* +ve > +ve */
2276429Svs195195 	{"test-7", 0xc094cccd, 0xc0980000, 2},	/* -ve > -ve */
2286429Svs195195 
2296429Svs195195 	{"test-8", 0xc094cccd, nan_sp, 3},	/* +ve ? NaN */
2306429Svs195195 	{"test-9", nan_sp, 0xc094cccd, 3},	/* -ve ? NaN */
2316429Svs195195 	{"test-10", nan_sp, nan_sp, 3},	/* NaN ? NaN */
2326429Svs195195 
2336429Svs195195 };
2346429Svs195195 
2356429Svs195195 #define	N_FCCDATA  (sizeof (fccData) / sizeof (FccData))
2366429Svs195195 
2376429Svs195195 /* Data used in test_rounding() */
2386429Svs195195 #define	FOUR_SP			0x40800000U
2396429Svs195195 #define	THREE_SP		0x40400000U
2406429Svs195195 #define	FOUR_DP_MSW		0x40100000U
2416429Svs195195 #define	FOUR_DP_LSW		0x00000000U
2426429Svs195195 #define	THREE_DP_MSW	0x40080000U
2436429Svs195195 #define	THREE_DP_LSW	0x00000000U
2446429Svs195195 #define	FSR_RD_MASK_Z	0xFFFFFFFF3FFFFFFFUL
2456429Svs195195 
2466429Svs195195 /* No. of IEEE 754 rounding modes */
2476429Svs195195 #define	N_RD_MODES		4
2486429Svs195195 
2496429Svs195195 /* Data structure for the rounding test data */
2506429Svs195195 typedef struct {
2516429Svs195195 	char			*test_id;
2526429Svs195195 	unsigned int	operand1_msw;
2536429Svs195195 	unsigned int	operand1_lsw;
2546429Svs195195 	unsigned int	operand2_msw;
2556429Svs195195 	unsigned int	operand2_lsw;
2566429Svs195195 	unsigned int	operation;
2576429Svs195195 	uint64_t	    result_r2n;	/* Round to Nearest */
2586429Svs195195 	uint64_t	    result_r2z;	/* Round to Zero */
2596429Svs195195 	uint64_t	    result_r2pinf;	/* Round to +infinity */
2606429Svs195195 	uint64_t	    result_r2ninf;	/* Round to -infinity */
2616429Svs195195 
2626429Svs195195 }	RoundingData;
2636429Svs195195 
2646429Svs195195 
2656429Svs195195 /* Strings for rounding modes */
2666429Svs195195 static char	*rndModes[] =
2676429Svs195195 {
2686429Svs195195 	"Round to Nearest",
2696429Svs195195 	"Round to Zero",
2706429Svs195195 	"Round to +infinity",
2716429Svs195195 	"Round to -infinity",
2726429Svs195195 };
2736429Svs195195 
2746429Svs195195 /* Rounding test data */
2756429Svs195195 static RoundingData r_data[] =
2766429Svs195195 {
2776429Svs195195 	/* 4/3 SP */
2786429Svs195195 	{"Test-0",
2796429Svs195195 		FOUR_SP,
2806429Svs195195 		nocare,
2816429Svs195195 		THREE_SP,
2826429Svs195195 		nocare,
2836429Svs195195 		op_div_sp,
2846429Svs195195 		0x3faaaaab,
2856429Svs195195 		0x3faaaaaa,
2866429Svs195195 		0x3faaaaab,
2876429Svs195195 	0x3faaaaaa},
2886429Svs195195 
2896429Svs195195 	/* 4/3 DP */
2906429Svs195195 	{"Test-1",
2916429Svs195195 		FOUR_DP_MSW,
2926429Svs195195 		FOUR_DP_LSW,
2936429Svs195195 		THREE_DP_MSW,
2946429Svs195195 		THREE_DP_LSW,
2956429Svs195195 		op_div_dp,
2966429Svs195195 		0x3ff5555555555555,
2976429Svs195195 		0x3ff5555555555555,
2986429Svs195195 		0x3ff5555555555556,
2996429Svs195195 	0x3ff5555555555555},
3006429Svs195195 
3016429Svs195195 	{"Test-2",
3026429Svs195195 		0xc0600018,
3036429Svs195195 		nocare,
3046429Svs195195 		0xc1700009,
3056429Svs195195 		nocare,
3066429Svs195195 		op_add_sp,
3076429Svs195195 		0xc1940008,
3086429Svs195195 		0xc1940007,
3096429Svs195195 		0xc1940007,
3106429Svs195195 	0xc1940008},
3116429Svs195195 
3126429Svs195195 	{"Test-3",
3136429Svs195195 		0x880c0000,
3146429Svs195195 		0x00000018,
3156429Svs195195 		0x882e0000,
3166429Svs195195 		0x00000009,
3176429Svs195195 		op_add_dp,
3186429Svs195195 		0x8832800000000008,
3196429Svs195195 		0x8832800000000007,
3206429Svs195195 		0x8832800000000007,
3216429Svs195195 	0x8832800000000008},
3226429Svs195195 
3236429Svs195195 	/* 4/3 (DP) and convert to SP */
3246429Svs195195 	{"Test-4",
3256429Svs195195 		FOUR_DP_MSW,
3266429Svs195195 		FOUR_DP_LSW,
3276429Svs195195 		THREE_DP_MSW,
3286429Svs195195 		THREE_DP_LSW,
3296429Svs195195 		op_div_dp_c2sp,
3306429Svs195195 		0x3faaaaab,
3316429Svs195195 		0x3faaaaaa,
3326429Svs195195 		0x3faaaaab,
3336429Svs195195 	0x3faaaaaa},
3346429Svs195195 
3356429Svs195195 	/*
3366429Svs195195 	 * Convert a 64-bit *signed* integer to a single- precison FP number.
3376429Svs195195 	 * The 64-bit signed number used here, 0x0x882e000000000009, is
3386429Svs195195 	 * -0x77d1fffffffffff7 i.e -8633963435622662135.
3396429Svs195195 	 */
3406429Svs195195 	{"Test-5",
3416429Svs195195 		0x882e0000,
3426429Svs195195 		0x00000009,
3436429Svs195195 		nocare,
3446429Svs195195 		nocare,
3456429Svs195195 		op_fxtos,
3466429Svs195195 		0xdeefa400,
3476429Svs195195 		0xdeefa3ff,
3486429Svs195195 		0xdeefa3ff,
3496429Svs195195 	0xdeefa400}
3506429Svs195195 
3516429Svs195195 };
3526429Svs195195 
3536429Svs195195 #define	R_DATA_N  (sizeof (r_data)/sizeof (RoundingData))
3546429Svs195195 
3556429Svs195195 /*
3566429Svs195195  * fsr_test(struct fps_test_ereport *report) is the high level
3576429Svs195195  * caller of the functions that test the different fields of
3586429Svs195195  * the FSR. If an error is found, relevant data is stored in
3596429Svs195195  * report.
3606429Svs195195  */
3616429Svs195195 int
fsr_test(struct fps_test_ereport * report)3626429Svs195195 fsr_test(struct fps_test_ereport *report)
3636429Svs195195 {
3646429Svs195195 	if (test_ieee754_exc_fields(T_DISABLED, report) != FPU_OK)
3656429Svs195195 		return (FPU_FOROFFLINE);
3666429Svs195195 
3676429Svs195195 	if (test_ieee754_exc_fields(T_ENABLED, report) != FPU_OK)
3686429Svs195195 		return (FPU_FOROFFLINE);
3696429Svs195195 
3706429Svs195195 	if (test_fccn(report) != FPU_OK)
3716429Svs195195 		return (FPU_FOROFFLINE);
3726429Svs195195 
3736429Svs195195 	if (test_rounding(report) != FPU_OK)
3746429Svs195195 		return (FPU_FOROFFLINE);
3756429Svs195195 
3766429Svs195195 	return (FPU_OK);
3776429Svs195195 }
3786429Svs195195 
3796429Svs195195 /*
3806429Svs195195  * test_ieee754_exc_fields(int trapStatus,
3816429Svs195195  * struct fps_test_ereport *report)tests the FSR.cexc,
3826429Svs195195  * and FSR.aexc fields. It can operate in two modes: traps
3836429Svs195195  * enabled and traps disabled.
3846429Svs195195  *
3856429Svs195195  * In the T_DISABLED (FSR.TEM=0) mode, it checks if the
3866429Svs195195  * FSR.cexc and FSR.aexc fields have been set correctly.
3876429Svs195195  *
3886429Svs195195  * In the T_ENABLED mode, it check if the
3896429Svs195195  * appropriate trap has been raised and the FSR.cexc field has the correct
3906429Svs195195  * value.
3916429Svs195195  *
3926429Svs195195  * If an error is found, relevant data is stored in report.
3936429Svs195195  */
3946429Svs195195 static int
test_ieee754_exc_fields(int trapStatus,struct fps_test_ereport * report)3956429Svs195195 test_ieee754_exc_fields(int trapStatus, struct fps_test_ereport *report)
3966429Svs195195 {
3976429Svs195195 	char err_data[MAX_INFO_SIZE];
3986429Svs195195 	int i;
3996429Svs195195 	int rval;
4006429Svs195195 	uint64_t expected;
4016429Svs195195 	uint64_t observed;
4026429Svs195195 	uint64_t prev_fsr;
4036429Svs195195 	uint64_t result_fsr;
4046429Svs195195 	uint64_t t_fsr;
4056429Svs195195 	unsigned long alsw;
4066429Svs195195 	unsigned long amsw;
4076429Svs195195 	unsigned long blsw;
4086429Svs195195 	unsigned long bmsw;
4096429Svs195195 	unsigned long exc_bits;
4106429Svs195195 	unsigned long operation;
4116429Svs195195 
4126429Svs195195 	rval = FPU_OK;
4136429Svs195195 	prev_fsr = get_fsr();
4146429Svs195195 
4156429Svs195195 	for (i = 0; test_ws[i].instr != 0; i++) {
4166429Svs195195 		if (trapStatus == T_DISABLED) {
4176429Svs195195 			set_fsr(prev_fsr & 0xFFFFFFFFF07FFC00);
4186429Svs195195 		} else {
4196429Svs195195 			t_fsr = prev_fsr & 0xFFFFFFFFF07FFC1F;
4206429Svs195195 			t_fsr |= 0x000000000F800000;
4216429Svs195195 			set_fsr(t_fsr);
4226429Svs195195 		}
4236429Svs195195 
4246429Svs195195 		trap_flag = trap_flag | TRAP_SOLICITED;
4256429Svs195195 
4266429Svs195195 		amsw = test_ws[i].a_msw;
4276429Svs195195 		alsw = test_ws[i].a_lsw;
4286429Svs195195 		bmsw = test_ws[i].b_msw;
4296429Svs195195 		blsw = test_ws[i].b_lsw;
4306429Svs195195 		operation = test_ws[i].instr;
4316429Svs195195 
4326429Svs195195 		if (trapStatus == T_DISABLED)
4336429Svs195195 			exc_bits = test_ws[i].fsr_tem0_ieee754_exc;
4346429Svs195195 		else
4356429Svs195195 			exc_bits = test_ws[i].fsr_tem1_ieee754_exc;
4366429Svs195195 
4376429Svs195195 		result_fsr = 0;
4386429Svs195195 		fsr_at_trap = 0;
4396429Svs195195 
4406429Svs195195 		switch (operation) {
4416429Svs195195 		case op_add_sp:
4426429Svs195195 			result_fsr = wadd_sp(amsw, bmsw);
4436429Svs195195 			break;
4446429Svs195195 		case op_add_dp:
4456429Svs195195 			result_fsr = wadd_dp(amsw, alsw, bmsw, blsw);
4466429Svs195195 			break;
4476429Svs195195 		case op_div_sp:
4486429Svs195195 			result_fsr = wdiv_sp(amsw, bmsw);
4496429Svs195195 			break;
4506429Svs195195 		case op_div_dp:
4516429Svs195195 			result_fsr = wdiv_dp(amsw, alsw, bmsw, blsw);
4526429Svs195195 			break;
4536429Svs195195 		case op_mul_sp:
4546429Svs195195 			result_fsr = wmult_sp(amsw, bmsw);
4556429Svs195195 			break;
4566429Svs195195 		case op_mul_dp:
4576429Svs195195 			result_fsr = wmult_dp(amsw, alsw, bmsw, blsw);
4586429Svs195195 			break;
4596429Svs195195 		case op_fsqrts:
4606429Svs195195 			result_fsr = wsqrt_sp(amsw);
4616429Svs195195 			break;
4626429Svs195195 		case op_fsqrtd:
4636429Svs195195 			result_fsr = wsqrt_dp(((uint64_t)amsw << 32)
4646429Svs195195 			    | alsw);
4656429Svs195195 			break;
4666429Svs195195 		default:
4676429Svs195195 			break;
4686429Svs195195 		}
4696429Svs195195 
4706429Svs195195 		if (trapStatus == T_ENABLED) {
4716429Svs195195 			if (!trap_flag) {
4726429Svs195195 				result_fsr = fsr_at_trap;
4736429Svs195195 			} else {
4746429Svs195195 				rval = FPU_FOROFFLINE;
4756429Svs195195 				observed = 1;
4766429Svs195195 				expected = 0;
477*7186Skk158166 				(void) snprintf(err_data, sizeof (err_data),
4786429Svs195195 				    "test: %d", i);
4796429Svs195195 				setup_fps_test_struct(IS_EREPORT_INFO,
4806429Svs195195 				    report, 6305, &observed, &expected,
4816429Svs195195 				    1, 1, err_data);
4826429Svs195195 			}
4836429Svs195195 		}
4846429Svs195195 		if ((result_fsr & exc_bits) != exc_bits) {
4856429Svs195195 			rval = FPU_FOROFFLINE;
4866429Svs195195 			observed = (uint64_t)(result_fsr & exc_bits);
4876429Svs195195 			expected = (uint64_t)exc_bits;
488*7186Skk158166 			(void) snprintf(err_data, sizeof (err_data),
4896429Svs195195 			    "test: %d, trapStatus: %d", i, trapStatus);
4906429Svs195195 			setup_fps_test_struct(IS_EREPORT_INFO, report,
4916429Svs195195 			    6308, &observed, &expected, 1, 1, err_data);
4926429Svs195195 		}
4936429Svs195195 	}
4946429Svs195195 
4956429Svs195195 	set_fsr(prev_fsr);
4966429Svs195195 
4976429Svs195195 	return (rval);
4986429Svs195195 }
4996429Svs195195 
5006429Svs195195 /*
5016429Svs195195  * test_fccn(struct fps_test_ereport *report)
5026429Svs195195  * test the fcc0, fcc1, fcc2, and fcc3 fields of the FSR. Single-
5036429Svs195195  * precision comparision operations are done using the test data given
5046429Svs195195  * in fccData[], and the resultant value in the fccN field is compared
5056429Svs195195  * against the value in fccData. Each test data is used with all the
5066429Svs195195  * four fcc fields.
5076429Svs195195  *
5086429Svs195195  * If an error is found, relevant data is stored in report.
5096429Svs195195  */
5106429Svs195195 static int
test_fccn(struct fps_test_ereport * report)5116429Svs195195 test_fccn(struct fps_test_ereport *report)
5126429Svs195195 {
5136429Svs195195 	char err_data[MAX_INFO_SIZE];
5146429Svs195195 	int fcc;
5156429Svs195195 	int i;
5166429Svs195195 	int rval;
5176429Svs195195 	uint64_t expected;
5186429Svs195195 	uint64_t fcc_mask;
5196429Svs195195 	uint64_t observed;
5206429Svs195195 	uint64_t prev_fsr;
5216429Svs195195 	uint64_t result_fsr;
5226429Svs195195 	unsigned int shiftBits;
5236429Svs195195 
5246429Svs195195 #ifdef __lint
5256429Svs195195 	uint64_t des_fcc;
5266429Svs195195 	uint64_t res_fcc;
5276429Svs195195 #else
5286429Svs195195 	unsigned int des_fcc;
5296429Svs195195 	unsigned int res_fcc;
5306429Svs195195 #endif
5316429Svs195195 
5326429Svs195195 	prev_fsr = get_fsr();
5336429Svs195195 	rval = FPU_OK;
5346429Svs195195 	set_fsr(prev_fsr & 0xFFFFFFFFF07FFC00);
5356429Svs195195 
5366429Svs195195 	for (fcc = 0; fcc < N_FCCN; fcc++) {
5376429Svs195195 		fcc_mask = fccMasks[fcc];
5386429Svs195195 		shiftBits = fccShifts[fcc];
5396429Svs195195 
5406429Svs195195 		for (i = 0; i < N_FCCDATA; i++) {
5416429Svs195195 			des_fcc = fccData[i].fccVal;
5426429Svs195195 
5436429Svs195195 			result_fsr = fcmps_fcc(fccData[i].val1,
5446429Svs195195 			    fccData[i].val2, fcc);
5456429Svs195195 
5466429Svs195195 			res_fcc = ((result_fsr & fcc_mask)
5476429Svs195195 			    >> shiftBits);
5486429Svs195195 
5496429Svs195195 			if (res_fcc != des_fcc) {
5506429Svs195195 				rval = FPU_FOROFFLINE;
5516429Svs195195 				expected = (uint64_t)des_fcc;
5526429Svs195195 				observed = (uint64_t)res_fcc;
553*7186Skk158166 				(void) snprintf(err_data, sizeof (err_data),
5546429Svs195195 				    "FSR.fcc: %d, FCC ID: %s"
5556429Svs195195 				    "\nExpected: %lld"
5566429Svs195195 				    "\nObserved: %lld",
5576429Svs195195 				    fcc, fccData[i].testId, des_fcc,
5586429Svs195195 				    res_fcc);
5596429Svs195195 				setup_fps_test_struct(IS_EREPORT_INFO,
5606429Svs195195 				    report, 6310, &observed, &expected,
5616429Svs195195 				    1, 1, err_data);
5626429Svs195195 				continue;
5636429Svs195195 			}
5646429Svs195195 		}
5656429Svs195195 	}
5666429Svs195195 
5676429Svs195195 	set_fsr(prev_fsr);
5686429Svs195195 
5696429Svs195195 	return (rval);
5706429Svs195195 }
5716429Svs195195 
5726429Svs195195 /*
5736429Svs195195  * test_rounding(struct fps_test_ereport *report)
5746429Svs195195  * tests the 4 IEEE 754 rounding modes.
5756429Svs195195  * If an error is found, relevant data is stored
5766429Svs195195  * in report.
5776429Svs195195  */
5786429Svs195195 static int
test_rounding(struct fps_test_ereport * report)5796429Svs195195 test_rounding(struct fps_test_ereport *report)
5806429Svs195195 {
5816429Svs195195 	char err_data[MAX_INFO_SIZE];
5826429Svs195195 	int i;
5836429Svs195195 	int rval;
5846429Svs195195 	uint64_t des_res;
5856429Svs195195 	uint64_t expected;
5866429Svs195195 	uint64_t fsr_rd_masked;
5876429Svs195195 	uint64_t gsr_im_z;
5886429Svs195195 	uint64_t observed;
5896429Svs195195 	uint64_t oprnd;
5906429Svs195195 	uint64_t oprnd1;
5916429Svs195195 	uint64_t oprnd2;
5926429Svs195195 	uint64_t prev_fsr;
5936429Svs195195 	uint64_t prev_gsr;
5946429Svs195195 	uint64_t rd;
5956429Svs195195 	uint64_t result;
5966429Svs195195 	uint64_t rmode;
5976429Svs195195 
5986429Svs195195 	rval = FPU_OK;
5996429Svs195195 	prev_fsr = get_fsr();
6006429Svs195195 	fsr_rd_masked = prev_fsr & FSR_RD_MASK_Z;
6016429Svs195195 	prev_gsr = get_gsr();
6026429Svs195195 	gsr_im_z = prev_gsr & GSR_IM_ZERO;
6036429Svs195195 
6046429Svs195195 	for (i = 0; i < R_DATA_N; i++) {
6056429Svs195195 		for (rd = 0; rd < N_RD_MODES; rd++) {
6066429Svs195195 			rmode = rd << 30;
6076429Svs195195 
6086429Svs195195 			if (rd == 0)
6096429Svs195195 				des_res = r_data[i].result_r2n;
6106429Svs195195 			else if (rd == 1)
6116429Svs195195 				des_res = r_data[i].result_r2z;
6126429Svs195195 			else if (rd == 2)
6136429Svs195195 				des_res = r_data[i].result_r2pinf;
6146429Svs195195 			else if (rd == 3)
6156429Svs195195 				des_res = r_data[i].result_r2ninf;
6166429Svs195195 
6176429Svs195195 			switch (r_data[i].operation) {
6186429Svs195195 			case op_add_sp:
6196429Svs195195 				set_gsr(gsr_im_z);
6206429Svs195195 				set_fsr(fsr_rd_masked | rmode);
6216429Svs195195 				result = add_sp(r_data[i].operand1_msw,
6226429Svs195195 				    r_data[i].operand2_msw);
6236429Svs195195 
6246429Svs195195 				break;
6256429Svs195195 			case op_add_dp:
6266429Svs195195 				oprnd1 =
6276429Svs195195 				    ((uint64_t)r_data[i].operand1_msw
6286429Svs195195 				    << 32) | r_data[i].operand1_lsw;
6296429Svs195195 
6306429Svs195195 				oprnd2 =
6316429Svs195195 				    ((uint64_t)r_data[i].operand2_msw
6326429Svs195195 				    << 32) | r_data[i].operand2_lsw;
6336429Svs195195 
6346429Svs195195 				set_gsr(gsr_im_z);
6356429Svs195195 				set_fsr(fsr_rd_masked | rmode);
6366429Svs195195 				result = add_dp(oprnd1, oprnd2);
6376429Svs195195 
6386429Svs195195 				break;
6396429Svs195195 			case op_div_sp:
6406429Svs195195 				set_gsr(gsr_im_z);
6416429Svs195195 				set_fsr(fsr_rd_masked | rmode);
6426429Svs195195 				result = div_sp(r_data[i].operand1_msw,
6436429Svs195195 				    r_data[i].operand2_msw);
6446429Svs195195 
6456429Svs195195 				break;
6466429Svs195195 			case op_div_dp:
6476429Svs195195 				oprnd1 =
6486429Svs195195 				    ((uint64_t)r_data[i].operand1_msw
6496429Svs195195 				    << 32) | r_data[i].operand1_lsw;
6506429Svs195195 
6516429Svs195195 				oprnd2 =
6526429Svs195195 				    ((uint64_t)r_data[i].operand2_msw
6536429Svs195195 				    << 32) | r_data[i].operand2_lsw;
6546429Svs195195 
6556429Svs195195 				set_gsr(gsr_im_z);
6566429Svs195195 				set_fsr(fsr_rd_masked | rmode);
6576429Svs195195 				result = div_dp(oprnd1, oprnd2);
6586429Svs195195 
6596429Svs195195 				break;
6606429Svs195195 			case op_div_dp_c2sp:
6616429Svs195195 				oprnd1 =
6626429Svs195195 				    ((uint64_t)r_data[i].operand1_msw
6636429Svs195195 				    << 32) | r_data[i].operand1_lsw;
6646429Svs195195 
6656429Svs195195 				oprnd2 =
6666429Svs195195 				    ((uint64_t)r_data[i].operand2_msw
6676429Svs195195 				    << 32) | r_data[i].operand2_lsw;
6686429Svs195195 
6696429Svs195195 				set_gsr(gsr_im_z);
6706429Svs195195 				set_fsr(fsr_rd_masked | rmode);
6716429Svs195195 				result = div_dp(oprnd1, oprnd2);
6726429Svs195195 				result = convert_dp_sp(result);
6736429Svs195195 
6746429Svs195195 				break;
6756429Svs195195 			case op_fxtos:
6766429Svs195195 				oprnd =
6776429Svs195195 				    ((uint64_t)r_data[i].operand1_msw
6786429Svs195195 				    << 32) | r_data[i].operand1_lsw;
6796429Svs195195 				set_gsr(gsr_im_z);
6806429Svs195195 				set_fsr(fsr_rd_masked | rmode);
6816429Svs195195 				result = long_float_s(oprnd);
6826429Svs195195 
6836429Svs195195 				break;
6846429Svs195195 			default:
6856429Svs195195 				break;
6866429Svs195195 			}
6876429Svs195195 
6886429Svs195195 			if (result != des_res) {
6896429Svs195195 				expected = (uint64_t)des_res;
6906429Svs195195 				observed = (uint64_t)result;
691*7186Skk158166 				(void) snprintf(err_data, sizeof (err_data),
6926429Svs195195 				    "FSR.RD: %d, %s, TestID: %s"
6936429Svs195195 				    "\nExpected: %lld\nObserved: %lld",
6946429Svs195195 				    rd, rndModes[rd], r_data[i].test_id,
6956429Svs195195 				    des_res, result);
6966429Svs195195 				setup_fps_test_struct(IS_EREPORT_INFO,
6976429Svs195195 				    report, 6309, &observed, &expected,
6986429Svs195195 				    1, 1, err_data);
6996429Svs195195 				rval = FPU_FOROFFLINE;
7006429Svs195195 			}
7016429Svs195195 		}
7026429Svs195195 	}
7036429Svs195195 
7046429Svs195195 	set_gsr(prev_gsr);
7056429Svs195195 	set_fsr(prev_fsr);
7066429Svs195195 
7076429Svs195195 	return (rval);
7086429Svs195195 }
709