1 /* Copyright (C) 2012 IBM
3 Author: Maynard Johnson <maynardj@us.ibm.com>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
18 The GNU General Public License is contained in the file COPYING.
27 register double f14
__asm__ ("fr14");
28 register double f15
__asm__ ("fr15");
29 register double f16
__asm__ ("fr16");
30 register double f17
__asm__ ("fr17");
31 register double f18
__asm__ ("fr18");
32 register double f19
__asm__ ("fr19");
35 typedef unsigned char Bool
;
40 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
42 #define SET_CR(_arg) \
43 __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
45 #define SET_XER(_arg) \
46 __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
48 #define GET_CR(_lval) \
49 __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) )
51 #define GET_XER(_lval) \
52 __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
54 #define GET_CR_XER(_lval_cr,_lval_xer) \
55 do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0)
60 #define SET_XER_ZERO \
63 #define SET_CR_XER_ZERO \
64 do { SET_CR_ZERO; SET_XER_ZERO; } while (0)
66 #define SET_FPSCR_ZERO \
67 do { double _d = 0.0; \
68 __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
71 #define GET_FPSCR(_arg) \
72 __asm__ __volatile__ ("mffs %0" : "=f"(_arg) )
74 #define SET_FPSCR_DRN \
75 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) )
78 // The assembly-level instructions being tested
80 static void _test_dadd (void)
83 __asm__
__volatile__ ("dadd. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
85 __asm__
__volatile__ ("dadd %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
88 static void _test_dsub (void)
91 __asm__
__volatile__ ("dsub. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
93 __asm__
__volatile__ ("dsub %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
96 static void _test_dmul (void)
99 __asm__
__volatile__ ("dmul. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
101 __asm__
__volatile__ ("dmul %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
104 static void _test_ddiv (void)
107 __asm__
__volatile__ ("ddiv. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
109 __asm__
__volatile__ ("ddiv %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
112 // Quad DFP arith instructions
113 static void _test_daddq (void)
116 __asm__
__volatile__ ("daddq. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
118 __asm__
__volatile__ ("daddq %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
121 static void _test_dsubq (void)
124 __asm__
__volatile__ ("dsubq. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
126 __asm__
__volatile__ ("dsubq %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
129 static void _test_dmulq (void)
132 __asm__
__volatile__ ("dmulq. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
134 __asm__
__volatile__ ("dmulq %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
137 static void _test_ddivq (void)
140 __asm__
__volatile__ ("ddivq. %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
142 __asm__
__volatile__ ("ddivq %0, %1, %2" : "=f" (f18
) : "f" (f14
),"f" (f16
));
145 static void _test_mffs (void)
147 __asm__
__volatile__ ("mffs %0" : "=f"(f14
));
150 static void _test_mtfsf (int upper
)
153 __asm__
__volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14
) );
155 __asm__
__volatile__ ("mtfsf 1, %0, 0, 0" : : "f"(f14
) );
158 typedef void (*test_func_t
)(void);
159 typedef struct test_table
161 test_func_t test_category
;
166 * 345.0DD (0x2207c00000000000 0xe50)
167 * 1.2300e+5DD (0x2207c00000000000 0x14c000)
168 * -16.0DD (0xa207c00000000000 0xe0)
169 * 0.00189DD (0x2206c00000000000 0xcf)
170 * -4.1235DD (0xa205c00000000000 0x10a395bcf)
171 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
172 * 0DD (0x2208000000000000 0x0)
173 * 0DD (0x2208000000000000 0x0)
174 * infDD (0x7800000000000000 0x0)
175 * nanDD (0x7c00000000000000 0x0
177 static unsigned long long dfp128_vals
[] = {
178 // Some finite numbers
179 0x2207c00000000000ULL
, 0x0000000000000e50ULL
,
180 0x2207c00000000000ULL
, 0x000000000014c000ULL
,
181 0xa207c00000000000ULL
, 0x00000000000000e0ULL
,
182 0x2206c00000000000ULL
, 0x00000000000000cfULL
,
183 0xa205c00000000000ULL
, 0x000000010a395bcfULL
,
184 0x6209400000fd0000ULL
, 0x00253f1f534acdd4ULL
, // huge number
185 0x000400000089b000ULL
, 0x0a6000d000000049ULL
, // very small number
187 0x2208000000000000ULL
, 0x0000000000000000ULL
,
188 0xa208000000000000ULL
, 0x0000000000000000ULL
, // negative
189 0xa248000000000000ULL
, 0x0000000000000000ULL
,
191 0x7c00000000000000ULL
, 0x0000000000000000ULL
, // quiet
192 0xfc00000000000000ULL
, 0xc00100035b007700ULL
,
193 0x7e00000000000000ULL
, 0xfe000000d0e0a0d0ULL
, // signaling
194 // flavors of Infinity
195 0x7800000000000000ULL
, 0x0000000000000000ULL
,
196 0xf800000000000000ULL
, 0x0000000000000000ULL
, // negative
197 0xf900000000000000ULL
, 0x0000000000000000ULL
200 static unsigned long long dfp64_vals
[] = {
201 // various finite numbers
202 0x2234000000000e50ULL
,
203 0x223400000014c000ULL
,
204 0xa2340000000000e0ULL
,// negative
205 0x22240000000000cfULL
,
206 0xa21400010a395bcfULL
,// negative
207 0x6e4d3f1f534acdd4ULL
,// huge number
208 0x000400000089b000ULL
,// very small number
210 0x2238000000000000ULL
,
211 0xa238000000000000ULL
,
212 0x4248000000000000ULL
,
214 0x7e34000000000111ULL
,
215 0xfe000000d0e0a0d0ULL
,//signaling
216 0xfc00000000000000ULL
,//quiet
217 // flavors of Infinity
218 0x7800000000000000ULL
,
219 0xf800000000000000ULL
,//negative
220 0x7a34000000000000ULL
,
224 typedef struct dfp_test_args
{
230 // Index pairs from dfp64_vals or dfp128_vals array to be used with dfp_two_arg_tests
231 static dfp_test_args_t dfp_2args_x2
[] = {
253 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests
254 static dfp_test_args_t dfp_2args_x1
[] = {
287 typedef struct dfp_test
289 test_func_t test_func
;
291 dfp_test_args_t
* targs
;
293 precision_type_t precision
;
300 dfp_two_arg_tests
[] = {
301 { &_test_dadd
, "dadd", dfp_2args_x1
, 25, LONG_TEST
, "+", False
},
302 { &_test_dsub
, "dsub", dfp_2args_x1
, 25, LONG_TEST
, "-", False
},
303 { &_test_dmul
, "dmul", dfp_2args_x2
, 19, LONG_TEST
, "*", False
},
304 { &_test_ddiv
, "ddiv", dfp_2args_x2
, 19, LONG_TEST
, "/", False
},
305 { &_test_daddq
, "daddq", dfp_2args_x1
, 25, QUAD_TEST
, "+", False
},
306 { &_test_dsubq
, "dsubq", dfp_2args_x1
, 25, QUAD_TEST
, "-", False
},
307 { &_test_dmulq
, "dmulq", dfp_2args_x2
, 19, QUAD_TEST
, "*", False
},
308 { &_test_ddivq
, "ddivq", dfp_2args_x2
, 19, QUAD_TEST
, "/", False
},
309 { NULL
, NULL
, NULL
, 0, 0, NULL
}
312 static void test_dfp_two_arg_ops(void)
315 unsigned long long u0
, u0x
, u1
, u1x
;
316 double res
, d0
, d1
, *d0p
, *d1p
;
317 double d0x
, d1x
, *d0xp
, *d1xp
;
325 while ((func
= dfp_two_arg_tests
[k
].test_func
)) {
327 dfp_test_t test_group
= dfp_two_arg_tests
[k
];
331 for (i
= 0; i
< test_group
.num_tests
; i
++) {
332 unsigned int condreg
;
335 if (test_group
.precision
== LONG_TEST
) {
336 u0
= dfp64_vals
[test_group
.targs
[i
].fra_idx
];
337 u1
= dfp64_vals
[test_group
.targs
[i
].frb_idx
];
339 u0
= dfp128_vals
[test_group
.targs
[i
].fra_idx
* 2];
340 u0x
= dfp128_vals
[(test_group
.targs
[i
].fra_idx
* 2) + 1];
341 u1
= dfp128_vals
[test_group
.targs
[i
].frb_idx
* 2];
342 u1x
= dfp128_vals
[(test_group
.targs
[i
].frb_idx
* 2) + 1];
344 *(unsigned long long *)d0p
= u0
;
345 *(unsigned long long *)d1p
= u1
;
348 if (test_group
.precision
== QUAD_TEST
) {
349 *(unsigned long long *)d0xp
= u0x
;
350 *(unsigned long long *)d1xp
= u1x
;
361 condreg
= (flags
& 0x000000f0) >> 4;
362 printf("%s%s %016llx", test_group
.name
, do_dot
? "." : "", u0
);
363 if (test_group
.precision
== LONG_TEST
) {
364 printf(" %s %016llx => %016llx",
365 test_group
.op
, u1
, *((unsigned long long *)(&res
)));
368 printf(" %016llx %s %016llx %016llx ==> %016llx %016llx",
369 u0x
, test_group
.op
, u1
, u1x
,
370 *((unsigned long long *)(&res
)), *((unsigned long long *)(&resx
)));
372 if (test_group
.cr_supported
)
373 printf(" (cr = %08x)\n", condreg
);
389 void test_move_toFrom_fpscr(void)
393 unsigned long long i
, max_rm
, expected_val
;
394 double fpscr_in
, fpscr_out
;
395 unsigned long long * hex_fpscr_in
= (unsigned long long *)&fpscr_in
;
396 unsigned long long * hex_fpscr_out
= (unsigned long long *)&fpscr_out
;
401 /* NOTE: The first time through this loop is for setting the binary
402 * floating point rounding mode (bits 62:63 of FPSCR). The second time
403 * through is for setting the decimal floating point rounding mode
404 * (bits 29:31 of FPSCR). In the second time through this loop, the value
405 * returned should include the final binary FP rounding mode, along with
406 * the decimal FP rounding modes.
408 for (i
= 0; i
< max_rm
; i
++) {
409 *hex_fpscr_in
= (i
<< shift
);
411 _test_mtfsf(max_rm
/8);
412 *hex_fpscr_in
= 0ULL;
417 *hex_fpscr_out
&= (max_rm
- 1) << shift
;
418 expected_val
= i
<< shift
;
420 *hex_fpscr_out
&= BFP_MAX_RM
| ((max_rm
- 1) << shift
);
421 expected_val
= (i
<< shift
) | BFP_MAX_RM
;
424 printf("FPSCR %s floating point rounding mode %016llx == %016llx? %s\n",
425 (max_rm
== 8) ? "decimal" : "binary",
426 *hex_fpscr_out
, expected_val
,
427 (expected_val
== *hex_fpscr_out
) ? "yes" : "no");
436 void test_rounding_modes(void)
439 unsigned long long u0
, u1
, rm_idx
;
440 double res
, d0
, d1
, *d0p
, *d1p
, fpscr
;
441 unsigned long long * hex_fpscr
= (unsigned long long *)&fpscr
;
442 u0
= 0x26cc3f1f534acdd4ULL
;
443 u1
= 0x27feff197a42ba06ULL
;
447 for (j
= 0; j
< 12; j
++) {
448 for (rm_idx
= 0; rm_idx
< 8; rm_idx
++) {
450 __asm__
__volatile__ ("mffs %0" : "=f"(f14
));
452 *hex_fpscr
&= 0xFFFFFFF0FFFFFFFFULL
;
453 *hex_fpscr
|= (rm_idx
<< 32);
456 *(unsigned long long *)d0p
= u0
;
457 *(unsigned long long *)d1p
= u1
;
462 printf("test #%d: dmul with rounding mode %d: %016llx * %016llx => %016llx\n",
463 j
, (int)rm_idx
, u0
, u1
, *((unsigned long long *)(&res
)));
466 // Changing the least significant bit of one of the dmul arguments give us more
467 // opportunities for different rounding modes to yield different results which
468 // can then be validated.
476 { &test_dfp_two_arg_ops
,
477 "Test DFP arithmetic instructions"},
478 { &test_rounding_modes
,
479 "Test DFP rounding modes"},
480 { &test_move_toFrom_fpscr
,
481 "Test move to/from FPSCR"},
493 while ((func
= all_tests
[i
].test_category
)) {
494 aTest
= all_tests
[i
];
495 printf( "%s\n", aTest
.name
);