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