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
30register double f14 __asm__ ("fr14");
31register double f15 __asm__ ("fr15");
32register double f16 __asm__ ("fr16");
33register double f17 __asm__ ("fr17");
34register double f18 __asm__ ("fr18");
35register double f19 __asm__ ("fr19");
36
37
38typedef 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
82static 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
118static 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
155static 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
160static void _test_dxex(int a __attribute__((unused)), int b __attribute__((unused)))
161{
162   __asm__ __volatile__ ("dxex  %0, %1" : "=f" (f18) : "f" (f16));
163}
164
165static 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
201static 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
238static 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
274static 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
310static 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
315static void _test_dxexq(int a __attribute__((unused)), int b __attribute__((unused)))
316{
317   __asm__ __volatile__ ("dxexq  %0, %1" : "=f" (f18) : "f" (f16));
318}
319
320static 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
356static 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
392static 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
416static 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
440static 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
464static 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
488static int TE_vals[] = { -16, -2, 0, 5};
489#define TE_VAL_LEN sizeof(TE_vals)/sizeof(int)
490static 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
500static 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
584static 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
669typedef void (*test_func_t)(int a, int b);
670typedef void (*test_driver_func_t)(void);
671typedef 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 */
689static 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
712static 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
739typedef 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
746static 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
774typedef enum {
775   LONG_TEST,
776   QUAD_TEST
777} precision_type_t;
778
779typedef 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
789typedef 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
798static dfp_one_arg_test_t
799dfp_quai_tests[] = {
800                    { &_test_dquai, "dquai", LONG_TEST, "[QI]"},
801                    { &_test_dquaiq, "dquaiq", QUAD_TEST, "[QI]"},
802                    { NULL, NULL, 0, NULL}
803};
804
805static 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
859static dfp_test_t
860dfp_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
866static 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
922static dfp_one_arg_test_t
923dfp_rrnd_tests[] = {
924                    { &_test_drrnd, "drrnd", LONG_TEST, "[RR]"},
925                    { &_test_drrndq, "drrndq", QUAD_TEST, "[RR]"},
926                    { NULL, NULL, 0, NULL}
927};
928
929static 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
988static dfp_one_arg_test_t
989dfp_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
997static 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
1083static dfp_one_arg_test_t
1084dfp_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
1092static 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
1143static dfp_test_t
1144dfp_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
1152static 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
1176again:
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
1228static 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
1247int 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