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