2002-03-19 Chris G. Demetriou <cgd@broadcom.com>
[external/binutils.git] / sim / mips / cp1.c
1 /*> cp1.c <*/
2 /* Floating Point Support for gdb MIPS simulators
3
4    This file is part of the MIPS sim
5
6                 THIS SOFTWARE IS NOT COPYRIGHTED
7
8    Cygnus offers the following for use in the public domain.  Cygnus
9    makes no warranty with regard to the software or it's performance
10    and the user accepts the software "AS IS" with all faults.
11
12    CYGNUS DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO
13    THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15
16    (Originally, this code was in interp.c)
17 */
18
19 #include "sim-main.h"
20 #include "sim-fpu.h"
21
22 /* Within cp1.c we refer to sim_cpu directly.  */
23 #define CPU cpu
24 #define SD sd
25
26 /*-- FPU support routines ---------------------------------------------------*/
27
28 /* Numbers are held in normalized form. The SINGLE and DOUBLE binary
29    formats conform to ANSI/IEEE Std 754-1985. */
30 /* SINGLE precision floating:
31  *    seeeeeeeefffffffffffffffffffffff
32  *      s =  1bit  = sign
33  *      e =  8bits = exponent
34  *      f = 23bits = fraction
35  */
36 /* SINGLE precision fixed:
37  *    siiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
38  *      s =  1bit  = sign
39  *      i = 31bits = integer
40  */
41 /* DOUBLE precision floating:
42  *    seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
43  *      s =  1bit  = sign
44  *      e = 11bits = exponent
45  *      f = 52bits = fraction
46  */
47 /* DOUBLE precision fixed:
48  *    siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
49  *      s =  1bit  = sign
50  *      i = 63bits = integer
51  */
52
53 /* Extract sign-bit: */
54 #define FP_S_s(v)    (((v) & ((unsigned)1 << 31)) ? 1 : 0)
55 #define FP_D_s(v)    (((v) & ((uword64)1 << 63)) ? 1 : 0)
56 /* Extract biased exponent: */
57 #define FP_S_be(v)   (((v) >> 23) & 0xFF)
58 #define FP_D_be(v)   (((v) >> 52) & 0x7FF)
59 /* Extract unbiased Exponent: */
60 #define FP_S_e(v)    (FP_S_be(v) - 0x7F)
61 #define FP_D_e(v)    (FP_D_be(v) - 0x3FF)
62 /* Extract complete fraction field: */
63 #define FP_S_f(v)    ((v) & ~((unsigned)0x1FF << 23))
64 #define FP_D_f(v)    ((v) & ~((uword64)0xFFF << 52))
65 /* Extract numbered fraction bit: */
66 #define FP_S_fb(b,v) (((v) & (1 << (23 - (b)))) ? 1 : 0)
67 #define FP_D_fb(b,v) (((v) & (1 << (52 - (b)))) ? 1 : 0)
68
69 /* Explicit QNaN values used when value required: */
70 #define FPQNaN_SINGLE   (0x7FBFFFFF)
71 #define FPQNaN_WORD     (0x7FFFFFFF)
72 #define FPQNaN_DOUBLE   (((uword64)0x7FF7FFFF << 32) | 0xFFFFFFFF)
73 #define FPQNaN_LONG     (((uword64)0x7FFFFFFF << 32) | 0xFFFFFFFF)
74
75 /* Explicit Infinity values used when required: */
76 #define FPINF_SINGLE    (0x7F800000)
77 #define FPINF_DOUBLE    (((uword64)0x7FF00000 << 32) | 0x00000000)
78
79 static const char *fpu_format_name (FP_formats fmt);
80 #ifdef DEBUG
81 static const char *fpu_rounding_mode_name (int rm);
82 #endif
83
84 uword64
85 value_fpr (SIM_DESC sd,
86            sim_cpu *cpu,
87            address_word cia,
88            int fpr,
89            FP_formats fmt)
90 {
91   uword64 value = 0;
92   int err = 0;
93
94   /* Treat unused register values, as fixed-point 64bit values: */
95   if ((fmt == fmt_uninterpreted) || (fmt == fmt_unknown))
96 #if 1
97    /* If request to read data as "uninterpreted", then use the current
98       encoding: */
99    fmt = FPR_STATE[fpr];
100 #else
101    fmt = fmt_long;
102 #endif
103
104   /* For values not yet accessed, set to the desired format: */
105   if (FPR_STATE[fpr] == fmt_uninterpreted) {
106     FPR_STATE[fpr] = fmt;
107 #ifdef DEBUG
108     printf("DBG: Register %d was fmt_uninterpreted. Now %s\n",fpr, fpu_format_name (fmt));
109 #endif /* DEBUG */
110   }
111   if (fmt != FPR_STATE[fpr]) {
112     sim_io_eprintf(sd,"FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%s)\n",fpr, fpu_format_name (FPR_STATE[fpr]), fpu_format_name (fmt),pr_addr(cia));
113     FPR_STATE[fpr] = fmt_unknown;
114   }
115
116   if (FPR_STATE[fpr] == fmt_unknown) {
117    /* Set QNaN value: */
118    switch (fmt) {
119     case fmt_single:
120      value = FPQNaN_SINGLE;
121      break;
122
123     case fmt_double:
124      value = FPQNaN_DOUBLE;
125      break;
126
127     case fmt_word:
128      value = FPQNaN_WORD;
129      break;
130
131     case fmt_long:
132      value = FPQNaN_LONG;
133      break;
134
135     default:
136      err = -1;
137      break;
138    }
139   } else if (SizeFGR() == 64) {
140     switch (fmt) {
141      case fmt_single:
142      case fmt_word:
143       value = (FGR[fpr] & 0xFFFFFFFF);
144       break;
145
146      case fmt_uninterpreted:
147      case fmt_double:
148      case fmt_long:
149       value = FGR[fpr];
150       break;
151
152      default :
153       err = -1;
154       break;
155     }
156   } else {
157     switch (fmt) {
158      case fmt_single:
159      case fmt_word:
160       value = (FGR[fpr] & 0xFFFFFFFF);
161       break;
162
163      case fmt_uninterpreted:
164      case fmt_double:
165      case fmt_long:
166       if ((fpr & 1) == 0) { /* even registers only */
167 #ifdef DEBUG
168         printf("DBG: ValueFPR: FGR[%d] = %s, FGR[%d] = %s\n", 
169                fpr+1, pr_uword64( (uword64) FGR[fpr+1] ),
170                fpr, pr_uword64( (uword64) FGR[fpr] ));
171 #endif
172         value = ((((uword64)FGR[fpr+1]) << 32) | (FGR[fpr] & 0xFFFFFFFF));
173       } else {
174         SignalException(ReservedInstruction,0);
175       }
176       break;
177
178      default :
179       err = -1;
180       break;
181     }
182   }
183
184   if (err)
185    SignalExceptionSimulatorFault ("Unrecognised FP format in ValueFPR()");
186
187 #ifdef DEBUG
188   printf("DBG: ValueFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR() = %d\n",fpr, fpu_format_name (fmt),pr_uword64(value),pr_addr(cia),SizeFGR());
189 #endif /* DEBUG */
190
191   return(value);
192 }
193
194 void
195 store_fpr (SIM_DESC sd,
196            sim_cpu *cpu,
197            address_word cia,
198            int fpr,
199            FP_formats fmt,
200            uword64 value)
201 {
202   int err = 0;
203
204 #ifdef DEBUG
205   printf("DBG: StoreFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR() = %d,\n",fpr, fpu_format_name (fmt),pr_uword64(value),pr_addr(cia),SizeFGR());
206 #endif /* DEBUG */
207
208   if (SizeFGR() == 64) {
209     switch (fmt) {
210       case fmt_uninterpreted_32:
211         fmt = fmt_uninterpreted;
212       case fmt_single :
213       case fmt_word :
214        if (STATE_VERBOSE_P(SD))
215          sim_io_eprintf (SD, "Warning: PC 0x%s: interp.c store_fpr DEADCODE\n",
216            pr_addr(cia));
217        FGR[fpr] = (((uword64)0xDEADC0DE << 32) | (value & 0xFFFFFFFF));
218        FPR_STATE[fpr] = fmt;
219        break;
220
221       case fmt_uninterpreted_64:
222         fmt = fmt_uninterpreted;
223       case fmt_uninterpreted:
224       case fmt_double :
225       case fmt_long :
226        FGR[fpr] = value;
227        FPR_STATE[fpr] = fmt;
228        break;
229
230       default :
231        FPR_STATE[fpr] = fmt_unknown;
232        err = -1;
233        break;
234     }
235   } else {
236     switch (fmt) {
237       case fmt_uninterpreted_32:
238         fmt = fmt_uninterpreted;
239       case fmt_single :
240       case fmt_word :
241        FGR[fpr] = (value & 0xFFFFFFFF);
242        FPR_STATE[fpr] = fmt;
243        break;
244
245       case fmt_uninterpreted_64:
246         fmt = fmt_uninterpreted;
247       case fmt_uninterpreted:
248       case fmt_double :
249       case fmt_long :
250         if ((fpr & 1) == 0) { /* even register number only */
251           FGR[fpr+1] = (value >> 32);
252           FGR[fpr] = (value & 0xFFFFFFFF);
253           FPR_STATE[fpr + 1] = fmt;
254           FPR_STATE[fpr] = fmt;
255         } else {
256           FPR_STATE[fpr] = fmt_unknown;
257           FPR_STATE[fpr + 1] = fmt_unknown;
258           SignalException(ReservedInstruction,0);
259         }
260        break;
261
262       default :
263        FPR_STATE[fpr] = fmt_unknown;
264        err = -1;
265        break;
266     }
267   }
268 #if defined(WARN_RESULT)
269   else
270     UndefinedResult();
271 #endif /* WARN_RESULT */
272
273   if (err)
274    SignalExceptionSimulatorFault ("Unrecognised FP format in StoreFPR()");
275
276 #ifdef DEBUG
277   printf("DBG: StoreFPR: fpr[%d] = 0x%s (format %s)\n",fpr,pr_uword64(FGR[fpr]), fpu_format_name (fmt));
278 #endif /* DEBUG */
279
280   return;
281 }
282
283 int
284 NaN(op,fmt)
285      uword64 op;
286      FP_formats fmt; 
287 {
288   int boolean = 0;
289   switch (fmt) {
290    case fmt_single:
291    case fmt_word:
292     {
293       sim_fpu wop;
294       sim_fpu_32to (&wop, op);
295       boolean = sim_fpu_is_nan (&wop);
296       break;
297     }
298    case fmt_double:
299    case fmt_long:
300     {
301       sim_fpu wop;
302       sim_fpu_64to (&wop, op);
303       boolean = sim_fpu_is_nan (&wop);
304       break;
305     }
306    default:
307     fprintf (stderr, "Bad switch\n");
308     abort ();
309   }
310
311 #ifdef DEBUG
312 printf("DBG: NaN: returning %d for 0x%s (format = %s)\n",boolean,pr_addr(op), fpu_format_name (fmt));
313 #endif /* DEBUG */
314
315   return(boolean);
316 }
317
318 int
319 Infinity(op,fmt)
320      uword64 op;
321      FP_formats fmt; 
322 {
323   int boolean = 0;
324
325 #ifdef DEBUG
326   printf("DBG: Infinity: format %s 0x%s\n", fpu_format_name (fmt),pr_addr(op));
327 #endif /* DEBUG */
328
329   switch (fmt) {
330    case fmt_single:
331     {
332       sim_fpu wop;
333       sim_fpu_32to (&wop, op);
334       boolean = sim_fpu_is_infinity (&wop);
335       break;
336     }
337    case fmt_double:
338     {
339       sim_fpu wop;
340       sim_fpu_64to (&wop, op);
341       boolean = sim_fpu_is_infinity (&wop);
342       break;
343     }
344    default:
345     printf("DBG: TODO: unrecognised format (%s) for Infinity check\n", fpu_format_name (fmt));
346     break;
347   }
348
349 #ifdef DEBUG
350   printf("DBG: Infinity: returning %d for 0x%s (format = %s)\n",boolean,pr_addr(op), fpu_format_name (fmt));
351 #endif /* DEBUG */
352
353   return(boolean);
354 }
355
356 int
357 Less(op1,op2,fmt)
358      uword64 op1;
359      uword64 op2;
360      FP_formats fmt; 
361 {
362   int boolean = 0;
363
364   /* Argument checking already performed by the FPCOMPARE code */
365
366 #ifdef DEBUG
367   printf("DBG: Less: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
368 #endif /* DEBUG */
369
370   /* The format type should already have been checked: */
371   switch (fmt) {
372    case fmt_single:
373     {
374       sim_fpu wop1;
375       sim_fpu wop2;
376       sim_fpu_32to (&wop1, op1);
377       sim_fpu_32to (&wop2, op2);
378       boolean = sim_fpu_is_lt (&wop1, &wop2);
379       break;
380     }
381    case fmt_double:
382     {
383       sim_fpu wop1;
384       sim_fpu wop2;
385       sim_fpu_64to (&wop1, op1);
386       sim_fpu_64to (&wop2, op2);
387       boolean = sim_fpu_is_lt (&wop1, &wop2);
388       break;
389     }
390    default:
391     fprintf (stderr, "Bad switch\n");
392     abort ();
393   }
394
395 #ifdef DEBUG
396   printf("DBG: Less: returning %d (format = %s)\n",boolean, fpu_format_name (fmt));
397 #endif /* DEBUG */
398
399   return(boolean);
400 }
401
402 int
403 Equal(op1,op2,fmt)
404      uword64 op1;
405      uword64 op2;
406      FP_formats fmt; 
407 {
408   int boolean = 0;
409
410   /* Argument checking already performed by the FPCOMPARE code */
411
412 #ifdef DEBUG
413   printf("DBG: Equal: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
414 #endif /* DEBUG */
415
416   /* The format type should already have been checked: */
417   switch (fmt) {
418    case fmt_single:
419     {
420       sim_fpu wop1;
421       sim_fpu wop2;
422       sim_fpu_32to (&wop1, op1);
423       sim_fpu_32to (&wop2, op2);
424       boolean = sim_fpu_is_eq (&wop1, &wop2);
425       break;
426     }
427    case fmt_double:
428     {
429       sim_fpu wop1;
430       sim_fpu wop2;
431       sim_fpu_64to (&wop1, op1);
432       sim_fpu_64to (&wop2, op2);
433       boolean = sim_fpu_is_eq (&wop1, &wop2);
434       break;
435     }
436    default:
437     fprintf (stderr, "Bad switch\n");
438     abort ();
439   }
440
441 #ifdef DEBUG
442   printf("DBG: Equal: returning %d (format = %s)\n",boolean, fpu_format_name (fmt));
443 #endif /* DEBUG */
444
445   return(boolean);
446 }
447
448 uword64
449 AbsoluteValue(op,fmt)
450      uword64 op;
451      FP_formats fmt; 
452 {
453   uword64 result = 0;
454
455 #ifdef DEBUG
456   printf("DBG: AbsoluteValue: %s: op = 0x%s\n", fpu_format_name (fmt),pr_addr(op));
457 #endif /* DEBUG */
458
459   /* The format type should already have been checked: */
460   switch (fmt) {
461    case fmt_single:
462     {
463       sim_fpu wop;
464       unsigned32 ans;
465       sim_fpu_32to (&wop, op);
466       sim_fpu_abs (&wop, &wop);
467       sim_fpu_to32 (&ans, &wop);
468       result = ans;
469       break;
470     }
471    case fmt_double:
472     {
473       sim_fpu wop;
474       unsigned64 ans;
475       sim_fpu_64to (&wop, op);
476       sim_fpu_abs (&wop, &wop);
477       sim_fpu_to64 (&ans, &wop);
478       result = ans;
479       break;
480     }
481    default:
482     fprintf (stderr, "Bad switch\n");
483     abort ();
484   }
485
486   return(result);
487 }
488
489 uword64
490 Negate(op,fmt)
491      uword64 op;
492      FP_formats fmt; 
493 {
494   uword64 result = 0;
495
496 #ifdef DEBUG
497   printf("DBG: Negate: %s: op = 0x%s\n", fpu_format_name (fmt),pr_addr(op));
498 #endif /* DEBUG */
499
500   /* The format type should already have been checked: */
501   switch (fmt) {
502    case fmt_single:
503     {
504       sim_fpu wop;
505       unsigned32 ans;
506       sim_fpu_32to (&wop, op);
507       sim_fpu_neg (&wop, &wop);
508       sim_fpu_to32 (&ans, &wop);
509       result = ans;
510       break;
511     }
512    case fmt_double:
513     {
514       sim_fpu wop;
515       unsigned64 ans;
516       sim_fpu_64to (&wop, op);
517       sim_fpu_neg (&wop, &wop);
518       sim_fpu_to64 (&ans, &wop);
519       result = ans;
520       break;
521     }
522    default:
523     fprintf (stderr, "Bad switch\n");
524     abort ();
525   }
526
527   return(result);
528 }
529
530 uword64
531 Add(op1,op2,fmt)
532      uword64 op1;
533      uword64 op2;
534      FP_formats fmt; 
535 {
536   uword64 result = 0;
537
538 #ifdef DEBUG
539   printf("DBG: Add: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
540 #endif /* DEBUG */
541
542   /* The registers must specify FPRs valid for operands of type
543      "fmt". If they are not valid, the result is undefined. */
544
545   /* The format type should already have been checked: */
546   switch (fmt) {
547    case fmt_single:
548     {
549       sim_fpu wop1;
550       sim_fpu wop2;
551       sim_fpu ans;
552       unsigned32 res;
553       sim_fpu_32to (&wop1, op1);
554       sim_fpu_32to (&wop2, op2);
555       sim_fpu_add (&ans, &wop1, &wop2);
556       sim_fpu_to32 (&res, &ans);
557       result = res;
558       break;
559     }
560    case fmt_double:
561     {
562       sim_fpu wop1;
563       sim_fpu wop2;
564       sim_fpu ans;
565       unsigned64 res;
566       sim_fpu_64to (&wop1, op1);
567       sim_fpu_64to (&wop2, op2);
568       sim_fpu_add (&ans, &wop1, &wop2);
569       sim_fpu_to64 (&res, &ans);
570       result = res;
571       break;
572     }
573    default:
574     fprintf (stderr, "Bad switch\n");
575     abort ();
576   }
577
578 #ifdef DEBUG
579   printf("DBG: Add: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
580 #endif /* DEBUG */
581
582   return(result);
583 }
584
585 uword64
586 Sub(op1,op2,fmt)
587      uword64 op1;
588      uword64 op2;
589      FP_formats fmt; 
590 {
591   uword64 result = 0;
592
593 #ifdef DEBUG
594   printf("DBG: Sub: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
595 #endif /* DEBUG */
596
597   /* The registers must specify FPRs valid for operands of type
598      "fmt". If they are not valid, the result is undefined. */
599
600   /* The format type should already have been checked: */
601   switch (fmt) {
602    case fmt_single:
603     {
604       sim_fpu wop1;
605       sim_fpu wop2;
606       sim_fpu ans;
607       unsigned32 res;
608       sim_fpu_32to (&wop1, op1);
609       sim_fpu_32to (&wop2, op2);
610       sim_fpu_sub (&ans, &wop1, &wop2);
611       sim_fpu_to32 (&res, &ans);
612       result = res;
613     }
614     break;
615    case fmt_double:
616     {
617       sim_fpu wop1;
618       sim_fpu wop2;
619       sim_fpu ans;
620       unsigned64 res;
621       sim_fpu_64to (&wop1, op1);
622       sim_fpu_64to (&wop2, op2);
623       sim_fpu_sub (&ans, &wop1, &wop2);
624       sim_fpu_to64 (&res, &ans);
625       result = res;
626     }
627     break;
628    default:
629     fprintf (stderr, "Bad switch\n");
630     abort ();
631   }
632
633 #ifdef DEBUG
634   printf("DBG: Sub: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
635 #endif /* DEBUG */
636
637   return(result);
638 }
639
640 uword64
641 Multiply(op1,op2,fmt)
642      uword64 op1;
643      uword64 op2;
644      FP_formats fmt; 
645 {
646   uword64 result = 0;
647
648 #ifdef DEBUG
649   printf("DBG: Multiply: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
650 #endif /* DEBUG */
651
652   /* The registers must specify FPRs valid for operands of type
653      "fmt". If they are not valid, the result is undefined. */
654
655   /* The format type should already have been checked: */
656   switch (fmt) {
657    case fmt_single:
658     {
659       sim_fpu wop1;
660       sim_fpu wop2;
661       sim_fpu ans;
662       unsigned32 res;
663       sim_fpu_32to (&wop1, op1);
664       sim_fpu_32to (&wop2, op2);
665       sim_fpu_mul (&ans, &wop1, &wop2);
666       sim_fpu_to32 (&res, &ans);
667       result = res;
668       break;
669     }
670    case fmt_double:
671     {
672       sim_fpu wop1;
673       sim_fpu wop2;
674       sim_fpu ans;
675       unsigned64 res;
676       sim_fpu_64to (&wop1, op1);
677       sim_fpu_64to (&wop2, op2);
678       sim_fpu_mul (&ans, &wop1, &wop2);
679       sim_fpu_to64 (&res, &ans);
680       result = res;
681       break;
682     }
683    default:
684     fprintf (stderr, "Bad switch\n");
685     abort ();
686   }
687
688 #ifdef DEBUG
689   printf("DBG: Multiply: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
690 #endif /* DEBUG */
691
692   return(result);
693 }
694
695 uword64
696 Divide(op1,op2,fmt)
697      uword64 op1;
698      uword64 op2;
699      FP_formats fmt; 
700 {
701   uword64 result = 0;
702
703 #ifdef DEBUG
704   printf("DBG: Divide: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
705 #endif /* DEBUG */
706
707   /* The registers must specify FPRs valid for operands of type
708      "fmt". If they are not valid, the result is undefined. */
709
710   /* The format type should already have been checked: */
711   switch (fmt) {
712    case fmt_single:
713     {
714       sim_fpu wop1;
715       sim_fpu wop2;
716       sim_fpu ans;
717       unsigned32 res;
718       sim_fpu_32to (&wop1, op1);
719       sim_fpu_32to (&wop2, op2);
720       sim_fpu_div (&ans, &wop1, &wop2);
721       sim_fpu_to32 (&res, &ans);
722       result = res;
723       break;
724     }
725    case fmt_double:
726     {
727       sim_fpu wop1;
728       sim_fpu wop2;
729       sim_fpu ans;
730       unsigned64 res;
731       sim_fpu_64to (&wop1, op1);
732       sim_fpu_64to (&wop2, op2);
733       sim_fpu_div (&ans, &wop1, &wop2);
734       sim_fpu_to64 (&res, &ans);
735       result = res;
736       break;
737     }
738    default:
739     fprintf (stderr, "Bad switch\n");
740     abort ();
741   }
742
743 #ifdef DEBUG
744   printf("DBG: Divide: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
745 #endif /* DEBUG */
746
747   return(result);
748 }
749
750 uword64 UNUSED
751 Recip(op,fmt)
752      uword64 op;
753      FP_formats fmt; 
754 {
755   uword64 result = 0;
756
757 #ifdef DEBUG
758   printf("DBG: Recip: %s: op = 0x%s\n", fpu_format_name (fmt),pr_addr(op));
759 #endif /* DEBUG */
760
761   /* The registers must specify FPRs valid for operands of type
762      "fmt". If they are not valid, the result is undefined. */
763
764   /* The format type should already have been checked: */
765   switch (fmt) {
766    case fmt_single:
767     {
768       sim_fpu wop;
769       sim_fpu ans;
770       unsigned32 res;
771       sim_fpu_32to (&wop, op);
772       sim_fpu_inv (&ans, &wop);
773       sim_fpu_to32 (&res, &ans);
774       result = res;
775       break;
776     }
777    case fmt_double:
778     {
779       sim_fpu wop;
780       sim_fpu ans;
781       unsigned64 res;
782       sim_fpu_64to (&wop, op);
783       sim_fpu_inv (&ans, &wop);
784       sim_fpu_to64 (&res, &ans);
785       result = res;
786       break;
787     }
788    default:
789     fprintf (stderr, "Bad switch\n");
790     abort ();
791   }
792
793 #ifdef DEBUG
794   printf("DBG: Recip: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
795 #endif /* DEBUG */
796
797   return(result);
798 }
799
800 uword64
801 SquareRoot(op,fmt)
802      uword64 op;
803      FP_formats fmt; 
804 {
805   uword64 result = 0;
806
807 #ifdef DEBUG
808   printf("DBG: SquareRoot: %s: op = 0x%s\n", fpu_format_name (fmt),pr_addr(op));
809 #endif /* DEBUG */
810
811   /* The registers must specify FPRs valid for operands of type
812      "fmt". If they are not valid, the result is undefined. */
813
814   /* The format type should already have been checked: */
815   switch (fmt) {
816    case fmt_single:
817     {
818       sim_fpu wop;
819       sim_fpu ans;
820       unsigned32 res;
821       sim_fpu_32to (&wop, op);
822       sim_fpu_sqrt (&ans, &wop);
823       sim_fpu_to32 (&res, &ans);
824       result = res;
825       break;
826     }
827    case fmt_double:
828     {
829       sim_fpu wop;
830       sim_fpu ans;
831       unsigned64 res;
832       sim_fpu_64to (&wop, op);
833       sim_fpu_sqrt (&ans, &wop);
834       sim_fpu_to64 (&res, &ans);
835       result = res;
836       break;
837     }
838    default:
839     fprintf (stderr, "Bad switch\n");
840     abort ();
841   }
842
843 #ifdef DEBUG
844   printf("DBG: SquareRoot: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
845 #endif /* DEBUG */
846
847   return(result);
848 }
849
850 #if 0
851 uword64
852 Max (uword64 op1,
853      uword64 op2,
854      FP_formats fmt)
855 {
856   int cmp;
857   unsigned64 result;
858
859 #ifdef DEBUG
860   printf("DBG: Max: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
861 #endif /* DEBUG */
862
863   /* The registers must specify FPRs valid for operands of type
864      "fmt". If they are not valid, the result is undefined. */
865
866   /* The format type should already have been checked: */
867   switch (fmt)
868     {
869     case fmt_single:
870       {
871         sim_fpu wop1;
872         sim_fpu wop2;
873         sim_fpu_32to (&wop1, op1);
874         sim_fpu_32to (&wop2, op2);
875         cmp = sim_fpu_cmp (&wop1, &wop2);
876         break;
877       }
878     case fmt_double:
879       {
880         sim_fpu wop1;
881         sim_fpu wop2;
882         sim_fpu_64to (&wop1, op1);
883         sim_fpu_64to (&wop2, op2);
884         cmp = sim_fpu_cmp (&wop1, &wop2);
885         break;
886       }
887     default:
888       fprintf (stderr, "Bad switch\n");
889       abort ();
890     }
891   
892   switch (cmp)
893     {
894     case SIM_FPU_IS_SNAN:
895     case SIM_FPU_IS_QNAN:
896       result = op1;
897     case SIM_FPU_IS_NINF:
898     case SIM_FPU_IS_NNUMBER:
899     case SIM_FPU_IS_NDENORM:
900     case SIM_FPU_IS_NZERO:
901       result = op2; /* op1 - op2 < 0 */
902     case SIM_FPU_IS_PINF:
903     case SIM_FPU_IS_PNUMBER:
904     case SIM_FPU_IS_PDENORM:
905     case SIM_FPU_IS_PZERO:
906       result = op1; /* op1 - op2 > 0 */
907     default:
908       fprintf (stderr, "Bad switch\n");
909       abort ();
910     }
911
912 #ifdef DEBUG
913   printf("DBG: Max: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
914 #endif /* DEBUG */
915
916   return(result);
917 }
918 #endif 
919
920 #if 0
921 uword64
922 Min (uword64 op1,
923      uword64 op2,
924      FP_formats fmt)
925 {
926   int cmp;
927   unsigned64 result;
928
929 #ifdef DEBUG
930   printf("DBG: Min: %s: op1 = 0x%s : op2 = 0x%s\n", fpu_format_name (fmt),pr_addr(op1),pr_addr(op2));
931 #endif /* DEBUG */
932
933   /* The registers must specify FPRs valid for operands of type
934      "fmt". If they are not valid, the result is undefined. */
935
936   /* The format type should already have been checked: */
937   switch (fmt)
938     {
939     case fmt_single:
940       {
941         sim_fpu wop1;
942         sim_fpu wop2;
943         sim_fpu_32to (&wop1, op1);
944         sim_fpu_32to (&wop2, op2);
945         cmp = sim_fpu_cmp (&wop1, &wop2);
946         break;
947       }
948     case fmt_double:
949       {
950         sim_fpu wop1;
951         sim_fpu wop2;
952         sim_fpu_64to (&wop1, op1);
953         sim_fpu_64to (&wop2, op2);
954         cmp = sim_fpu_cmp (&wop1, &wop2);
955         break;
956       }
957     default:
958       fprintf (stderr, "Bad switch\n");
959       abort ();
960     }
961   
962   switch (cmp)
963     {
964     case SIM_FPU_IS_SNAN:
965     case SIM_FPU_IS_QNAN:
966       result = op1;
967     case SIM_FPU_IS_NINF:
968     case SIM_FPU_IS_NNUMBER:
969     case SIM_FPU_IS_NDENORM:
970     case SIM_FPU_IS_NZERO:
971       result = op1; /* op1 - op2 < 0 */
972     case SIM_FPU_IS_PINF:
973     case SIM_FPU_IS_PNUMBER:
974     case SIM_FPU_IS_PDENORM:
975     case SIM_FPU_IS_PZERO:
976       result = op2; /* op1 - op2 > 0 */
977     default:
978       fprintf (stderr, "Bad switch\n");
979       abort ();
980     }
981
982 #ifdef DEBUG
983   printf("DBG: Min: returning 0x%s (format = %s)\n",pr_addr(result), fpu_format_name (fmt));
984 #endif /* DEBUG */
985
986   return(result);
987 }
988 #endif
989
990 uword64
991 convert (SIM_DESC sd,
992          sim_cpu *cpu,
993          address_word cia,
994          int rm,
995          uword64 op,
996          FP_formats from,
997          FP_formats to)
998 {
999   sim_fpu wop;
1000   sim_fpu_round round;
1001   unsigned32 result32;
1002   unsigned64 result64;
1003
1004 #ifdef DEBUG
1005 #if 0 /* FIXME: doesn't compile */
1006   printf("DBG: Convert: mode %s : op 0x%s : from %s : to %s : (PC = 0x%s)\n", fpu_rounding_mode_name (rm),pr_addr(op), fpu_format_name (from), fpu_format_name (to),pr_addr(IPC));
1007 #endif
1008 #endif /* DEBUG */
1009
1010   switch (rm)
1011     {
1012     case FP_RM_NEAREST:
1013       /* Round result to nearest representable value. When two
1014          representable values are equally near, round to the value
1015          that has a least significant bit of zero (i.e. is even). */
1016       round = sim_fpu_round_near;
1017       break;
1018     case FP_RM_TOZERO:
1019       /* Round result to the value closest to, and not greater in
1020          magnitude than, the result. */
1021       round = sim_fpu_round_zero;
1022       break;
1023     case FP_RM_TOPINF:
1024       /* Round result to the value closest to, and not less than,
1025          the result. */
1026       round = sim_fpu_round_up;
1027       break;
1028       
1029     case FP_RM_TOMINF:
1030       /* Round result to the value closest to, and not greater than,
1031          the result. */
1032       round = sim_fpu_round_down;
1033       break;
1034     default:
1035       round = 0;
1036       fprintf (stderr, "Bad switch\n");
1037       abort ();
1038     }
1039   
1040   /* Convert the input to sim_fpu internal format */
1041   switch (from)
1042     {
1043     case fmt_double:
1044       sim_fpu_64to (&wop, op);
1045       break;
1046     case fmt_single:
1047       sim_fpu_32to (&wop, op);
1048       break;
1049     case fmt_word:
1050       sim_fpu_i32to (&wop, op, round);
1051       break;
1052     case fmt_long:
1053       sim_fpu_i64to (&wop, op, round);
1054       break;
1055     default:
1056       fprintf (stderr, "Bad switch\n");
1057       abort ();
1058     }
1059
1060   /* Convert sim_fpu format into the output */
1061   /* The value WOP is converted to the destination format, rounding
1062      using mode RM. When the destination is a fixed-point format, then
1063      a source value of Infinity, NaN or one which would round to an
1064      integer outside the fixed point range then an IEEE Invalid
1065      Operation condition is raised. */
1066   switch (to)
1067     {
1068     case fmt_single:
1069       sim_fpu_round_32 (&wop, round, 0);
1070       sim_fpu_to32 (&result32, &wop);
1071       result64 = result32;
1072       break;
1073     case fmt_double:
1074       sim_fpu_round_64 (&wop, round, 0);
1075       sim_fpu_to64 (&result64, &wop);
1076       break;
1077     case fmt_word:
1078       sim_fpu_to32i (&result32, &wop, round);
1079       result64 = result32;
1080       break;
1081     case fmt_long:
1082       sim_fpu_to64i (&result64, &wop, round);
1083       break;
1084     default:
1085       result64 = 0;
1086       fprintf (stderr, "Bad switch\n");
1087       abort ();
1088     }
1089  
1090 #ifdef DEBUG
1091   printf("DBG: Convert: returning 0x%s (to format = %s)\n",pr_addr(result64), fpu_format_name (to));
1092 #endif /* DEBUG */
1093
1094   return(result64);
1095 }
1096
1097 static const char *
1098 fpu_format_name (FP_formats fmt)
1099 {
1100   switch (fmt)
1101     {
1102     case fmt_single:
1103       return "single";
1104     case fmt_double:
1105       return "double";
1106     case fmt_word:
1107       return "word";
1108     case fmt_long:
1109       return "long";
1110     case fmt_unknown:
1111       return "<unknown>";
1112     case fmt_uninterpreted:
1113       return "<uninterpreted>";
1114     case fmt_uninterpreted_32:
1115       return "<uninterpreted_32>";
1116     case fmt_uninterpreted_64:
1117       return "<uninterpreted_64>";
1118     default:
1119       return "<format error>";
1120     }
1121 }
1122
1123 #ifdef DEBUG
1124 static const char *
1125 fpu_rounding_mode_name (int rm)
1126 {
1127   switch (rm)
1128     {
1129     case FP_RM_NEAREST:
1130       return "Round";
1131     case FP_RM_TOZERO:
1132       return "Trunc";
1133     case FP_RM_TOPINF:
1134       return "Ceil";
1135     case FP_RM_TOMINF:
1136       return "Floor";
1137     default:
1138       return "<rounding mode error>";
1139     }
1140 }
1141 #endif /* DEBUG */