1 /* Copyright (C) 2012 IBM
2
3 Author: Maynard Johnson <maynardj@us.ibm.com>
4
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.
9
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.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307, USA.
19
20 The GNU General Public License is contained in the file COPYING.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <string.h>
27
28 #if defined(HAS_DFP)
29
30 register double f14 __asm__ ("fr14");
31 register double f15 __asm__ ("fr15");
32 register double f16 __asm__ ("fr16");
33 register double f17 __asm__ ("fr17");
34 register double f18 __asm__ ("fr18");
35 register double f19 __asm__ ("fr19");
36
37
38 typedef unsigned char Bool;
39 #define True 1
40 #define False 0
41
42
43 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
44
45 #define SET_CR(_arg) \
46 __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
47
48 #define SET_XER(_arg) \
49 __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
50
51 #define GET_CR(_lval) \
52 __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) )
53
54 #define GET_XER(_lval) \
55 __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
56
57 #define GET_CR_XER(_lval_cr,_lval_xer) \
58 do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0)
59
60 #define SET_CR_ZERO \
61 SET_CR(0)
62
63 #define SET_XER_ZERO \
64 SET_XER(0)
65
66 #define SET_CR_XER_ZERO \
67 do { SET_CR_ZERO; SET_XER_ZERO; } while (0)
68
69 #define SET_FPSCR_ZERO \
70 do { double _d = 0.0; \
71 __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
72 } while (0)
73
74 #define GET_FPSCR(_arg) \
75 __asm__ __volatile__ ("mffs %0" : "=f"(_arg) )
76
77 #define SET_FPSCR_DRN \
78 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) )
79
80
81 // The assembly-level instructions being tested
_test_drintx(int R,int RMC)82 static void _test_drintx(int R, int RMC)
83 {
84 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) {
85 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC);
86 return;
87 }
88 switch (RMC) {
89 case 0:
90 if (R)
91 __asm__ __volatile__ ("drintx 1, %0, %1, 0" : "=f" (f18) : "f" (f16));
92 else
93 __asm__ __volatile__ ("drintx 0, %0, %1, 0" : "=f" (f18) : "f" (f16));
94 break;
95 case 1:
96 if (R)
97 __asm__ __volatile__ ("drintx 1, %0, %1, 1" : "=f" (f18) : "f" (f16));
98 else
99 __asm__ __volatile__ ("drintx 0, %0, %1, 1" : "=f" (f18) : "f" (f16));
100 break;
101 case 2:
102 if (R)
103 __asm__ __volatile__ ("drintx 1, %0, %1, 2" : "=f" (f18) : "f" (f16));
104 else
105 __asm__ __volatile__ ("drintx 0, %0, %1, 2" : "=f" (f18) : "f" (f16));
106 break;
107 case 3:
108 if (R)
109 __asm__ __volatile__ ("drintx 1, %0, %1, 3" : "=f" (f18) : "f" (f16));
110 else
111 __asm__ __volatile__ ("drintx 0, %0, %1, 3" : "=f" (f18) : "f" (f16));
112 break;
113 default:
114 break;
115 }
116 }
117
_test_drintn(int R,int RMC)118 static void _test_drintn(int R, int RMC)
119 {
120 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) {
121 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC);
122 return;
123 }
124 switch (RMC) {
125 case 0:
126 if (R)
127 __asm__ __volatile__ ("drintn 1, %0, %1, 0" : "=f" (f18) : "f" (f16));
128 else
129 __asm__ __volatile__ ("drintn 0, %0, %1, 0" : "=f" (f18) : "f" (f16));
130 break;
131 case 1:
132 if (R)
133 __asm__ __volatile__ ("drintn 1, %0, %1, 1" : "=f" (f18) : "f" (f16));
134 else
135 __asm__ __volatile__ ("drintn 0, %0, %1, 1" : "=f" (f18) : "f" (f16));
136 break;
137 case 2:
138 if (R)
139 __asm__ __volatile__ ("drintn 1, %0, %1, 2" : "=f" (f18) : "f" (f16));
140 else
141 __asm__ __volatile__ ("drintn 0, %0, %1, 2" : "=f" (f18) : "f" (f16));
142 break;
143 case 3:
144 if (R)
145 __asm__ __volatile__ ("drintn 1, %0, %1, 3" : "=f" (f18) : "f" (f16));
146 else
147 __asm__ __volatile__ ("drintn 0, %0, %1, 3" : "=f" (f18) : "f" (f16));
148 break;
149 default:
150 break;
151 }
152 }
153
154
_test_diex(int a,int b)155 static void _test_diex(int a __attribute__((unused)), int b __attribute__((unused)))
156 {
157 __asm__ __volatile__ ("diex %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
158 }
159
_test_dxex(int a,int b)160 static void _test_dxex(int a __attribute__((unused)), int b __attribute__((unused)))
161 {
162 __asm__ __volatile__ ("dxex %0, %1" : "=f" (f18) : "f" (f16));
163 }
164
_test_dcmpo(int BF,int x)165 static void _test_dcmpo(int BF, int x __attribute__((unused)))
166 {
167 if (BF < 0 || BF > 7) {
168 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF);
169 return;
170 }
171 switch (BF) {
172 case 0:
173 __asm__ __volatile__ ("dcmpo 0, %0, %1" : : "f" (f14),"f" (f16));
174 break;
175 case 1:
176 __asm__ __volatile__ ("dcmpo 1, %0, %1" : : "f" (f14),"f" (f16));
177 break;
178 case 2:
179 __asm__ __volatile__ ("dcmpo 2, %0, %1" : : "f" (f14),"f" (f16));
180 break;
181 case 3:
182 __asm__ __volatile__ ("dcmpo 3, %0, %1" : : "f" (f14),"f" (f16));
183 break;
184 case 4:
185 __asm__ __volatile__ ("dcmpo 4, %0, %1" : : "f" (f14),"f" (f16));
186 break;
187 case 5:
188 __asm__ __volatile__ ("dcmpo 5, %0, %1" : : "f" (f14),"f" (f16));
189 break;
190 case 6:
191 __asm__ __volatile__ ("dcmpo 6, %0, %1" : : "f" (f14),"f" (f16));
192 break;
193 case 7:
194 __asm__ __volatile__ ("dcmpo 7, %0, %1" : : "f" (f14),"f" (f16));
195 break;
196 default:
197 break;
198 }
199 }
200
_test_dcmpu(int BF,int x)201 static void _test_dcmpu(int BF, int x __attribute__((unused)))
202 {
203 if (BF < 0 || BF > 7) {
204 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF);
205 return;
206 }
207 switch (BF) {
208 case 0:
209 __asm__ __volatile__ ("dcmpu 0, %0, %1" : : "f" (f14),"f" (f16));
210 break;
211 case 1:
212 __asm__ __volatile__ ("dcmpu 1, %0, %1" : : "f" (f14),"f" (f16));
213 break;
214 case 2:
215 __asm__ __volatile__ ("dcmpu 2, %0, %1" : : "f" (f14),"f" (f16));
216 break;
217 case 3:
218 __asm__ __volatile__ ("dcmpu 3, %0, %1" : : "f" (f14),"f" (f16));
219 break;
220 case 4:
221 __asm__ __volatile__ ("dcmpu 4, %0, %1" : : "f" (f14),"f" (f16));
222 break;
223 case 5:
224 __asm__ __volatile__ ("dcmpu 5, %0, %1" : : "f" (f14),"f" (f16));
225 break;
226 case 6:
227 __asm__ __volatile__ ("dcmpu 6, %0, %1" : : "f" (f14),"f" (f16));
228 break;
229 case 7:
230 __asm__ __volatile__ ("dcmpu 7, %0, %1" : : "f" (f14),"f" (f16));
231 break;
232 default:
233 break;
234 }
235 }
236
237 // Quad instruction testing
_test_drintxq(int R,int RMC)238 static void _test_drintxq(int R, int RMC)
239 {
240 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) {
241 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC);
242 return;
243 }
244 switch (RMC) {
245 case 0:
246 if (R)
247 __asm__ __volatile__ ("drintxq 1, %0, %1, 0" : "=f" (f18) : "f" (f16));
248 else
249 __asm__ __volatile__ ("drintxq 0, %0, %1, 0" : "=f" (f18) : "f" (f16));
250 break;
251 case 1:
252 if (R)
253 __asm__ __volatile__ ("drintxq 1, %0, %1, 1" : "=f" (f18) : "f" (f16));
254 else
255 __asm__ __volatile__ ("drintxq 0, %0, %1, 1" : "=f" (f18) : "f" (f16));
256 break;
257 case 2:
258 if (R)
259 __asm__ __volatile__ ("drintxq 1, %0, %1, 2" : "=f" (f18) : "f" (f16));
260 else
261 __asm__ __volatile__ ("drintxq 0, %0, %1, 2" : "=f" (f18) : "f" (f16));
262 break;
263 case 3:
264 if (R)
265 __asm__ __volatile__ ("drintxq 1, %0, %1, 3" : "=f" (f18) : "f" (f16));
266 else
267 __asm__ __volatile__ ("drintxq 0, %0, %1, 3" : "=f" (f18) : "f" (f16));
268 break;
269 default:
270 break;
271 }
272 }
273
_test_drintnq(int R,int RMC)274 static void _test_drintnq(int R, int RMC)
275 {
276 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) {
277 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC);
278 return;
279 }
280 switch (RMC) {
281 case 0:
282 if (R)
283 __asm__ __volatile__ ("drintnq 1, %0, %1, 0" : "=f" (f18) : "f" (f16));
284 else
285 __asm__ __volatile__ ("drintnq 0, %0, %1, 0" : "=f" (f18) : "f" (f16));
286 break;
287 case 1:
288 if (R)
289 __asm__ __volatile__ ("drintnq 1, %0, %1, 1" : "=f" (f18) : "f" (f16));
290 else
291 __asm__ __volatile__ ("drintnq 0, %0, %1, 1" : "=f" (f18) : "f" (f16));
292 break;
293 case 2:
294 if (R)
295 __asm__ __volatile__ ("drintnq 1, %0, %1, 2" : "=f" (f18) : "f" (f16));
296 else
297 __asm__ __volatile__ ("drintnq 0, %0, %1, 2" : "=f" (f18) : "f" (f16));
298 break;
299 case 3:
300 if (R)
301 __asm__ __volatile__ ("drintnq 1, %0, %1, 3" : "=f" (f18) : "f" (f16));
302 else
303 __asm__ __volatile__ ("drintnq 0, %0, %1, 3" : "=f" (f18) : "f" (f16));
304 break;
305 default:
306 break;
307 }
308 }
309
_test_diexq(int a,int b)310 static void _test_diexq(int a __attribute__((unused)), int b __attribute__((unused)))
311 {
312 __asm__ __volatile__ ("diexq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
313 }
314
_test_dxexq(int a,int b)315 static void _test_dxexq(int a __attribute__((unused)), int b __attribute__((unused)))
316 {
317 __asm__ __volatile__ ("dxexq %0, %1" : "=f" (f18) : "f" (f16));
318 }
319
_test_dcmpoq(int BF,int x)320 static void _test_dcmpoq(int BF, int x __attribute__((unused)))
321 {
322 if (BF < 0 || BF > 7) {
323 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF );
324 return;
325 }
326 switch (BF) {
327 case 0:
328 __asm__ __volatile__ ("dcmpoq 0, %0, %1" : : "f" (f14),"f" (f16));
329 break;
330 case 1:
331 __asm__ __volatile__ ("dcmpoq 1, %0, %1" : : "f" (f14),"f" (f16));
332 break;
333 case 2:
334 __asm__ __volatile__ ("dcmpoq 2, %0, %1" : : "f" (f14),"f" (f16));
335 break;
336 case 3:
337 __asm__ __volatile__ ("dcmpoq 3, %0, %1" : : "f" (f14),"f" (f16));
338 break;
339 case 4:
340 __asm__ __volatile__ ("dcmpoq 4, %0, %1" : : "f" (f14),"f" (f16));
341 break;
342 case 5:
343 __asm__ __volatile__ ("dcmpoq 5, %0, %1" : : "f" (f14),"f" (f16));
344 break;
345 case 6:
346 __asm__ __volatile__ ("dcmpoq 6, %0, %1" : : "f" (f14),"f" (f16));
347 break;
348 case 7:
349 __asm__ __volatile__ ("dcmpoq 7, %0, %1" : : "f" (f14),"f" (f16));
350 break;
351 default:
352 break;
353 }
354 }
355
_test_dcmpuq(int BF,int x)356 static void _test_dcmpuq(int BF, int x __attribute__((unused)))
357 {
358 if (BF < 0 || BF > 7) {
359 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF);
360 return;
361 }
362 switch (BF) {
363 case 0:
364 __asm__ __volatile__ ("dcmpuq 0, %0, %1" : : "f" (f14),"f" (f16));
365 break;
366 case 1:
367 __asm__ __volatile__ ("dcmpuq 1, %0, %1" : : "f" (f14),"f" (f16));
368 break;
369 case 2:
370 __asm__ __volatile__ ("dcmpuq 2, %0, %1" : : "f" (f14),"f" (f16));
371 break;
372 case 3:
373 __asm__ __volatile__ ("dcmpuq 3, %0, %1" : : "f" (f14),"f" (f16));
374 break;
375 case 4:
376 __asm__ __volatile__ ("dcmpuq 4, %0, %1" : : "f" (f14),"f" (f16));
377 break;
378 case 5:
379 __asm__ __volatile__ ("dcmpuq 5, %0, %1" : : "f" (f14),"f" (f16));
380 break;
381 case 6:
382 __asm__ __volatile__ ("dcmpuq 6, %0, %1" : : "f" (f14),"f" (f16));
383 break;
384 case 7:
385 __asm__ __volatile__ ("dcmpuq 7, %0, %1" : : "f" (f14),"f" (f16));
386 break;
387 default:
388 break;
389 }
390 }
391
_test_drrnd(int x,int RMC)392 static void _test_drrnd(int x __attribute__((unused)), int RMC)
393 {
394 if (RMC < 0 || RMC > 31) {
395 fprintf(stderr, "Invalid input to asm test: a=%d\n", RMC);
396 return;
397 }
398 switch (RMC) {
399 case 0:
400 __asm__ __volatile__ ("drrnd %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16));
401 break;
402 case 1:
403 __asm__ __volatile__ ("drrnd %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16));
404 break;
405 case 2:
406 __asm__ __volatile__ ("drrnd %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16));
407 break;
408 case 3:
409 __asm__ __volatile__ ("drrnd %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16));
410 break;
411 default:
412 break;
413 }
414 }
415
_test_drrndq(int x,int RMC)416 static void _test_drrndq(int x __attribute__((unused)), int RMC)
417 {
418 if (RMC < 0 || RMC > 3) {
419 fprintf(stderr, "Invalid input to asm test: a=%dn", RMC);
420 return;
421 }
422 switch (RMC) {
423 case 0:
424 __asm__ __volatile__ ("drrndq %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16));
425 break;
426 case 1:
427 __asm__ __volatile__ ("drrndq %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16));
428 break;
429 case 2:
430 __asm__ __volatile__ ("drrndq %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16));
431 break;
432 case 3:
433 __asm__ __volatile__ ("drrndq %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16));
434 break;
435 default:
436 break;
437 }
438 }
439
_test_dqua(int x,int RMC)440 static void _test_dqua(int x __attribute__((unused)), int RMC)
441 {
442 if (RMC < 0 || RMC > 3) {
443 fprintf(stderr, "Invalid input to asm test: a=%d\n", RMC);
444 return;
445 }
446 switch (RMC) {
447 case 0:
448 __asm__ __volatile__ ("dqua %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16));
449 break;
450 case 1:
451 __asm__ __volatile__ ("dqua %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16));
452 break;
453 case 2:
454 __asm__ __volatile__ ("dqua %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16));
455 break;
456 case 3:
457 __asm__ __volatile__ ("dqua %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16));
458 break;
459 default:
460 break;
461 }
462 }
463
_test_dquaq(int x,int RMC)464 static void _test_dquaq(int x __attribute__((unused)), int RMC)
465 {
466 if (RMC < 0 || RMC > 3) {
467 fprintf(stderr, "Invalid input to asm test: a=%d\n", RMC);
468 return;
469 }
470 switch (RMC) {
471 case 0:
472 __asm__ __volatile__ ("dquaq %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16));
473 break;
474 case 1:
475 __asm__ __volatile__ ("dquaq %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16));
476 break;
477 case 2:
478 __asm__ __volatile__ ("dquaq %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16));
479 break;
480 case 3:
481 __asm__ __volatile__ ("dquaq %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16));
482 break;
483 default:
484 break;
485 }
486 }
487
488 static int TE_vals[] = { -16, -2, 0, 5};
489 #define TE_VAL_LEN sizeof(TE_vals)/sizeof(int)
__is_TE_val(int x)490 static Bool __is_TE_val(int x)
491 {
492 int i;
493 for (i = 0; i < TE_VAL_LEN; i++) {
494 if (x==TE_vals[i])
495 return True;
496 }
497 return False;
498 }
499
_test_dquai(int TE,int RMC)500 static void _test_dquai(int TE, int RMC)
501 {
502 if (RMC < 0 || RMC > 3 || !__is_TE_val(TE)) {
503 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", TE, RMC);
504 return;
505 }
506 switch (RMC) {
507 case 0:
508 switch (TE) {
509 case -16:
510 __asm__ __volatile__ ("dquai -16, %0, %1, 0" : "=f" (f18) : "f" (f16));
511 break;
512 case -2:
513 __asm__ __volatile__ ("dquai -2, %0, %1, 0" : "=f" (f18) : "f" (f16));
514 break;
515 case 0:
516 __asm__ __volatile__ ("dquai 0, %0, %1, 0" : "=f" (f18) : "f" (f16));
517 break;
518 case 5:
519 __asm__ __volatile__ ("dquai 5, %0, %1, 0" : "=f" (f18) : "f" (f16));
520 break;
521 default:
522 break;
523 }
524 break;
525 case 1:
526 switch (TE) {
527 case -16:
528 __asm__ __volatile__ ("dquai -16, %0, %1, 1" : "=f" (f18) : "f" (f16));
529 break;
530 case -2:
531 __asm__ __volatile__ ("dquai -2, %0, %1, 1" : "=f" (f18) : "f" (f16));
532 break;
533 case 0:
534 __asm__ __volatile__ ("dquai 0, %0, %1, 1" : "=f" (f18) : "f" (f16));
535 break;
536 case 5:
537 __asm__ __volatile__ ("dquai 5, %0, %1, 1" : "=f" (f18) : "f" (f16));
538 break;
539 default:
540 break;
541 }
542 break;
543 case 2:
544 switch (TE) {
545 case -16:
546 __asm__ __volatile__ ("dquai -16, %0, %1, 2" : "=f" (f18) : "f" (f16));
547 break;
548 case -2:
549 __asm__ __volatile__ ("dquai -2, %0, %1, 2" : "=f" (f18) : "f" (f16));
550 break;
551 case 0:
552 __asm__ __volatile__ ("dquai 0, %0, %1, 2" : "=f" (f18) : "f" (f16));
553 break;
554 case 5:
555 __asm__ __volatile__ ("dquai 5, %0, %1, 2" : "=f" (f18) : "f" (f16));
556 break;
557 default:
558 break;
559 }
560 break;
561 case 3:
562 switch (TE) {
563 case -16:
564 __asm__ __volatile__ ("dquai -16, %0, %1, 3" : "=f" (f18) : "f" (f16));
565 break;
566 case -2:
567 __asm__ __volatile__ ("dquai -2, %0, %1, 3" : "=f" (f18) : "f" (f16));
568 break;
569 case 0:
570 __asm__ __volatile__ ("dquai 0, %0, %1, 3" : "=f" (f18) : "f" (f16));
571 break;
572 case 5:
573 __asm__ __volatile__ ("dquai 5, %0, %1, 3" : "=f" (f18) : "f" (f16));
574 break;
575 default:
576 break;
577 }
578 break;
579 default:
580 break;
581 }
582 }
583
_test_dquaiq(int TE,int RMC)584 static void _test_dquaiq(int TE, int RMC)
585 {
586 if (RMC < 0 || RMC > 3 || !__is_TE_val(TE)) {
587 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", TE, RMC);
588 return;
589 }
590 switch (RMC) {
591 case 0:
592 switch (TE) {
593 case -16:
594 __asm__ __volatile__ ("dquaiq -16, %0, %1, 0" : "=f" (f18) : "f" (f16));
595 break;
596 case -2:
597 __asm__ __volatile__ ("dquaiq -2, %0, %1, 0" : "=f" (f18) : "f" (f16));
598 break;
599 case 0:
600 __asm__ __volatile__ ("dquaiq 0, %0, %1, 0" : "=f" (f18) : "f" (f16));
601 break;
602 case 5:
603 __asm__ __volatile__ ("dquaiq 5, %0, %1, 0" : "=f" (f18) : "f" (f16));
604 break;
605 default:
606 break;
607 }
608 break;
609 case 1:
610 switch (TE) {
611 case -16:
612 __asm__ __volatile__ ("dquaiq -16, %0, %1, 1" : "=f" (f18) : "f" (f16));
613 break;
614 case -2:
615 __asm__ __volatile__ ("dquaiq -2, %0, %1, 1" : "=f" (f18) : "f" (f16));
616 break;
617 case 0:
618 __asm__ __volatile__ ("dquaiq 0, %0, %1, 1" : "=f" (f18) : "f" (f16));
619 break;
620 case 5:
621 __asm__ __volatile__ ("dquaiq 5, %0, %1, 1" : "=f" (f18) : "f" (f16));
622 break;
623 default:
624 break;
625 }
626 break;
627 case 2:
628 switch (TE) {
629 case -16:
630 __asm__ __volatile__ ("dquaiq -16, %0, %1, 2" : "=f" (f18) : "f" (f16));
631 break;
632 case -2:
633 __asm__ __volatile__ ("dquaiq -2, %0, %1, 2" : "=f" (f18) : "f" (f16));
634 break;
635 case 0:
636 __asm__ __volatile__ ("dquaiq 0, %0, %1, 2" : "=f" (f18) : "f" (f16));
637 break;
638 case 5:
639 __asm__ __volatile__ ("dquaiq 5, %0, %1, 2" : "=f" (f18) : "f" (f16));
640 break;
641 default:
642 break;
643 }
644 break;
645 case 3:
646 switch (TE) {
647 case -16:
648 __asm__ __volatile__ ("dquaiq -16, %0, %1, 3" : "=f" (f18) : "f" (f16));
649 break;
650 case -2:
651 __asm__ __volatile__ ("dquaiq -2, %0, %1, 3" : "=f" (f18) : "f" (f16));
652 break;
653 case 0:
654 __asm__ __volatile__ ("dquaiq 0, %0, %1, 3" : "=f" (f18) : "f" (f16));
655 break;
656 case 5:
657 __asm__ __volatile__ ("dquaiq 5, %0, %1, 3" : "=f" (f18) : "f" (f16));
658 break;
659 default:
660 break;
661 }
662 break;
663 default:
664 break;
665 }
666 }
667
668
669 typedef void (*test_func_t)(int a, int b);
670 typedef void (*test_driver_func_t)(void);
671 typedef struct test_table
672 {
673 test_driver_func_t test_category;
674 char * name;
675 } test_table_t;
676
677 /*
678 * 345.0DD (0x2207c00000000000 0xe50)
679 * 1.2300e+5DD (0x2207c00000000000 0x14c000)
680 * -16.0DD (0xa207c00000000000 0xe0)
681 * 0.00189DD (0x2206c00000000000 0xcf)
682 * -4.1235DD (0xa205c00000000000 0x10a395bcf)
683 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
684 * 0DD (0x2208000000000000 0x0)
685 * 0DD (0x2208000000000000 0x0)
686 * infDD (0x7800000000000000 0x0)
687 * nanDD (0x7c00000000000000 0x0
688 */
689 static unsigned long long dfp128_vals[] = {
690 // Some finite numbers
691 0x2207c00000000000ULL, 0x0000000000000e50ULL,
692 0x2207c00000000000ULL, 0x000000000014c000ULL,
693 0xa207c00000000000ULL, 0x00000000000000e0ULL,
694 0x2206c00000000000ULL, 0x00000000000000cfULL,
695 0xa205c00000000000ULL, 0x000000010a395bcfULL,
696 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
697 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
698 // flavors of zero
699 0x2208000000000000ULL, 0x0000000000000000ULL,
700 0xa208000000000000ULL, 0x0000000000000000ULL, // negative
701 0xa248000000000000ULL, 0x0000000000000000ULL,
702 // flavors of NAN
703 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
704 0xfc00000000000000ULL, 0xc00100035b007700ULL,
705 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
706 // flavors of Infinity
707 0x7800000000000000ULL, 0x0000000000000000ULL,
708 0xf800000000000000ULL, 0x0000000000000000ULL, // negative
709 0xf900000000000000ULL, 0x0000000000000000ULL
710 };
711
712 static unsigned long long dfp64_vals[] = {
713 // various finite numbers
714 0x2234000000000e50ULL,
715 0x223400000014c000ULL,
716 0xa2340000000000e0ULL,// negative
717 0x22240000000000cfULL,
718 0xa21400010a395bcfULL,// negative
719 0x6e4d3f1f534acdd4ULL,// huge number
720 0x000400000089b000ULL,// very small number
721 // flavors of zero
722 0x2238000000000000ULL,
723 0xa238000000000000ULL,
724 0x4248000000000000ULL,
725 // flavors of NAN
726 0x7e34000000000111ULL,
727 0xfe000000d0e0a0d0ULL,//signaling
728 0xfc00000000000000ULL,//quiet
729 // flavors of Infinity
730 0x7800000000000000ULL,
731 0xf800000000000000ULL,//negative
732 0x7a34000000000000ULL,
733 };
734
735 // Both Long and Quad arrays of DFP values should have the same length.
736 // If that length is changed, t
737 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8)
738
739 typedef struct dfp_test_args {
740 int fra_idx;
741 int frb_idx;
742 } dfp_test_args_t;
743
744
745 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests
746 static dfp_test_args_t dfp_2args_x1[] = {
747 {0, 1},
748 {2, 1},
749 {3, 4},
750 {0, 6},
751 {2, 4},
752 {5, 1},
753 {5, 2},
754 {7, 1},
755 {7, 2},
756 {8, 0},
757 {8, 1},
758 {8, 2},
759 {7, 8},
760 {12, 14},
761 {12, 1},
762 {12, 13},
763 {12, 12},
764 {12, 11},
765 {11, 14},
766 {11, 0},
767 {11, 13},
768 {11, 11},
769 {14, 14},
770 {14, 3},
771 {14, 15},
772 };
773
774 typedef enum {
775 LONG_TEST,
776 QUAD_TEST
777 } precision_type_t;
778
779 typedef struct dfp_test
780 {
781 test_func_t test_func;
782 const char * name;
783 dfp_test_args_t * targs;
784 int num_tests;
785 precision_type_t precision;
786 const char * op;
787 } dfp_test_t;
788
789 typedef struct dfp_one_arg_test
790 {
791 test_func_t test_func;
792 const char * name;
793 precision_type_t precision;
794 const char * op;
795 } dfp_one_arg_test_t;
796
797
798 static dfp_one_arg_test_t
799 dfp_quai_tests[] = {
800 { &_test_dquai, "dquai", LONG_TEST, "[QI]"},
801 { &_test_dquaiq, "dquaiq", QUAD_TEST, "[QI]"},
802 { NULL, NULL, 0, NULL}
803 };
804
test_dfp_quai_ops(void)805 static void test_dfp_quai_ops(void)
806 {
807 test_func_t func;
808 unsigned long long u0, u0x;
809 double res, d0, *d0p, d0x, *d0xp;
810
811 int k = 0;
812 u0 = u0x = 0;
813 d0p = &d0;
814 d0xp = &d0x;
815
816 while ((func = dfp_quai_tests[k].test_func)) {
817 int i;
818 dfp_one_arg_test_t test_def = dfp_quai_tests[k];
819
820 for (i = 0; i < NUM_DFP_VALS; i++) {
821 int TE, RMC;
822
823 if (test_def.precision == LONG_TEST) {
824 u0 = dfp64_vals[i];
825 } else {
826 u0 = dfp128_vals[i * 2];
827 u0x = dfp128_vals[(i * 2) + 1];
828 }
829 *(unsigned long long *)d0p = u0;
830 f16 = d0;
831 if (test_def.precision == QUAD_TEST) {
832 *(unsigned long long *)d0xp = u0x;
833 f17 = d0x;
834 }
835
836 for (TE = 0; TE < TE_VAL_LEN; TE++) {
837 for (RMC = 0; RMC < 4; RMC++) {
838 (*func)(TE_vals[TE], RMC);
839 res = f18;
840 printf("%s (RMC=%2d, TE=%3d) %s %016llx", test_def.name, RMC,
841 TE_vals[TE], test_def.op, u0);
842 if (test_def.precision == LONG_TEST) {
843 printf(" => %016llx\n",
844 *((unsigned long long *)(&res)));
845 } else {
846 double resx = f19;
847 printf(" %016llx ==> %016llx %016llx\n",
848 u0x, *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
849 }
850 }
851 }
852 }
853 k++;
854 printf( "\n" );
855 }
856 }
857
858
859 static dfp_test_t
860 dfp_qua_tests[] = {
861 { &_test_dqua, "dqua", dfp_2args_x1, 25, LONG_TEST, "[Q]"},
862 { &_test_dquaq, "dquaq", dfp_2args_x1, 25, QUAD_TEST, "[Q]"},
863 { NULL, NULL, NULL, 0, 0, NULL}
864 };
865
test_dfp_qua_ops(void)866 static void test_dfp_qua_ops(void)
867 {
868 test_func_t func;
869 unsigned long long u0, u0x, u1, u1x;
870 double res, d0, d1, *d0p, *d1p;
871 double d0x, d1x, *d0xp, *d1xp;
872 int k = 0;
873 u0x = u1x = 0;
874 d0p = &d0;
875 d0xp = &d0x;
876 d1p = &d1;
877 d1xp = &d1x;
878
879 while ((func = dfp_qua_tests[k].test_func)) {
880 int i, RMC;
881 dfp_test_t test_def = dfp_qua_tests[k];
882
883 for (i = 0; i < test_def.num_tests; i++) {
884 if (test_def.precision == LONG_TEST) {
885 u0 = dfp64_vals[test_def.targs[i].fra_idx];
886 u1 = dfp64_vals[test_def.targs[i].frb_idx];
887 } else {
888 u0 = dfp128_vals[test_def.targs[i].fra_idx * 2];
889 u0x = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1];
890 u1 = dfp128_vals[test_def.targs[i].frb_idx * 2];
891 u1x = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1];
892 }
893 *(unsigned long long *)d0p = u0;
894 *(unsigned long long *)d1p = u1;
895 f14 = d0;
896 f16 = d1;
897 if (test_def.precision == QUAD_TEST) {
898 *(unsigned long long *)d0xp = u0x;
899 *(unsigned long long *)d1xp = u1x;
900 f15 = d0x;
901 f17 = d1x;
902 }
903 for (RMC = 0; RMC < 4; RMC++) {
904 (*func)(-1, RMC);
905 res = f18;
906 printf("%s (RMC=%2d) %s %016llx", test_def.name, RMC, test_def.op, u0);
907 if (test_def.precision == LONG_TEST) {
908 printf(", %016llx => %016llx\n", u1, *((unsigned long long *)(&res)));
909 } else {
910 double resx = f19;
911 printf(" %016llx, %016llx %016llx ==> %016llx %016llx\n",u0x, u1, u1x,
912 *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
913 }
914 }
915 }
916 k++;
917 printf( "\n" );
918 }
919 }
920
921
922 static dfp_one_arg_test_t
923 dfp_rrnd_tests[] = {
924 { &_test_drrnd, "drrnd", LONG_TEST, "[RR]"},
925 { &_test_drrndq, "drrndq", QUAD_TEST, "[RR]"},
926 { NULL, NULL, 0, NULL}
927 };
928
test_dfp_rrnd_ops(void)929 static void test_dfp_rrnd_ops(void)
930 {
931 test_func_t func;
932 unsigned long long u0, u0x;
933 double res, d0, *d0p, d0x, *d0xp, reference_sig, *reference_sig_p;
934 long long reference_sig_vals[] = {0ULL, 2ULL, 6ULL, 63ULL};
935 int num_reference_sig_vals = sizeof(reference_sig_vals)/sizeof(long long);
936
937 int k = 0;
938 u0 = u0x = 0;
939 d0p = &d0;
940 d0xp = &d0x;
941 reference_sig_p = &reference_sig;
942
943 while ((func = dfp_rrnd_tests[k].test_func)) {
944 int i, j;
945 dfp_one_arg_test_t test_def = dfp_rrnd_tests[k];
946
947 for (i = 0; i < NUM_DFP_VALS; i++) {
948 int RMC;
949
950 if (test_def.precision == LONG_TEST) {
951 u0 = dfp64_vals[i];
952 } else {
953 u0 = dfp128_vals[i * 2];
954 u0x = dfp128_vals[(i * 2) + 1];
955 }
956 *(unsigned long long *)d0p = u0;
957 f16 = d0;
958 if (test_def.precision == QUAD_TEST) {
959 *(unsigned long long *)d0xp = u0x;
960 f17 = d0x;
961 }
962
963 for (j = 0; j < num_reference_sig_vals; j++) {
964 *(long long *)reference_sig_p = reference_sig_vals[j];
965 f14 = reference_sig;
966 for (RMC = 0; RMC < 4; RMC++) {
967 (*func)(-1, RMC);
968 res = f18;
969 printf("%s (RMC=%d, ref sig=%d) %s%016llx", test_def.name, RMC,
970 (int)reference_sig_vals[j], test_def.op, u0);
971 if (test_def.precision == LONG_TEST) {
972 printf(" => %016llx\n",
973 *((unsigned long long *)(&res)));
974 } else {
975 double resx = f19;
976 printf(" %016llx ==> %016llx %016llx\n",
977 u0x, *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
978 }
979 }
980 }
981 }
982 k++;
983 printf( "\n" );
984 }
985 }
986
987
988 static dfp_one_arg_test_t
989 dfp_xiex_tests[] = {
990 { &_test_diex, "diex", LONG_TEST, ">>"},
991 { &_test_diexq, "diexq", QUAD_TEST, ">>"},
992 { &_test_dxex, "dxex", LONG_TEST, "<<"},
993 { &_test_dxexq, "dxexq", QUAD_TEST, "<<"},
994 { NULL, NULL, 0, NULL}
995 };
996
test_dfp_xiex_ops(void)997 static void test_dfp_xiex_ops(void)
998 {
999 test_func_t func;
1000 unsigned long long u0, u0x;
1001 double res, d0, *d0p, d0x, *d0xp, target_exp, *target_exp_p;
1002 /* The first two positions are placeholders and will be filled in later,
1003 * based on the precision of the DFP argument.
1004 */
1005 long long target_exp_vals[] = {0ULL, 0ULL, 0ULL, -1ULL, -2ULL, -3ULL, -4ULL, -5ULL};
1006 int num_exp_vals = sizeof(target_exp_vals)/sizeof(long long);
1007 int k = 0;
1008 u0 = u0x = 0;
1009 d0p = &d0;
1010 d0xp = &d0x;
1011 target_exp_p = &target_exp;
1012
1013 while ((func = dfp_xiex_tests[k].test_func)) {
1014 int i;
1015 Bool insert_insn = False;
1016 dfp_one_arg_test_t test_def = dfp_xiex_tests[k];
1017
1018 if (!strncmp(test_def.name, "di", 2))
1019 insert_insn = True;
1020
1021 if (test_def.precision == QUAD_TEST) {
1022 target_exp_vals[0] = 12288ULL; // > max biased exponent
1023 target_exp_vals[1] = 5235ULL;
1024 } else {
1025 target_exp_vals[0] = 768ULL; // > max biased exponent
1026 target_exp_vals[1] = 355ULL;
1027 }
1028
1029 for (i = 0; i < NUM_DFP_VALS; i++) {
1030 unsigned int j;
1031
1032 if (test_def.precision == QUAD_TEST) {
1033 u0 = dfp128_vals[i * 2];
1034 u0x = dfp128_vals[(i * 2) + 1];
1035 } else {
1036 u0 = dfp64_vals[i];
1037 }
1038 *(unsigned long long *)d0p = u0;
1039 f16 = d0;
1040 if (test_def.precision == QUAD_TEST) {
1041 *(unsigned long long *)d0xp = u0x;
1042 f17 = d0x;
1043 }
1044
1045 if (!insert_insn) {
1046 // This is just for extract insns (dexex[q])
1047 (*func)(0, 0);
1048 res = f18;
1049 printf("%s %s ", test_def.name, test_def.op);
1050 if (test_def.precision == LONG_TEST) {
1051 printf("%016llx => %016llx\n", u0,
1052 *((unsigned long long *)(&res)));
1053 } else {
1054 double resx = f19;
1055 printf("%016llx %016llx ==> %016llx %016llx\n", u0, u0x,
1056 *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
1057 }
1058 continue;
1059 }
1060 // The following for-loop is just for insert insns (diex[q])
1061 for (j = 0; j < num_exp_vals; j++) {
1062 *(long long *)target_exp_p = target_exp_vals[j];
1063 f14 = target_exp;
1064 (*func)(0, 0);
1065 res = f18;
1066 printf("%s %s %5d, ", test_def.name, test_def.op, (int)target_exp_vals[j]);
1067
1068 if (test_def.precision == LONG_TEST) {
1069 printf("%016llx => %016llx\n", u0,
1070 *((unsigned long long *)(&res)));
1071 } else {
1072 double resx = f19;
1073 printf("%016llx %016llx ==> %016llx %016llx\n", u0, u0x,
1074 *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
1075 }
1076 }
1077 }
1078 k++;
1079 printf( "\n" );
1080 }
1081 }
1082
1083 static dfp_one_arg_test_t
1084 dfp_rint_tests[] = {
1085 { &_test_drintn, "drintn", LONG_TEST, "~"},
1086 { &_test_drintnq, "drintnq", QUAD_TEST, "~"},
1087 { &_test_drintx, "drintx", LONG_TEST, "~"},
1088 { &_test_drintxq, "drintxq", QUAD_TEST, "~"},
1089 { NULL, NULL, 0, NULL}
1090 };
1091
test_dfp_rint_ops(void)1092 static void test_dfp_rint_ops(void)
1093 {
1094 test_func_t func;
1095 unsigned long long u0, u0x;
1096 double res, d0, *d0p, d0x, *d0xp;
1097 int k = 0;
1098 u0 = u0x = 0;
1099 d0p = &d0;
1100 d0xp = &d0x;
1101
1102 while ((func = dfp_rint_tests[k].test_func)) {
1103 int i;
1104 dfp_one_arg_test_t test_def = dfp_rint_tests[k];
1105
1106 for (i = 0; i < NUM_DFP_VALS; i++) {
1107 int R, RMC;
1108
1109 if (test_def.precision == LONG_TEST) {
1110 u0 = dfp64_vals[i];
1111 } else {
1112 u0 = dfp128_vals[i * 2];
1113 u0x = dfp128_vals[(i * 2) + 1];
1114 }
1115 *(unsigned long long *)d0p = u0;
1116 f16 = d0;
1117 if (test_def.precision == QUAD_TEST) {
1118 *(unsigned long long *)d0xp = u0x;
1119 f17 = d0x;
1120 }
1121
1122 for (R = 0; R < 2; R++) {
1123 for (RMC = 0; RMC < 4; RMC++) {
1124 (*func)(R, RMC);
1125 res = f18;
1126 printf("%s (RM=%d) %s%016llx", test_def.name, (RMC + (R << 2)), test_def.op, u0);
1127 if (test_def.precision == LONG_TEST) {
1128 printf(" => %016llx\n",
1129 *((unsigned long long *)(&res)));
1130 } else {
1131 double resx = f19;
1132 printf(" %016llx ==> %016llx %016llx\n",
1133 u0x, *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
1134 }
1135 }
1136 }
1137 }
1138 k++;
1139 printf( "\n" );
1140 }
1141 }
1142
1143 static dfp_test_t
1144 dfp_cmp_tests[] = {
1145 { &_test_dcmpo, "dcmpo", dfp_2args_x1, 25, LONG_TEST, "<>"},
1146 { &_test_dcmpoq, "dcmpoq", dfp_2args_x1, 25, QUAD_TEST, "<>"},
1147 { &_test_dcmpu, "dcmpu", dfp_2args_x1, 25, LONG_TEST, "<>"},
1148 { &_test_dcmpuq, "dcmpuq", dfp_2args_x1, 25, QUAD_TEST, "<>"},
1149 { NULL, NULL, NULL, 0, 0, NULL}
1150 };
1151
test_dfp_cmp_ops(void)1152 static void test_dfp_cmp_ops(void)
1153 {
1154 test_func_t func;
1155 unsigned long long u0, u0x, u1, u1x;
1156 double d0, d1, *d0p, *d1p;
1157 double d0x, d1x, *d0xp, *d1xp;
1158 /* BF is a 3-bit instruction field that indicates the CR field in which the
1159 * result of the compare should be placed. We won't iterate through all
1160 * 8 possible BF values since storing compare results to a given field is
1161 * a well-tested mechanism in VEX. But we will test two BF values, just as
1162 * a sniff-test.
1163 */
1164 int k = 0, BF;
1165 u0x = u1x = 0;
1166 d0p = &d0;
1167 d0xp = &d0x;
1168 d1p = &d1;
1169 d1xp = &d1x;
1170
1171 while ((func = dfp_cmp_tests[k].test_func)) {
1172 int i, repeat = 1;
1173 dfp_test_t test_def = dfp_cmp_tests[k];
1174 BF = 0;
1175
1176 again:
1177 for (i = 0; i < test_def.num_tests; i++) {
1178 unsigned int condreg;
1179 unsigned int flags;
1180
1181 if (test_def.precision == LONG_TEST) {
1182 u0 = dfp64_vals[test_def.targs[i].fra_idx];
1183 u1 = dfp64_vals[test_def.targs[i].frb_idx];
1184 } else {
1185 u0 = dfp128_vals[test_def.targs[i].fra_idx * 2];
1186 u0x = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1];
1187 u1 = dfp128_vals[test_def.targs[i].frb_idx * 2];
1188 u1x = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1];
1189 }
1190 *(unsigned long long *)d0p = u0;
1191 *(unsigned long long *)d1p = u1;
1192 f14 = d0;
1193 f16 = d1;
1194 if (test_def.precision == QUAD_TEST) {
1195 *(unsigned long long *)d0xp = u0x;
1196 *(unsigned long long *)d1xp = u1x;
1197 f15 = d0x;
1198 f17 = d1x;
1199 }
1200
1201 SET_FPSCR_ZERO;
1202 SET_CR_XER_ZERO;
1203 (*func)(BF, 0);
1204 GET_CR(flags);
1205
1206 condreg = ((flags >> (4 * (7-BF)))) & 0xf;
1207 printf("%s %016llx", test_def.name, u0);
1208 if (test_def.precision == LONG_TEST) {
1209 printf(" %s %016llx => %x (BF=%d)\n",
1210 test_def.op, u1, condreg, BF);
1211 } else {
1212 printf(" %016llx %s %016llx %016llx ==> %x (BF=%d)\n",
1213 u0x, test_def.op, u1, u1x,
1214 condreg, BF);
1215 }
1216 }
1217 if (repeat) {
1218 repeat = 0;
1219 BF = 5;
1220 goto again;
1221 }
1222 k++;
1223 printf( "\n" );
1224 }
1225 }
1226
1227
1228 static test_table_t
1229 all_tests[] =
1230 {
1231 { &test_dfp_cmp_ops,
1232 "Test DFP compare instructions"},
1233 { &test_dfp_rint_ops,
1234 "Test DFP round instructions"},
1235 { &test_dfp_xiex_ops,
1236 "Test DFP insert/extract instructions"},
1237 { &test_dfp_rrnd_ops,
1238 "Test DFP reround instructions"},
1239 { &test_dfp_qua_ops,
1240 "Test DFP quantize instructions"},
1241 { &test_dfp_quai_ops,
1242 "Test DFP quantize immediate instructions"},
1243 { NULL, NULL }
1244 };
1245 #endif // HAS_DFP
1246
main()1247 int main() {
1248 #if defined(HAS_DFP)
1249
1250 test_table_t aTest;
1251 test_driver_func_t func;
1252 int i = 0;
1253
1254 while ((func = all_tests[i].test_category)) {
1255 aTest = all_tests[i];
1256 printf( "%s\n", aTest.name );
1257 (*func)();
1258 i++;
1259 }
1260
1261 #endif // HAS_DFP
1262 return 0;
1263 }
1264