1 /* PFPO.C       (c) Copyright Roger Bowler, 2007                     */
2 /*              Perform Floating Point Operation instruction         */
3 
4 /*              (c) Copyright Bernard van der Helm, 2009             */
5 /*              Noordwijkerhout, The Netherlands                     */
6 
7 /*-------------------------------------------------------------------*/
8 /* This module implements the Perform Floating Point Operation       */
9 /* instruction described in the manual SA22-7832-05.                 */
10 /*-------------------------------------------------------------------*/
11 
12 #include "hstdinc.h"
13 
14 #if !defined(_HENGINE_DLL_)
15 #define _HENGINE_DLL_
16 #endif
17 
18 #if !defined(_PFPO_C_)
19 #define _PFPO_C_
20 #endif
21 
22 #include "hercules.h"
23 #include "opcode.h"
24 #include "inline.h"
25 
26 #include "decimal128.h"
27 #include "decimal64.h"
28 #include "decimal32.h"
29 #include "decPacked.h"
30 
31 #if defined(FEATURE_PFPO)
32 
33 #define CLASS_ZERO      1
34 #define CLASS_SUBNORMAL 2
35 #define CLASS_INFINITY  3
36 #define CLASS_QNAN      4
37 #define CLASS_SNAN      5
38 #define CLASS_NORMAL    6
39 
40 #define INFINITYSTR     "Infinity"
41 #define QNANSTR         "NaN"
42 #define SNANSTR         "sNaN"
43 
44 typedef struct
45 {
46   unsigned base;
47   unsigned class;
48   char str[256];
49 }
50 PFPO_FLOAT;
51 
52 #if 0 // PFPO not yet implemented
53 /*-------------------------------------------------------------------*/
54 /* Binary floating point routines                                    */
55 /*-------------------------------------------------------------------*/
56 
57 static void BFPshortGet(PFPO_FLOAT *f, U32 r)
58 {
59   unsigned exp;
60   U32 frac;
61   unsigned i;
62   U32 mask;
63   unsigned sign;
64 
65   sign = r & 0x80000000 ? 1 : 0;
66   exp = (r & 0x7f800000) >> 23;
67   frac = r & 0x007fffff;
68 
69   if(exp == 127)
70   {
71     if(!frac)
72       f->class = CLASS_ZERO;
73     else
74       f->class = CLASS_SUBNORMAL;
75   }
76   else if(exp == 0xff)
77   {
78     if(!frac)
79       f->class = CLASS_INFINITY;
80     else
81     {
82       if(frac & 0x80000000)
83         f->class = CLASS_QNAN;
84       else
85         f->class = CLASS_SNAN;
86     }
87   }
88   else
89     f->class = CLASS_NORMAL;
90 
91   f->base = 2;
92   switch(f->class)
93   {
94     case CLASS_ZERO:
95       strcpy(f->str, "0");
96       break;
97 
98     case CLASS_INFINITY:
99       if(sign)
100         strcpy(f->str, "-" INFINITYSTR);
101       else
102         strcpy(f->str, INFINITYSTR);
103       break;
104 
105     case CLASS_QNAN:
106       strcpy(f->str, QNANSTR);
107       break;
108 
109     case CLASS_SNAN:
110       strcpy(f->str, SNANSTR);
111       break;
112 
113     case CLASS_NORMAL:
114     case CLASS_SUBNORMAL:
115       if(sign)
116         strcpy(f->str, "-0.");
117       else
118         strcpy(f->str, "0.");
119       if(f->class == CLASS_NORMAL)
120         strcat(f->str, "1");
121       else
122         strcat(f->str, "0");
123       mask = 0x00400000;
124       for(i = 0; i < 23; i++)
125       {
126         if(frac & mask)
127           strcat(f->str, "1");
128         else
129           strcat(f->str, "0");
130         mask >>= 1;
131       }
132       strcat(f->str, "@");
133       if(f->class == CLASS_NORMAL)
134         sprintf(&f->str[strlen(f->str)], "%d", exp - 127);
135       else
136         strcat(f->str, "1");
137       break;
138   }
139 }
140 
141 static void BFPlongGet(PFPO_FLOAT *f, U64 r)
142 {
143   unsigned exp;
144   U64 frac;
145   unsigned i;
146   U64 mask;
147   unsigned sign;
148 
149   sign = r & 0x8000000000000000 ? 1 : 0;
150   exp = (r & 0x7ff0000000000000) >> 52;
151   frac = r & 0x000fffffffffffff;
152 
153   if(exp == 1023)
154   {
155     if(!frac)
156       f->class = CLASS_ZERO;
157     else
158       f->class = CLASS_SUBNORMAL;
159   }
160   else if(exp == 0x7ff)
161   {
162     if(!frac)
163       f->class = CLASS_INFINITY;
164     else
165     {
166       if(frac & 0x8000000000000000)
167         f->class = CLASS_QNAN;
168       else
169         f->class = CLASS_SNAN;
170     }
171   }
172   else
173     f->class = CLASS_NORMAL;
174 
175   f->base = 2;
176   switch(f->class)
177   {
178     case CLASS_ZERO:
179       strcpy(f->str, "0");
180       break;
181 
182     case CLASS_INFINITY:
183       if(sign)
184         strcpy(f->str, "-" INFINITYSTR);
185       else
186         strcpy(f->str, INFINITYSTR);
187       break;
188 
189     case CLASS_QNAN:
190       strcpy(f->str, QNANSTR);
191       break;
192 
193     case CLASS_SNAN:
194       strcpy(f->str, SNANSTR);
195       break;
196 
197     case CLASS_NORMAL:
198     case CLASS_SUBNORMAL:
199       if(sign)
200         strcpy(f->str, "-0.");
201       else
202         strcpy(f->str, "0.");
203       if(f->class == CLASS_NORMAL)
204         strcat(f->str, "1");
205       else
206         strcat(f->str, "0");
207       mask = 0x0008000000000000;
208       for(i = 0; i < 52; i++)
209       {
210         if(frac & mask)
211           strcat(f->str, "1");
212         else
213           strcat(f->str, "0");
214         mask >>= 1;
215       }
216       strcat(f->str, "@");
217       if(f->class == CLASS_NORMAL)
218         sprintf(&f->str[strlen(f->str)], "%d", exp - 1023);
219       else
220         strcat(f->str, "1");
221       break;
222   }
223 }
224 
225 static void BFPextGet(PFPO_FLOAT *f, U64 h, U64 l)
226 {
227   unsigned exp;
228   U64 frach;
229   U64 fracl;
230   unsigned i;
231   U64 mask;
232   unsigned sign;
233 
234   sign = h & 0x8000000000000000 ? 1 : 0;
235   exp = (h & 0x7fff000000000000) >> 48;
236   frach = h & 0x0000ffffffffffff;
237   fracl = l;
238 
239   if(exp == 16383)
240   {
241     if(!frach && !fracl)
242       f->class = CLASS_ZERO;
243     else
244       f->class = CLASS_SUBNORMAL;
245   }
246   else if(exp == 0x7fff)
247   {
248     if(!frach && !fracl)
249       f->class = CLASS_INFINITY;
250     else
251     {
252       if(frach & 0x8000000000000000)
253         f->class = CLASS_QNAN;
254       else
255         f->class = CLASS_SNAN;
256     }
257   }
258   else
259     f->class = CLASS_NORMAL;
260 
261   f->base = 2;
262   switch(f->class)
263   {
264     case CLASS_ZERO:
265       strcpy(f->str, "0");
266       break;
267 
268     case CLASS_INFINITY:
269       if(sign)
270         strcpy(f->str, "-" INFINITYSTR);
271       else
272         strcpy(f->str, INFINITYSTR);
273       break;
274 
275     case CLASS_QNAN:
276       strcpy(f->str, QNANSTR);
277       break;
278 
279     case CLASS_SNAN:
280       strcpy(f->str, SNANSTR);
281       break;
282 
283     case CLASS_NORMAL:
284     case CLASS_SUBNORMAL:
285       if(sign)
286         strcpy(f->str, "-0.");
287       else
288         strcpy(f->str, "0.");
289       if(f->class == CLASS_NORMAL)
290         strcat(f->str, "1");
291       else
292         strcat(f->str, "0");
293       mask = 0x0000800000000000;
294       for(i = 0; i < 48; i++)
295       {
296         if(frach & mask)
297           strcat(f->str, "1");
298         else
299           strcat(f->str, "0");
300         mask >>= 1;
301       }
302       mask = 0x8000000000000000;
303       for(i = 0; i < 64; i++)
304       {
305         if(fracl & mask)
306           strcat(f->str, "1");
307         else
308           strcat(f->str, "0");
309         mask >>= 1;
310       }
311       strcat(f->str, "@");
312       if(f->class == CLASS_NORMAL)
313         sprintf(&f->str[strlen(f->str)], "%d", exp - 16383);
314       else
315         strcat(f->str, "1");
316       break;
317   }
318 }
319 
320 /*-------------------------------------------------------------------*/
321 /* Decimal floating point routines                                   */
322 /*-------------------------------------------------------------------*/
323 
324 static void DFPshortGet(PFPO_FLOAT *f, U32 r)
325 {
326   decimal32 dec32;
327   unsigned i;
328   U32 temp;
329 
330   temp = r;
331   for(i = 0; i < 4; i++)
332   {
333     dec32.bytes[i] = temp & 0xff;
334     temp >>= 8;
335   }
336   decimal32ToString(&dec32, f->str);
337 
338   f->base = 10;
339   if(!strncmp(f->str, "-0E", 2) || !strncmp(f->str, "0E", 2))
340     f->class = CLASS_ZERO;
341   else if(strstr(f->str, "E0"))
342     f->class = CLASS_SUBNORMAL;
343   else if(!strcmp(f->str, "Ininity"))
344     f->class = CLASS_INFINITY;
345   else if(!strcmp(f->str, "NaN"))
346     f->class = CLASS_QNAN;
347   else if(!strcmp(f->str, "sNaN"))
348     f->class = CLASS_SNAN;
349   else
350     f->class = CLASS_NORMAL;
351 }
352 
353 static void DFPlongGet(PFPO_FLOAT *f, U64 r)
354 {
355   decimal64 dec64;
356   unsigned i;
357   U64 temp;
358 
359   temp = r;
360   for(i = 0; i < 8; i++)
361   {
362     dec64.bytes[i] = temp & 0xff;
363     temp >>= 8;
364   }
365   decimal64ToString(&dec64, f->str);
366 
367   f->base = 10;
368   if(!strncmp(f->str, "-0E", 2) || !strncmp(f->str, "0E", 2))
369     f->class = CLASS_ZERO;
370   else if(strstr(f->str, "E0"))
371     f->class = CLASS_SUBNORMAL;
372   else if(!strcmp(f->str, "Ininity"))
373     f->class = CLASS_INFINITY;
374   else if(!strcmp(f->str, "NaN"))
375     f->class = CLASS_QNAN;
376   else if(!strcmp(f->str, "sNaN"))
377     f->class = CLASS_SNAN;
378   else
379     f->class = CLASS_NORMAL;
380 }
381 
382 static void DFPextGet(PFPO_FLOAT *f, U64 h, U64 l)
383 {
384   decimal128 dec128;
385   unsigned i;
386   U64 temph;
387   U64 templ;
388 
389   temph = h;
390   templ = l;
391 
392   for(i = 0; i < 8; i++)
393   {
394     dec128.bytes[i] = templ & 0xff;
395     dec128.bytes[i + 8] = temph & 0xff;
396     templ >>= 8;
397     temph >>= 8;
398   }
399   decimal128ToString(&dec128, f->str);
400 
401   f->base = 10;
402   if(!strncmp(f->str, "-0E", 2) || !strncmp(f->str, "0E", 2))
403     f->class = CLASS_ZERO;
404   else if(strstr(f->str, "E0"))
405     f->class = CLASS_SUBNORMAL;
406   else if(!strcmp(f->str, "Ininity"))
407     f->class = CLASS_INFINITY;
408   else if(!strcmp(f->str, "NaN"))
409     f->class = CLASS_QNAN;
410   else if(!strcmp(f->str, "sNaN"))
411     f->class = CLASS_SNAN;
412   else
413     f->class = CLASS_NORMAL;
414 }
415 
416 /*-------------------------------------------------------------------*/
417 /* Hexadecimal floating point routines                               */
418 /*-------------------------------------------------------------------*/
419 
420 static void HFPshortGet(PFPO_FLOAT *f, U32 r)
421 {
422   unsigned exp;
423   U32 frac;
424   unsigned i;
425   U32 mask;
426   unsigned sign;
427 
428   sign = r & 0x80000000 ? 1 : 0;
429   exp = (r & 0x7f000000) >> 24;
430   frac = r & 0x00ffffff;
431 
432   if(!frac)
433     f->class = CLASS_ZERO;
434   else
435     f->class = CLASS_NORMAL;
436 
437   f->base = 16;
438   switch(f->class)
439   {
440     case CLASS_ZERO:
441       strcpy(f->str, "0");
442       break;
443 
444     case CLASS_NORMAL:
445       if(sign)
446         strcpy(f->str, "-0.");
447       else
448         strcpy(f->str, "0.");
449       mask = 0x00ff0000;
450       for(i = 0; i < 3; i++)
451       {
452         sprintf(&f->str[strlen(f->str)], "%02x", (r & mask) >> (16 - (i * 8)));
453         mask >>= 8;
454       }
455       strcat(f->str, "@");
456       sprintf(&f->str[strlen(f->str)], "%d", exp - 64);
457       break;
458   }
459 }
460 
461 static void HFPlongGet(PFPO_FLOAT *f, U64 r)
462 {
463   unsigned exp;
464   U64 frac;
465   unsigned i;
466   U64 mask;
467   unsigned sign;
468 
469   sign = r & 0x8000000000000000 ? 1 : 0;
470   exp = (r & 0x7f00000000000000) >> 56;
471   frac = r & 0x00ffffffffffffff;
472 
473   if(!frac)
474     f->class = CLASS_ZERO;
475   else
476     f->class = CLASS_NORMAL;
477 
478   f->base = 16;
479   switch(f->class)
480   {
481     case CLASS_ZERO:
482       strcpy(f->str, "0");
483       break;
484 
485     case CLASS_NORMAL:
486       if(sign)
487         strcpy(f->str, "-0.");
488       else
489         strcpy(f->str, "0.");
490       mask = 0x00ff000000000000;
491       for(i = 0; i < 7; i++)
492       {
493         sprintf(&f->str[strlen(f->str)], "%02"I64_FMT"x", (r & mask) >> (48 - (i * 8)));
494         mask >>= 8;
495       }
496       strcat(f->str, "@");
497       sprintf(&f->str[strlen(f->str)], "%d", exp - 64);
498       break;
499   }
500 }
501 
502 static void HFPextGet(PFPO_FLOAT *f, U64 h, U64 l)
503 {
504   unsigned exp;
505   U64 frach;
506   U64 fracl;
507   unsigned i;
508   U64 mask;
509   unsigned sign;
510 
511   sign = h & 0x8000000000000000 ? 1 : 0;
512   exp = (h & 0x7f00000000000000) >> 56;
513   frach = h & 0x00ffffffffffffff;
514   fracl = l & 0x00ffffffffffffff;
515 
516   if(!frach && !fracl)
517     f->class = CLASS_ZERO;
518   else
519     f->class = CLASS_NORMAL;
520 
521   f->base = 16;
522   switch(f->class)
523   {
524     case CLASS_ZERO:
525       strcpy(f->str, "0");
526       break;
527 
528     case CLASS_NORMAL:
529       if(sign)
530         strcpy(f->str, "-0.");
531       else
532         strcpy(f->str, "0.");
533       mask = 0x00ff000000000000;
534       for(i = 0; i < 7; i++)
535       {
536         sprintf(&f->str[strlen(f->str)], "%02"I64_FMT"x", (h & mask) >> (48 - (i * 8)));
537         mask >>= 8;
538       }
539       mask = 0x00ff000000000000;
540       for(i = 0; i < 7; i++)
541       {
542         sprintf(&f->str[strlen(f->str)], "%02"I64_FMT"x", (l & mask) >> (48 - (i * 8)));
543         mask >>= 8;
544       }
545       strcat(f->str, "@");
546       sprintf(&f->str[strlen(f->str)], "%d", exp - 64);
547       break;
548   }
549 }
550 #endif // PFPO not yet implemented
551 
552 /*-------------------------------------------------------------------*/
553 /* 010A PFPO  - Perform Floating Point Operation                 [E] */
554 /*-------------------------------------------------------------------*/
DEF_INST(perform_floating_point_operation)555 DEF_INST(perform_floating_point_operation)
556 {
557 
558   E(inst, regs);
559 
560   ARCH_DEP(program_interrupt)(regs, PGM_OPERATION_EXCEPTION);
561 
562 } /* end DEF_INST(perform_floating_point_operation) */
563 
564 #endif /*defined(FEATURE_PFPO)*/
565 
566 #if !defined(_GEN_ARCH)
567 
568 #if defined(_ARCHMODE2)
569   #define  _GEN_ARCH _ARCHMODE2
570   #include "pfpo.c"
571 #endif
572 
573 #if defined(_ARCHMODE3)
574   #undef   _GEN_ARCH
575   #define  _GEN_ARCH _ARCHMODE3
576   #include "pfpo.c"
577 #endif
578 
579 #endif /*!defined(_GEN_ARCH)*/
580