2002-06-07 Chris Demetriou <cgd@broadcom.com>
[external/binutils.git] / sim / mips / cp1.c
1 /*> cp1.c <*/
2 /* MIPS Simulator FPU (CoProcessor 1) support.
3    Copyright (C) 2002 Free Software Foundation, Inc.
4    Originally created by Cygnus Solutions, modified substially
5    by Broadcom Corporation (SiByte).
6
7 This file is part of GDB, the GNU debugger.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License along
20 with this program; if not, write to the Free Software Foundation, Inc.,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
22
23 /* XXX: The following notice should be removed as soon as is practical:  */
24 /* Floating Point Support for gdb MIPS simulators
25
26    This file is part of the MIPS sim
27
28                 THIS SOFTWARE IS NOT COPYRIGHTED
29    (by Cygnus.)
30
31    Cygnus offers the following for use in the public domain.  Cygnus
32    makes no warranty with regard to the software or it's performance
33    and the user accepts the software "AS IS" with all faults.
34
35    CYGNUS DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO
36    THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
38
39    (Originally, this code was in interp.c)
40 */
41
42 #include "sim-main.h"
43
44 /* Within cp1.c we refer to sim_cpu directly.  */
45 #define CPU cpu
46 #define SD CPU_STATE(cpu)
47
48 /*-- FPU support routines ---------------------------------------------------*/
49
50 /* Numbers are held in normalized form. The SINGLE and DOUBLE binary
51    formats conform to ANSI/IEEE Std 754-1985.
52
53    SINGLE precision floating:
54       seeeeeeeefffffffffffffffffffffff
55         s =  1bit  = sign
56         e =  8bits = exponent
57         f = 23bits = fraction
58
59    SINGLE precision fixed:
60       siiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
61         s =  1bit  = sign
62         i = 31bits = integer
63
64    DOUBLE precision floating:
65       seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
66         s =  1bit  = sign
67         e = 11bits = exponent
68         f = 52bits = fraction
69
70    DOUBLE precision fixed:
71       siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
72         s =  1bit  = sign
73         i = 63bits = integer
74  */
75
76 /* Explicit QNaN values.  */
77 #define FPQNaN_SINGLE   (0x7FBFFFFF)
78 #define FPQNaN_WORD     (0x7FFFFFFF)
79 #define FPQNaN_DOUBLE   (UNSIGNED64 (0x7FF7FFFFFFFFFFFF))
80 #define FPQNaN_LONG     (UNSIGNED64 (0x7FFFFFFFFFFFFFFF))
81
82 static const char *fpu_format_name (FP_formats fmt);
83 #ifdef DEBUG
84 static const char *fpu_rounding_mode_name (int rm);
85 #endif
86
87 uword64
88 value_fpr (sim_cpu *cpu,
89            address_word cia,
90            int fpr,
91            FP_formats fmt)
92 {
93   uword64 value = 0;
94   int err = 0;
95
96   /* Treat unused register values, as fixed-point 64bit values.  */
97   if ((fmt == fmt_uninterpreted) || (fmt == fmt_unknown))
98     {
99 #if 1
100       /* If request to read data as "uninterpreted", then use the current
101          encoding:  */
102       fmt = FPR_STATE[fpr];
103 #else
104       fmt = fmt_long;
105 #endif
106     }
107
108   /* For values not yet accessed, set to the desired format.  */
109   if (FPR_STATE[fpr] == fmt_uninterpreted)
110     {
111       FPR_STATE[fpr] = fmt;
112 #ifdef DEBUG
113       printf ("DBG: Register %d was fmt_uninterpreted. Now %s\n", fpr,
114               fpu_format_name (fmt));
115 #endif /* DEBUG */
116     }
117   if (fmt != FPR_STATE[fpr])
118     {
119       sim_io_eprintf (SD, "FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%s)\n",
120                       fpr, fpu_format_name (FPR_STATE[fpr]),
121                       fpu_format_name (fmt), pr_addr (cia));
122       FPR_STATE[fpr] = fmt_unknown;
123     }
124
125   if (FPR_STATE[fpr] == fmt_unknown)
126     {
127       /* Set QNaN value:  */
128       switch (fmt)
129         {
130         case fmt_single:  value = FPQNaN_SINGLE;  break;
131         case fmt_double:  value = FPQNaN_DOUBLE;  break;
132         case fmt_word:    value = FPQNaN_WORD;    break;
133         case fmt_long:    value = FPQNaN_LONG;    break;
134         default:          err = -1;               break;
135         }
136     }
137   else if (SizeFGR () == 64)
138     {
139       switch (fmt)
140         {
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     }
157   else
158     {
159       switch (fmt)
160         {
161         case fmt_single:
162         case fmt_word:
163           value = (FGR[fpr] & 0xFFFFFFFF);
164           break;
165
166         case fmt_uninterpreted:
167         case fmt_double:
168         case fmt_long:
169           if ((fpr & 1) == 0)
170             {
171               /* Even register numbers only.  */
172 #ifdef DEBUG
173               printf ("DBG: ValueFPR: FGR[%d] = %s, FGR[%d] = %s\n",
174                       fpr + 1, pr_uword64 ((uword64) FGR[fpr+1]),
175                       fpr, pr_uword64 ((uword64) FGR[fpr]));
176 #endif
177               value = ((((uword64) FGR[fpr+1]) << 32)
178                        | (FGR[fpr] & 0xFFFFFFFF));
179             }
180           else
181             {
182               SignalException (ReservedInstruction, 0);
183             }
184           break;
185
186         default:
187           err = -1;
188           break;
189         }
190     }
191
192   if (err)
193     SignalExceptionSimulatorFault ("Unrecognised FP format in ValueFPR ()");
194
195 #ifdef DEBUG
196   printf ("DBG: ValueFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR () = %d\n",
197           fpr, fpu_format_name (fmt), pr_uword64 (value), pr_addr (cia),
198           SizeFGR ());
199 #endif /* DEBUG */
200
201   return (value);
202 }
203
204 void
205 store_fpr (sim_cpu *cpu,
206            address_word cia,
207            int fpr,
208            FP_formats fmt,
209            uword64 value)
210 {
211   int err = 0;
212
213 #ifdef DEBUG
214   printf ("DBG: StoreFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR () = %d, \n",
215           fpr, fpu_format_name (fmt), pr_uword64 (value), pr_addr (cia),
216           SizeFGR ());
217 #endif /* DEBUG */
218
219   if (SizeFGR () == 64)
220     {
221       switch (fmt)
222         {
223         case fmt_uninterpreted_32:
224           fmt = fmt_uninterpreted;
225         case fmt_single:
226         case fmt_word:
227           if (STATE_VERBOSE_P (SD))
228             sim_io_eprintf (SD,
229                             "Warning: PC 0x%s: interp.c store_fpr DEADCODE\n",
230                             pr_addr (cia));
231           FGR[fpr] = (((uword64) 0xDEADC0DE << 32) | (value & 0xFFFFFFFF));
232           FPR_STATE[fpr] = fmt;
233           break;
234
235         case fmt_uninterpreted_64:
236           fmt = fmt_uninterpreted;
237         case fmt_uninterpreted:
238         case fmt_double:
239         case fmt_long:
240           FGR[fpr] = value;
241           FPR_STATE[fpr] = fmt;
242           break;
243
244         default:
245           FPR_STATE[fpr] = fmt_unknown;
246           err = -1;
247           break;
248         }
249     }
250   else
251     {
252       switch (fmt)
253         {
254         case fmt_uninterpreted_32:
255           fmt = fmt_uninterpreted;
256         case fmt_single:
257         case fmt_word:
258           FGR[fpr] = (value & 0xFFFFFFFF);
259           FPR_STATE[fpr] = fmt;
260           break;
261
262         case fmt_uninterpreted_64:
263           fmt = fmt_uninterpreted;
264         case fmt_uninterpreted:
265         case fmt_double:
266         case fmt_long:
267           if ((fpr & 1) == 0)
268             {
269               /* Even register numbers only.  */
270               FGR[fpr+1] = (value >> 32);
271               FGR[fpr] = (value & 0xFFFFFFFF);
272               FPR_STATE[fpr + 1] = fmt;
273               FPR_STATE[fpr] = fmt;
274             }
275           else
276             {
277               FPR_STATE[fpr] = fmt_unknown;
278               FPR_STATE[fpr + 1] = fmt_unknown;
279               SignalException (ReservedInstruction, 0);
280             }
281           break;
282
283         default:
284           FPR_STATE[fpr] = fmt_unknown;
285           err = -1;
286           break;
287         }
288     }
289
290   if (err)
291     SignalExceptionSimulatorFault ("Unrecognised FP format in StoreFPR ()");
292
293 #ifdef DEBUG
294   printf ("DBG: StoreFPR: fpr[%d] = 0x%s (format %s)\n",
295           fpr, pr_uword64 (FGR[fpr]), fpu_format_name (fmt));
296 #endif /* DEBUG */
297
298   return;
299 }
300
301
302 /* CP1 control/status register access functions.  */
303
304 void
305 test_fcsr (sim_cpu *cpu,
306            address_word cia)
307 {
308   unsigned int cause;
309
310   cause = (FCSR & fcsr_CAUSE_mask) >> fcsr_CAUSE_shift;
311   if ((cause & ((FCSR & fcsr_ENABLES_mask) >> fcsr_ENABLES_shift)) != 0
312       || (cause & (1 << UO)))
313     {
314       SignalExceptionFPE();
315     }
316 }
317
318 unsigned_word
319 value_fcr(sim_cpu *cpu,
320           address_word cia,
321           int fcr)
322 {
323   unsigned32 value = 0;
324
325   switch (fcr)
326     {
327     case 0:  /* FP Implementation and Revision Register.  */
328       value = FCR0;
329       break;
330     case 25:  /* FP Condition Codes Register (derived from FCSR).  */
331       value = (FCR31 & fcsr_FCC_mask) >> fcsr_FCC_shift;
332       value = (value & 0x1) | (value >> 1);   /* Close FCC gap.  */
333       break;
334     case 26:  /* FP Exceptions Register (derived from FCSR).  */
335       value = FCR31 & (fcsr_CAUSE_mask | fcsr_FLAGS_mask);
336       break;
337     case 28:  /* FP Enables Register (derived from FCSR).  */
338       value = FCR31 & (fcsr_ENABLES_mask | fcsr_RM_mask);
339       if ((FCR31 & fcsr_FS) != 0)
340         value |= fenr_FS;
341       break;
342     case 31:  /* FP Control/Status Register (FCSR).  */
343       value = FCR31 & ~fcsr_ZERO_mask;
344       break;
345     }
346
347   return (EXTEND32 (value));
348 }
349
350 void
351 store_fcr(sim_cpu *cpu,
352           address_word cia,
353           int fcr,
354           unsigned_word value)
355 {
356   unsigned32 v;
357
358   v = VL4_8(value);
359   switch (fcr)
360     {
361     case 25:  /* FP Condition Codes Register (stored into FCSR).  */
362       v = (v << 1) | (v & 0x1);             /* Adjust for FCC gap.  */
363       FCR31 &= ~fcsr_FCC_mask;
364       FCR31 |= ((v << fcsr_FCC_shift) & fcsr_FCC_mask);
365       break;
366     case 26:  /* FP Exceptions Register (stored into FCSR).  */
367       FCR31 &= ~(fcsr_CAUSE_mask | fcsr_FLAGS_mask);
368       FCR31 |= (v & (fcsr_CAUSE_mask | fcsr_FLAGS_mask));
369       test_fcsr(cpu, cia);
370       break;
371     case 28:  /* FP Enables Register (stored into FCSR).  */
372       if ((v & fenr_FS) != 0)
373         v |= fcsr_FS;
374       else
375         v &= ~fcsr_FS;
376       FCR31 &= (fcsr_FCC_mask | fcsr_CAUSE_mask | fcsr_FLAGS_mask);
377       FCR31 |= (v & (fcsr_FS | fcsr_ENABLES_mask | fcsr_RM_mask));
378       test_fcsr(cpu, cia);
379       break;
380     case 31:  /* FP Control/Status Register (FCSR).  */
381       FCR31 = v & ~fcsr_ZERO_mask;
382       test_fcsr(cpu, cia);
383       break;
384     }
385 }
386
387 void
388 update_fcsr (sim_cpu *cpu,
389              address_word cia,
390              sim_fpu_status status)
391 {
392   FCSR &= ~fcsr_CAUSE_mask;
393
394   if (status != 0)
395     {
396       unsigned int cause = 0;
397
398       /* map between sim_fpu codes and MIPS FCSR */
399       if (status & (sim_fpu_status_invalid_snan
400                     | sim_fpu_status_invalid_isi
401                     | sim_fpu_status_invalid_idi
402                     | sim_fpu_status_invalid_zdz
403                     | sim_fpu_status_invalid_imz
404                     | sim_fpu_status_invalid_cmp
405                     | sim_fpu_status_invalid_sqrt
406                     | sim_fpu_status_invalid_cvi))
407         cause |= (1 << IO);
408       if (status & sim_fpu_status_invalid_div0)
409         cause |= (1 << DZ);
410       if (status & sim_fpu_status_overflow)
411         cause |= (1 << OF);
412       if (status & sim_fpu_status_underflow)
413         cause |= (1 << UF);
414       if (status & sim_fpu_status_inexact)
415         cause |= (1 << IR);
416 #if 0 /* Not yet.  */
417       /* Implicit clearing of other bits by unimplemented done by callers.  */
418       if (status & sim_fpu_status_unimplemented)
419         cause |= (1 << UO);
420 #endif
421
422       FCSR |= (cause << fcsr_CAUSE_shift);
423       test_fcsr (cpu, cia);
424       FCSR |= ((cause & ~(1 << UO)) << fcsr_FLAGS_shift);
425     }
426   return;
427 }
428
429 static sim_fpu_round
430 rounding_mode(int rm)
431 {
432   sim_fpu_round round;
433
434   switch (rm)
435     {
436     case FP_RM_NEAREST:
437       /* Round result to nearest representable value. When two
438          representable values are equally near, round to the value
439          that has a least significant bit of zero (i.e. is even).  */
440       round = sim_fpu_round_near;
441       break;
442     case FP_RM_TOZERO:
443       /* Round result to the value closest to, and not greater in
444          magnitude than, the result.  */
445       round = sim_fpu_round_zero;
446       break;
447     case FP_RM_TOPINF:
448       /* Round result to the value closest to, and not less than,
449          the result.  */
450       round = sim_fpu_round_up;
451       break;
452     case FP_RM_TOMINF:
453       /* Round result to the value closest to, and not greater than,
454          the result.  */
455       round = sim_fpu_round_down;
456       break;
457     default:
458       round = 0;
459       fprintf (stderr, "Bad switch\n");
460       abort ();
461     }
462   return round;
463 }
464
465 /* When the FS bit is set, MIPS processors return zero for
466    denormalized results and optionally replace denormalized inputs
467    with zero.  When FS is clear, some implementation trap on input
468    and/or output, while other perform the operation in hardware.  */
469 static sim_fpu_denorm
470 denorm_mode(sim_cpu *cpu)
471 {
472   sim_fpu_denorm denorm;
473
474   /* XXX: FIXME: Eventually should be CPU model dependent.  */
475   if (GETFS())
476     denorm = sim_fpu_denorm_zero;
477   else
478     denorm = 0;
479   return denorm;
480 }
481
482
483 /* Comparison operations.  */
484
485 static sim_fpu_status
486 fp_test(unsigned64 op1,
487         unsigned64 op2,
488         FP_formats fmt,
489         int abs,
490         int cond,
491         int *condition)
492 {
493   sim_fpu wop1;
494   sim_fpu wop2;
495   sim_fpu_status status = 0;
496   int  less, equal, unordered;
497
498   /* The format type has already been checked:  */
499   switch (fmt)
500     {
501     case fmt_single:
502       {
503         sim_fpu_32to (&wop1, op1);
504         sim_fpu_32to (&wop2, op2);
505         break;
506       }
507     case fmt_double:
508       {
509         sim_fpu_64to (&wop1, op1);
510         sim_fpu_64to (&wop2, op2);
511         break;
512       }
513     default:
514       fprintf (stderr, "Bad switch\n");
515       abort ();
516     }
517
518   if (sim_fpu_is_nan (&wop1) || sim_fpu_is_nan (&wop2))
519     {
520       if ((cond & (1 << 3)) ||
521           sim_fpu_is_snan (&wop1) || sim_fpu_is_snan (&wop2))
522         status = sim_fpu_status_invalid_snan;
523       less = 0;
524       equal = 0;
525       unordered = 1;
526     }
527   else
528     {
529       if (abs)
530         {
531           status |= sim_fpu_abs (&wop1, &wop1);
532           status |= sim_fpu_abs (&wop2, &wop2);
533         }
534       equal = sim_fpu_is_eq (&wop1, &wop2);
535       less = !equal && sim_fpu_is_lt (&wop1, &wop2);
536       unordered = 0;
537     }
538   *condition = (((cond & (1 << 2)) && less)
539                 || ((cond & (1 << 1)) && equal)
540                 || ((cond & (1 << 0)) && unordered));
541   return status;
542 }
543
544 void
545 fp_cmp(sim_cpu *cpu,
546        address_word cia,
547        unsigned64 op1,
548        unsigned64 op2,
549        FP_formats fmt,
550        int abs,
551        int cond,
552        int cc)
553 {
554   sim_fpu_status status = 0;
555
556   /* The format type should already have been checked.  The FCSR is
557      updated before the condition codes so that any exceptions will
558      be signalled before the condition codes are changed.  */
559   switch (fmt)
560     {
561     case fmt_single:
562     case fmt_double:
563       {
564         int result;
565         status = fp_test(op1, op2, fmt, abs, cond, &result);
566         update_fcsr (cpu, cia, status);
567         SETFCC (cc, result);
568         break;
569       }
570     default:
571       sim_io_eprintf (SD, "Bad switch\n");
572       abort ();
573     }
574 }
575
576
577 /* Basic arithmetic operations.  */
578
579 static unsigned64
580 fp_unary(sim_cpu *cpu,
581          address_word cia,
582          int (*sim_fpu_op)(sim_fpu *, const sim_fpu *),
583          unsigned64 op,
584          FP_formats fmt)
585 {
586   sim_fpu wop;
587   sim_fpu ans;
588   sim_fpu_round round = rounding_mode (GETRM());
589   sim_fpu_denorm denorm = denorm_mode (cpu);
590   sim_fpu_status status = 0;
591   unsigned64 result = 0;
592
593   /* The format type has already been checked: */
594   switch (fmt)
595     {
596     case fmt_single:
597       {
598         unsigned32 res;
599         sim_fpu_32to (&wop, op);
600         status |= (*sim_fpu_op) (&ans, &wop);
601         status |= sim_fpu_round_32 (&ans, round, denorm);
602         sim_fpu_to32 (&res, &ans);
603         result = res;
604         break;
605       }
606     case fmt_double:
607       {
608         unsigned64 res;
609         sim_fpu_64to (&wop, op);
610         status |= (*sim_fpu_op) (&ans, &wop);
611         status |= sim_fpu_round_64 (&ans, round, denorm);
612         sim_fpu_to64 (&res, &ans);
613         result = res;
614         break;
615       }
616     default:
617       sim_io_eprintf (SD, "Bad switch\n");
618       abort ();
619     }
620
621   update_fcsr (cpu, cia, status);
622   return result;
623 }
624
625 static unsigned64
626 fp_binary(sim_cpu *cpu,
627           address_word cia,
628           int (*sim_fpu_op)(sim_fpu *, const sim_fpu *, const sim_fpu *),
629           unsigned64 op1,
630           unsigned64 op2,
631           FP_formats fmt)
632 {
633   sim_fpu wop1;
634   sim_fpu wop2;
635   sim_fpu ans;
636   sim_fpu_round round = rounding_mode (GETRM());
637   sim_fpu_denorm denorm = denorm_mode (cpu);
638   sim_fpu_status status = 0;
639   unsigned64 result = 0;
640
641   /* The format type has already been checked: */
642   switch (fmt)
643     {
644     case fmt_single:
645       {
646         unsigned32 res;
647         sim_fpu_32to (&wop1, op1);
648         sim_fpu_32to (&wop2, op2);
649         status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
650         status |= sim_fpu_round_32 (&ans, round, denorm);
651         sim_fpu_to32 (&res, &ans);
652         result = res;
653         break;
654       }
655     case fmt_double:
656       {
657         unsigned64 res;
658         sim_fpu_64to (&wop1, op1);
659         sim_fpu_64to (&wop2, op2);
660         status |= (*sim_fpu_op) (&ans, &wop1, &wop2);
661         status |= sim_fpu_round_64 (&ans, round, denorm);
662         sim_fpu_to64 (&res, &ans);
663         result = res;
664         break;
665       }
666     default:
667       sim_io_eprintf (SD, "Bad switch\n");
668       abort ();
669     }
670
671   update_fcsr (cpu, cia, status);
672   return result;
673 }
674
675
676 unsigned64
677 fp_abs(sim_cpu *cpu,
678        address_word cia,
679        unsigned64 op,
680        FP_formats fmt)
681 {
682   return fp_unary(cpu, cia, &sim_fpu_abs, op, fmt);
683 }
684
685 unsigned64
686 fp_neg(sim_cpu *cpu,
687        address_word cia,
688        unsigned64 op,
689        FP_formats fmt)
690 {
691   return fp_unary(cpu, cia, &sim_fpu_neg, op, fmt);
692 }
693
694 unsigned64
695 fp_add(sim_cpu *cpu,
696        address_word cia,
697        unsigned64 op1,
698        unsigned64 op2,
699        FP_formats fmt)
700 {
701   return fp_binary(cpu, cia, &sim_fpu_add, op1, op2, fmt);
702 }
703
704 unsigned64
705 fp_sub(sim_cpu *cpu,
706        address_word cia,
707        unsigned64 op1,
708        unsigned64 op2,
709        FP_formats fmt)
710 {
711   return fp_binary(cpu, cia, &sim_fpu_sub, op1, op2, fmt);
712 }
713
714 unsigned64
715 fp_mul(sim_cpu *cpu,
716        address_word cia,
717        unsigned64 op1,
718        unsigned64 op2,
719        FP_formats fmt)
720 {
721   return fp_binary(cpu, cia, &sim_fpu_mul, op1, op2, fmt);
722 }
723
724 unsigned64
725 fp_div(sim_cpu *cpu,
726        address_word cia,
727        unsigned64 op1,
728        unsigned64 op2,
729        FP_formats fmt)
730 {
731   return fp_binary(cpu, cia, &sim_fpu_div, op1, op2, fmt);
732 }
733
734 unsigned64
735 fp_recip(sim_cpu *cpu,
736          address_word cia,
737          unsigned64 op,
738          FP_formats fmt)
739 {
740   return fp_unary(cpu, cia, &sim_fpu_inv, op, fmt);
741 }
742
743 unsigned64
744 fp_sqrt(sim_cpu *cpu,
745         address_word cia,
746         unsigned64 op,
747         FP_formats fmt)
748 {
749   return fp_unary(cpu, cia, &sim_fpu_sqrt, op, fmt);
750 }
751
752
753 /* Conversion operations.  */
754
755 uword64
756 convert (sim_cpu *cpu,
757          address_word cia,
758          int rm,
759          uword64 op,
760          FP_formats from,
761          FP_formats to)
762 {
763   sim_fpu wop;
764   sim_fpu_round round = rounding_mode (rm);
765   sim_fpu_denorm denorm = denorm_mode (cpu);
766   unsigned32 result32;
767   unsigned64 result64;
768   sim_fpu_status status = 0;
769
770   /* Convert the input to sim_fpu internal format */
771   switch (from)
772     {
773     case fmt_double:
774       sim_fpu_64to (&wop, op);
775       break;
776     case fmt_single:
777       sim_fpu_32to (&wop, op);
778       break;
779     case fmt_word:
780       status = sim_fpu_i32to (&wop, op, round);
781       break;
782     case fmt_long:
783       status = sim_fpu_i64to (&wop, op, round);
784       break;
785     default:
786       sim_io_eprintf (SD, "Bad switch\n");
787       abort ();
788     }
789
790   /* Convert sim_fpu format into the output */
791   /* The value WOP is converted to the destination format, rounding
792      using mode RM. When the destination is a fixed-point format, then
793      a source value of Infinity, NaN or one which would round to an
794      integer outside the fixed point range then an IEEE Invalid
795      Operation condition is raised.  */
796   switch (to)
797     {
798     case fmt_single:
799       status |= sim_fpu_round_32 (&wop, round, denorm);
800       /* For a NaN, normalize mantissa bits (cvt.s.d can't preserve them) */
801       if (sim_fpu_is_qnan (&wop))
802         wop = sim_fpu_qnan;
803       sim_fpu_to32 (&result32, &wop);
804       result64 = result32;
805       break;
806     case fmt_double:
807       status |= sim_fpu_round_64 (&wop, round, denorm);
808       /* For a NaN, normalize mantissa bits (make cvt.d.s consistent) */
809       if (sim_fpu_is_qnan (&wop))
810         wop = sim_fpu_qnan;
811       sim_fpu_to64 (&result64, &wop);
812       break;
813     case fmt_word:
814       status |= sim_fpu_to32i (&result32, &wop, round);
815       result64 = result32;
816       break;
817     case fmt_long:
818       status |= sim_fpu_to64i (&result64, &wop, round);
819       break;
820     default:
821       result64 = 0;
822       sim_io_eprintf (SD, "Bad switch\n");
823       abort ();
824     }
825
826   update_fcsr (cpu, cia, status);
827   return result64;
828 }
829
830 static const char *
831 fpu_format_name (FP_formats fmt)
832 {
833   switch (fmt)
834     {
835     case fmt_single:
836       return "single";
837     case fmt_double:
838       return "double";
839     case fmt_word:
840       return "word";
841     case fmt_long:
842       return "long";
843     case fmt_unknown:
844       return "<unknown>";
845     case fmt_uninterpreted:
846       return "<uninterpreted>";
847     case fmt_uninterpreted_32:
848       return "<uninterpreted_32>";
849     case fmt_uninterpreted_64:
850       return "<uninterpreted_64>";
851     default:
852       return "<format error>";
853     }
854 }
855
856 #ifdef DEBUG
857 static const char *
858 fpu_rounding_mode_name (int rm)
859 {
860   switch (rm)
861     {
862     case FP_RM_NEAREST:
863       return "Round";
864     case FP_RM_TOZERO:
865       return "Trunc";
866     case FP_RM_TOPINF:
867       return "Ceil";
868     case FP_RM_TOMINF:
869       return "Floor";
870     default:
871       return "<rounding mode error>";
872     }
873 }
874 #endif /* DEBUG */