PR sim/14540
[external/binutils.git] / sim / arm / maverick.c
1 /*  maverick.c -- Cirrus/DSP co-processor interface.
2     Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc.
3     Contributed by Aldy Hernandez (aldyh@redhat.com).
4  
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU 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, see <http://www.gnu.org/licenses/>. */
17
18 #include <assert.h>
19 #include "armdefs.h"
20 #include "ansidecl.h"
21 #include "armemu.h"
22
23 /*#define CIRRUS_DEBUG 1        /**/
24 #if CIRRUS_DEBUG
25 #  define printfdbg printf
26 #else
27 #  define printfdbg printf_nothing
28 #endif
29
30 #define POS64(i) ( (~(i)) >> 63 )
31 #define NEG64(i) ( (i) >> 63 )
32
33 /* Define Co-Processor instruction handlers here.  */
34
35 /* Here's ARMulator's DSP definition.  A few things to note:
36    1) it has 16 64-bit registers and 4 72-bit accumulators
37    2) you can only access its registers with MCR and MRC.  */
38
39 /* We can't define these in here because this file might not be linked
40    unless the target is arm9e-*.  They are defined in wrapper.c.
41    Eventually the simulator should be made to handle any coprocessor
42    at run time.  */
43 struct maverick_regs
44 {
45   union
46   {
47     int i;
48     float f;
49   } upper;
50   
51   union
52   {
53     int i;
54     float f;
55   } lower;
56 };
57
58 union maverick_acc_regs
59 {
60   long double ld;               /* Acc registers are 72-bits.  */
61 };
62
63 struct maverick_regs DSPregs[16];
64 union maverick_acc_regs DSPacc[4];
65 ARMword DSPsc;
66
67 #define DEST_REG        (BITS (12, 15))
68 #define SRC1_REG        (BITS (16, 19))
69 #define SRC2_REG        (BITS (0, 3))
70
71 static int lsw_int_index, msw_int_index;
72 static int lsw_float_index, msw_float_index;
73
74 static double mv_getRegDouble (int);
75 static long long mv_getReg64int (int);
76 static void mv_setRegDouble (int, double val);
77 static void mv_setReg64int (int, long long val);
78
79 static union
80 {
81   double d;
82   long long ll;
83   int ints[2];
84 } reg_conv;
85
86 static void
87 printf_nothing (void * foo, ...)
88 {
89 }
90
91 static void
92 cirrus_not_implemented (char * insn)
93 {
94   fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn);
95   fprintf (stderr, "aborting!\n");
96   
97   exit (1);
98 }
99
100 static unsigned
101 DSPInit (ARMul_State * state)
102 {
103   ARMul_ConsolePrint (state, ", DSP present");
104   return TRUE;
105 }
106
107 unsigned
108 DSPMRC4 (ARMul_State * state ATTRIBUTE_UNUSED,
109          unsigned      type  ATTRIBUTE_UNUSED,
110          ARMword       instr,
111          ARMword *     value)
112 {
113   switch (BITS (5, 7))
114     {
115     case 0: /* cfmvrdl */
116       /* Move lower half of a DF stored in a DSP reg into an Arm reg.  */
117       printfdbg ("cfmvrdl\n");
118       printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i);
119       printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
120       
121       *value = (ARMword) DSPregs[SRC1_REG].lower.i;
122       break;
123       
124     case 1: /* cfmvrdh */
125       /* Move upper half of a DF stored in a DSP reg into an Arm reg.  */
126       printfdbg ("cfmvrdh\n");
127       printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i);
128       printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
129       
130       *value = (ARMword) DSPregs[SRC1_REG].upper.i;
131       break;
132       
133     case 2: /* cfmvrs */
134       /* Move SF from upper half of a DSP register to an Arm register.  */
135       *value = (ARMword) DSPregs[SRC1_REG].upper.i;
136       printfdbg ("cfmvrs = mvf%d <-- %f\n",
137                  SRC1_REG,
138                  DSPregs[SRC1_REG].upper.f);
139       break;
140       
141 #ifdef doesnt_work
142     case 4: /* cfcmps */
143       {
144         float a, b;
145         int n, z, c, v;
146
147         a = DSPregs[SRC1_REG].upper.f;
148         b = DSPregs[SRC2_REG].upper.f;
149
150         printfdbg ("cfcmps\n");
151         printfdbg ("\tcomparing %f and %f\n", a, b);
152
153         z = a == b;             /* zero */
154         n = a != b;             /* negative */
155         v = a > b;              /* overflow */
156         c = 0;                  /* carry */
157         *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
158         break;
159       }
160       
161     case 5: /* cfcmpd */
162       {
163         double a, b;
164         int n, z, c, v;
165
166         a = mv_getRegDouble (SRC1_REG);
167         b = mv_getRegDouble (SRC2_REG);
168
169         printfdbg ("cfcmpd\n");
170         printfdbg ("\tcomparing %g and %g\n", a, b);
171
172         z = a == b;             /* zero */
173         n = a != b;             /* negative */
174         v = a > b;              /* overflow */
175         c = 0;                  /* carry */
176         *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
177         break;
178       }
179 #else
180       case 4: /* cfcmps */
181         {
182           float a, b;
183           int n, z, c, v;
184
185           a = DSPregs[SRC1_REG].upper.f;
186           b = DSPregs[SRC2_REG].upper.f;
187   
188           printfdbg ("cfcmps\n");
189           printfdbg ("\tcomparing %f and %f\n", a, b);
190
191           z = a == b;           /* zero */
192           n = a < b;            /* negative */
193           c = a > b;            /* carry */
194           v = 0;                /* fixme */
195           printfdbg ("\tz = %d, n = %d\n", z, n);
196           *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
197           break;
198         }
199         
200       case 5: /* cfcmpd */
201         {
202           double a, b;
203           int n, z, c, v;
204
205           a = mv_getRegDouble (SRC1_REG);
206           b = mv_getRegDouble (SRC2_REG);
207   
208           printfdbg ("cfcmpd\n");
209           printfdbg ("\tcomparing %g and %g\n", a, b);
210   
211           z = a == b;           /* zero */
212           n = a < b;            /* negative */
213           c = a > b;            /* carry */
214           v = 0;                /* fixme */
215           *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
216           break;
217         }
218 #endif
219     default:
220       fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr);
221       cirrus_not_implemented ("unknown");
222       break;
223     }
224
225   return ARMul_DONE;
226 }
227
228 unsigned
229 DSPMRC5 (ARMul_State * state ATTRIBUTE_UNUSED,
230          unsigned      type  ATTRIBUTE_UNUSED,
231          ARMword       instr,
232          ARMword *     value)
233 {
234   switch (BITS (5, 7))
235     {
236     case 0: /* cfmvr64l */
237       /* Move lower half of 64bit int from Cirrus to Arm.  */
238       *value = (ARMword) DSPregs[SRC1_REG].lower.i;
239       printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n",
240                  DEST_REG,
241                  (int) *value);
242       break;
243       
244     case 1: /* cfmvr64h */
245       /* Move upper half of 64bit int from Cirrus to Arm.  */
246       *value = (ARMword) DSPregs[SRC1_REG].upper.i;
247       printfdbg ("cfmvr64h <-- %d\n", (int) *value);
248       break;
249       
250     case 4: /* cfcmp32 */
251       {
252         int res;
253         int n, z, c, v;
254         unsigned int a, b;
255
256         printfdbg ("cfcmp32 mvfx%d - mvfx%d\n",
257                    SRC1_REG,
258                    SRC2_REG);
259
260         /* FIXME: see comment for cfcmps.  */
261         a = DSPregs[SRC1_REG].lower.i;
262         b = DSPregs[SRC2_REG].lower.i;
263
264         res = DSPregs[SRC1_REG].lower.i - DSPregs[SRC2_REG].lower.i;
265         /* zero */
266         z = res == 0;
267         /* negative */
268         n = res < 0;
269         /* overflow */
270         v = SubOverflow (DSPregs[SRC1_REG].lower.i, DSPregs[SRC2_REG].lower.i,
271                          res);
272         /* carry */
273         c = (NEG (a) && POS (b) ||
274              (NEG (a) && POS (res)) || (POS (b) && POS (res)));
275
276         *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
277         break;
278       }
279       
280     case 5: /* cfcmp64 */
281       {
282         long long res;
283         int n, z, c, v;
284         unsigned long long a, b;
285
286         printfdbg ("cfcmp64 mvdx%d - mvdx%d\n",
287                    SRC1_REG,
288                    SRC2_REG);
289
290         /* fixme: see comment for cfcmps.  */
291
292         a = mv_getReg64int (SRC1_REG);
293         b = mv_getReg64int (SRC2_REG);
294
295         res = mv_getReg64int (SRC1_REG) - mv_getReg64int (SRC2_REG);
296         /* zero */
297         z = res == 0;
298         /* negative */
299         n = res < 0;
300         /* overflow */
301         v = ((NEG64 (a) && POS64 (b) && POS64 (res))
302              || (POS64 (a) && NEG64 (b) && NEG64 (res)));
303         /* carry */
304         c = (NEG64 (a) && POS64 (b) ||
305              (NEG64 (a) && POS64 (res)) || (POS64 (b) && POS64 (res)));
306
307         *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
308         break;
309       }
310       
311     default:
312       fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr);
313       cirrus_not_implemented ("unknown");
314       break;
315     }
316
317   return ARMul_DONE;
318 }
319
320 unsigned
321 DSPMRC6 (ARMul_State * state ATTRIBUTE_UNUSED,
322          unsigned      type  ATTRIBUTE_UNUSED,
323          ARMword       instr,
324          ARMword *     value)
325 {
326   switch (BITS (5, 7))
327     {
328     case 0: /* cfmval32 */
329       cirrus_not_implemented ("cfmval32");
330       break;
331       
332     case 1: /* cfmvam32 */
333       cirrus_not_implemented ("cfmvam32");
334       break;
335       
336     case 2: /* cfmvah32 */
337       cirrus_not_implemented ("cfmvah32");
338       break;
339       
340     case 3: /* cfmva32 */
341       cirrus_not_implemented ("cfmva32");
342       break;
343       
344     case 4: /* cfmva64 */
345       cirrus_not_implemented ("cfmva64");
346       break;
347       
348     case 5: /* cfmvsc32 */
349       cirrus_not_implemented ("cfmvsc32");
350       break;
351       
352     default:
353       fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr);
354       cirrus_not_implemented ("unknown");
355       break;
356     }
357
358   return ARMul_DONE;
359 }
360
361 unsigned
362 DSPMCR4 (ARMul_State * state,
363          unsigned      type ATTRIBUTE_UNUSED,
364          ARMword       instr,
365          ARMword       value)
366 {
367   switch (BITS (5, 7))
368     {
369     case 0: /* cfmvdlr */
370       /* Move the lower half of a DF value from an Arm register into
371          the lower half of a Cirrus register.  */
372       printfdbg ("cfmvdlr <-- 0x%x\n", (int) value);
373       DSPregs[SRC1_REG].lower.i = (int) value;
374       break;
375       
376     case 1: /* cfmvdhr */
377       /* Move the upper half of a DF value from an Arm register into
378          the upper half of a Cirrus register.  */
379       printfdbg ("cfmvdhr <-- 0x%x\n", (int) value);
380       DSPregs[SRC1_REG].upper.i = (int) value;
381       break;
382       
383     case 2: /* cfmvsr */
384       /* Move SF from Arm register into upper half of Cirrus register.  */
385       printfdbg ("cfmvsr <-- 0x%x\n", (int) value);
386       DSPregs[SRC1_REG].upper.i = (int) value;
387       break;
388       
389     default:
390       fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr);
391       cirrus_not_implemented ("unknown");
392       break;
393     }
394
395   return ARMul_DONE;
396 }
397
398 unsigned
399 DSPMCR5 (ARMul_State * state,
400          unsigned      type   ATTRIBUTE_UNUSED,
401          ARMword       instr,
402          ARMword       value)
403 {
404   union
405   {
406     int s;
407     unsigned int us;
408   } val;
409
410   switch (BITS (5, 7))
411     {
412     case 0: /* cfmv64lr */
413       /* Move lower half of a 64bit int from an ARM register into the
414          lower half of a DSP register and sign extend it.  */
415       printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, (int) value);
416       DSPregs[SRC1_REG].lower.i = (int) value;
417       break;
418       
419     case 1: /* cfmv64hr */
420       /* Move upper half of a 64bit int from an ARM register into the
421          upper half of a DSP register.  */
422       printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n",
423                  SRC1_REG,
424                  (int) value);
425       DSPregs[SRC1_REG].upper.i = (int) value;
426       break;
427       
428     case 2: /* cfrshl32 */
429       printfdbg ("cfrshl32\n");
430       val.us = value;
431       if (val.s > 0)
432         DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i << value;
433       else
434         DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -value;
435       break;
436       
437     case 3: /* cfrshl64 */
438       printfdbg ("cfrshl64\n");
439       val.us = value;
440       if (val.s > 0)
441         mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) << value);
442       else
443         mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) >> -value);
444       break;
445       
446     default:
447       fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr);
448       cirrus_not_implemented ("unknown");
449       break;
450     }
451
452   return ARMul_DONE;
453 }
454
455 unsigned
456 DSPMCR6 (ARMul_State * state,
457          unsigned      type   ATTRIBUTE_UNUSED,
458          ARMword       instr,
459          ARMword       value)
460 {
461   switch (BITS (5, 7))
462     {
463     case 0: /* cfmv32al */
464       cirrus_not_implemented ("cfmv32al");
465       break;
466       
467     case 1: /* cfmv32am */
468       cirrus_not_implemented ("cfmv32am");
469       break;
470       
471     case 2: /* cfmv32ah */
472       cirrus_not_implemented ("cfmv32ah");
473       break;
474       
475     case 3: /* cfmv32a */
476       cirrus_not_implemented ("cfmv32a");
477       break;
478       
479     case 4: /* cfmv64a */
480       cirrus_not_implemented ("cfmv64a");
481       break;
482       
483     case 5: /* cfmv32sc */
484       cirrus_not_implemented ("cfmv32sc");
485       break;
486       
487     default:
488       fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr);
489       cirrus_not_implemented ("unknown");
490       break;
491     }
492
493   return ARMul_DONE;
494 }
495
496 unsigned
497 DSPLDC4 (ARMul_State * state ATTRIBUTE_UNUSED,
498          unsigned      type,
499          ARMword       instr,
500          ARMword       data)
501 {
502   static unsigned words;
503
504   if (type != ARMul_DATA)
505     {
506       words = 0;
507       return ARMul_DONE;
508     }
509   
510   if (BIT (22))
511     {                           /* it's a long access, get two words */
512       /* cfldrd */
513
514       printfdbg ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n",
515                  data, words, state->bigendSig, DEST_REG);
516       
517       if (words == 0)
518         {
519           if (state->bigendSig)
520             DSPregs[DEST_REG].upper.i = (int) data;
521           else
522             DSPregs[DEST_REG].lower.i = (int) data;
523         }
524       else
525         {
526           if (state->bigendSig)
527             DSPregs[DEST_REG].lower.i = (int) data;
528           else
529             DSPregs[DEST_REG].upper.i = (int) data;
530         }
531       
532       ++ words;
533       
534       if (words == 2)
535         {
536           printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG,
537                      mv_getRegDouble (DEST_REG));
538           
539           return ARMul_DONE;
540         }
541       else
542         return ARMul_INC;
543     }
544   else
545     {
546       /* Get just one word.  */
547       
548       /* cfldrs */
549       printfdbg ("cfldrs\n");
550
551       DSPregs[DEST_REG].upper.i = (int) data;
552
553       printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG,
554                  DSPregs[DEST_REG].upper.f);
555
556       return ARMul_DONE;
557     }
558 }
559
560 unsigned
561 DSPLDC5 (ARMul_State * state ATTRIBUTE_UNUSED,
562          unsigned      type,
563          ARMword       instr,
564          ARMword       data)
565 {
566   static unsigned words;
567
568   if (type != ARMul_DATA)
569     {
570       words = 0;
571       return ARMul_DONE;
572     }
573   
574   if (BIT (22))
575     {
576       /* It's a long access, get two words.  */
577       
578       /* cfldr64 */
579       printfdbg ("cfldr64: %d\n", data);
580
581       if (words == 0)
582         {
583           if (state->bigendSig)
584             DSPregs[DEST_REG].upper.i = (int) data;
585           else
586             DSPregs[DEST_REG].lower.i = (int) data;
587         }
588       else
589         {
590           if (state->bigendSig)
591             DSPregs[DEST_REG].lower.i = (int) data;
592           else
593             DSPregs[DEST_REG].upper.i = (int) data;
594         }
595       
596       ++ words;
597       
598       if (words == 2)
599         {
600           printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG,
601                      mv_getReg64int (DEST_REG));
602           
603           return ARMul_DONE;
604         }
605       else
606         return ARMul_INC;
607     }
608   else
609     {
610       /* Get just one word.  */
611       
612       /* cfldr32 */
613       printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data);
614       
615       /* 32bit ints should be sign extended to 64bits when loaded.  */
616       mv_setReg64int (DEST_REG, (long long) data);
617
618       return ARMul_DONE;
619     }
620 }
621
622 unsigned
623 DSPSTC4 (ARMul_State * state ATTRIBUTE_UNUSED,
624          unsigned      type,
625          ARMword       instr,
626          ARMword *     data)
627 {
628   static unsigned words;
629
630   if (type != ARMul_DATA)
631     {
632       words = 0;
633       return ARMul_DONE;
634     }
635   
636   if (BIT (22))
637     {
638       /* It's a long access, get two words.  */
639       /* cfstrd */
640       printfdbg ("cfstrd\n");
641
642       if (words == 0)
643         {
644           if (state->bigendSig)
645             *data = (ARMword) DSPregs[DEST_REG].upper.i;
646           else
647             *data = (ARMword) DSPregs[DEST_REG].lower.i;
648         }
649       else
650         {
651           if (state->bigendSig)
652             *data = (ARMword) DSPregs[DEST_REG].lower.i;
653           else
654             *data = (ARMword) DSPregs[DEST_REG].upper.i;
655         }
656       
657       ++ words;
658       
659       if (words == 2)
660         {
661           printfdbg ("\tmem = mvd%d = %g\n", DEST_REG,
662                      mv_getRegDouble (DEST_REG));
663           
664           return ARMul_DONE;
665         }
666       else
667         return ARMul_INC;
668     }
669   else
670     {
671       /* Get just one word.  */
672       /* cfstrs */
673       printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG,
674                  DSPregs[DEST_REG].upper.f);
675
676       *data = (ARMword) DSPregs[DEST_REG].upper.i;
677
678       return ARMul_DONE;
679     }
680 }
681
682 unsigned
683 DSPSTC5 (ARMul_State * state ATTRIBUTE_UNUSED,
684          unsigned      type,
685          ARMword       instr,
686          ARMword *     data)
687 {
688   static unsigned words;
689
690   if (type != ARMul_DATA)
691     {
692       words = 0;
693       return ARMul_DONE;
694     }
695   
696   if (BIT (22))
697     {
698       /* It's a long access, store two words.  */
699       /* cfstr64 */
700       printfdbg ("cfstr64\n");
701
702       if (words == 0)
703         {
704           if (state->bigendSig)
705             *data = (ARMword) DSPregs[DEST_REG].upper.i;
706           else
707             *data = (ARMword) DSPregs[DEST_REG].lower.i;
708         }
709       else
710         {
711           if (state->bigendSig)
712             *data = (ARMword) DSPregs[DEST_REG].lower.i;
713           else
714             *data = (ARMword) DSPregs[DEST_REG].upper.i;
715         }
716       
717       ++ words;
718       
719       if (words == 2)
720         {
721           printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG,
722                      mv_getReg64int (DEST_REG));
723           
724           return ARMul_DONE;
725         }
726       else
727         return ARMul_INC;
728     }
729   else
730     {
731       /* Store just one word.  */
732       /* cfstr32 */
733       *data = (ARMword) DSPregs[DEST_REG].lower.i;
734       
735       printfdbg ("cfstr32 MEM = %d\n", (int) *data);
736
737       return ARMul_DONE;
738     }
739 }
740
741 unsigned
742 DSPCDP4 (ARMul_State * state,
743          unsigned      type,
744          ARMword       instr)
745 {
746   int opcode2;
747
748   opcode2 = BITS (5,7);
749
750   switch (BITS (20,21))
751     {
752     case 0:
753       switch (opcode2)
754         {
755         case 0: /* cfcpys */
756           printfdbg ("cfcpys mvf%d = mvf%d = %f\n",
757                      DEST_REG,
758                      SRC1_REG,
759                      DSPregs[SRC1_REG].upper.f);
760           DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f;
761           break;
762           
763         case 1: /* cfcpyd */
764           printfdbg ("cfcpyd mvd%d = mvd%d = %g\n",
765                      DEST_REG,
766                      SRC1_REG,
767                      mv_getRegDouble (SRC1_REG));
768           mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG));
769           break;
770           
771         case 2: /* cfcvtds */
772           printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n",
773                      DEST_REG,
774                      SRC1_REG,
775                      (float) mv_getRegDouble (SRC1_REG));
776           DSPregs[DEST_REG].upper.f = (float) mv_getRegDouble (SRC1_REG);
777           break;
778           
779         case 3: /* cfcvtsd */
780           printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n",
781                      DEST_REG,
782                      SRC1_REG,
783                      (double) DSPregs[SRC1_REG].upper.f);
784           mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].upper.f);
785           break;
786           
787         case 4: /* cfcvt32s */
788           printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n",
789                      DEST_REG,
790                      SRC1_REG,
791                      (float) DSPregs[SRC1_REG].lower.i);
792           DSPregs[DEST_REG].upper.f = (float) DSPregs[SRC1_REG].lower.i;
793           break;
794           
795         case 5: /* cfcvt32d */
796           printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n",
797                      DEST_REG,
798                      SRC1_REG,
799                      (double) DSPregs[SRC1_REG].lower.i);
800           mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].lower.i);
801           break;
802           
803         case 6: /* cfcvt64s */
804           printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n",
805                      DEST_REG,
806                      SRC1_REG,
807                      (float) mv_getReg64int (SRC1_REG));
808           DSPregs[DEST_REG].upper.f = (float) mv_getReg64int (SRC1_REG);
809           break;
810           
811         case 7: /* cfcvt64d */
812           printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n",
813                      DEST_REG,
814                      SRC1_REG,
815                      (double) mv_getReg64int (SRC1_REG));
816           mv_setRegDouble (DEST_REG, (double) mv_getReg64int (SRC1_REG));
817           break;
818         }
819       break;
820
821     case 1:
822       switch (opcode2)
823         {
824         case 0: /* cfmuls */
825           printfdbg ("cfmuls mvf%d = mvf%d = %f\n",
826                      DEST_REG,
827                      SRC1_REG,
828                      DSPregs[SRC1_REG].upper.f * DSPregs[SRC2_REG].upper.f);
829                      
830           DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
831             * DSPregs[SRC2_REG].upper.f;
832           break;
833           
834         case 1: /* cfmuld */
835           printfdbg ("cfmuld mvd%d = mvd%d = %g\n",
836                      DEST_REG,
837                      SRC1_REG,
838                      mv_getRegDouble (SRC1_REG) * mv_getRegDouble (SRC2_REG));
839
840           mv_setRegDouble (DEST_REG,
841                            mv_getRegDouble (SRC1_REG)
842                            * mv_getRegDouble (SRC2_REG));
843           break;
844           
845         default:
846           fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
847           cirrus_not_implemented ("unknown");
848           break;
849         }
850       break;
851
852     case 3:
853       switch (opcode2)
854         {
855         case 0: /* cfabss */
856           DSPregs[DEST_REG].upper.f = (DSPregs[SRC1_REG].upper.f < 0.0F ?
857                                        -DSPregs[SRC1_REG].upper.f
858                                        : DSPregs[SRC1_REG].upper.f);
859           printfdbg ("cfabss mvf%d = |mvf%d| = %f\n",
860                      DEST_REG,
861                      SRC1_REG,
862                      DSPregs[DEST_REG].upper.f);
863           break;
864           
865         case 1: /* cfabsd */
866           mv_setRegDouble (DEST_REG,
867                            (mv_getRegDouble (SRC1_REG) < 0.0 ?
868                             -mv_getRegDouble (SRC1_REG)
869                             : mv_getRegDouble (SRC1_REG)));
870           printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n",
871                      DEST_REG,
872                      SRC1_REG,
873                      mv_getRegDouble (DEST_REG));
874           break;
875           
876         case 2: /* cfnegs */
877           DSPregs[DEST_REG].upper.f = -DSPregs[SRC1_REG].upper.f;
878           printfdbg ("cfnegs mvf%d = -mvf%d = %f\n",
879                      DEST_REG,
880                      SRC1_REG,
881                      DSPregs[DEST_REG].upper.f);
882           break;
883           
884         case 3: /* cfnegd */
885           mv_setRegDouble (DEST_REG,
886                            -mv_getRegDouble (SRC1_REG));
887           printfdbg ("cfnegd mvd%d = -mvd%d = %g\n",
888                      DEST_REG,
889                      mv_getRegDouble (DEST_REG));
890           break;
891           
892         case 4: /* cfadds */
893           DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
894             + DSPregs[SRC2_REG].upper.f;
895           printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n",
896                      DEST_REG,
897                      SRC1_REG,
898                      SRC2_REG,
899                      DSPregs[DEST_REG].upper.f);
900           break;
901           
902         case 5: /* cfaddd */
903           mv_setRegDouble (DEST_REG,
904                            mv_getRegDouble (SRC1_REG)
905                            + mv_getRegDouble (SRC2_REG));
906           printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n",
907                      DEST_REG,
908                      SRC1_REG,
909                      SRC2_REG,
910                      mv_getRegDouble (DEST_REG));
911           break;
912           
913         case 6: /* cfsubs */
914           DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
915             - DSPregs[SRC2_REG].upper.f;
916           printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n",
917                      DEST_REG,
918                      SRC1_REG,
919                      SRC2_REG,
920                      DSPregs[DEST_REG].upper.f);
921           break;
922           
923         case 7: /* cfsubd */
924           mv_setRegDouble (DEST_REG,
925                            mv_getRegDouble (SRC1_REG)
926                            - mv_getRegDouble (SRC2_REG));
927           printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n",
928                      DEST_REG,
929                      SRC1_REG,
930                      SRC2_REG,
931                      mv_getRegDouble (DEST_REG));
932           break;
933         }
934       break;
935
936     default:
937       fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
938       cirrus_not_implemented ("unknown");
939       break;
940     }
941
942   return ARMul_DONE;
943 }
944
945 unsigned
946 DSPCDP5 (ARMul_State * state,
947          unsigned      type,
948          ARMword       instr)
949 {
950    int opcode2;
951    char shift;
952
953    opcode2 = BITS (5,7);
954
955    /* Shift constants are 7bit signed numbers in bits 0..3|5..7.  */
956    shift = BITS (0, 3) | (BITS (5, 7)) << 4;
957    if (shift & 0x40)
958      shift |= 0xc0;
959
960    switch (BITS (20,21))
961      {
962      case 0:
963        /* cfsh32 */
964        printfdbg ("cfsh32 %s amount=%d\n", shift < 0 ? "right" : "left",
965                   shift);
966        if (shift < 0)
967          /* Negative shift is a right shift.  */
968          DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -shift;
969        else
970          /* Positive shift is a left shift.  */
971          DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i << shift;
972        break;
973
974      case 1:
975        switch (opcode2)
976          {
977          case 0: /* cfmul32 */
978            DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
979              * DSPregs[SRC2_REG].lower.i;
980            printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n",
981                       DEST_REG,
982                       SRC1_REG,
983                       SRC2_REG,
984                       DSPregs[DEST_REG].lower.i);
985            break;
986            
987          case 1: /* cfmul64 */
988            mv_setReg64int (DEST_REG,
989                            mv_getReg64int (SRC1_REG)
990                            * mv_getReg64int (SRC2_REG));
991            printfdbg ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n",
992                       DEST_REG,
993                       SRC1_REG,
994                       SRC2_REG,
995                       mv_getReg64int (DEST_REG));
996            break;
997            
998          case 2: /* cfmac32 */
999            DSPregs[DEST_REG].lower.i
1000              += DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i;
1001            printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n",
1002                       DEST_REG,
1003                       SRC1_REG,
1004                       SRC2_REG,
1005                       DSPregs[DEST_REG].lower.i);
1006            break;
1007            
1008          case 3: /* cfmsc32 */
1009            DSPregs[DEST_REG].lower.i
1010              -= DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i;
1011            printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n",
1012                       DEST_REG,
1013                       SRC1_REG,
1014                       SRC2_REG,
1015                       DSPregs[DEST_REG].lower.i);
1016            break;
1017            
1018          case 4: /* cfcvts32 */
1019            /* fixme: this should round */
1020            DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f;
1021            printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n",
1022                       DEST_REG,
1023                       SRC1_REG,
1024                       DSPregs[DEST_REG].lower.i);
1025            break;
1026            
1027          case 5: /* cfcvtd32 */
1028            /* fixme: this should round */
1029            DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG);
1030            printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n",
1031                       DEST_REG,
1032                       SRC1_REG,
1033                       DSPregs[DEST_REG].lower.i);
1034            break;
1035            
1036          case 6: /* cftruncs32 */
1037            DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f;
1038            printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n",
1039                       DEST_REG,
1040                       SRC1_REG,
1041                       DSPregs[DEST_REG].lower.i);
1042            break;
1043            
1044          case 7: /* cftruncd32 */
1045            DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG);
1046            printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n",
1047                       DEST_REG,
1048                       SRC1_REG,
1049                       DSPregs[DEST_REG].lower.i);
1050            break;
1051          }
1052        break;
1053
1054      case 2:
1055        /* cfsh64 */
1056        printfdbg ("cfsh64\n");
1057        
1058        if (shift < 0)
1059          /* Negative shift is a right shift.  */
1060          mv_setReg64int (DEST_REG,
1061                          mv_getReg64int (SRC1_REG) >> -shift);
1062        else
1063          /* Positive shift is a left shift.  */
1064          mv_setReg64int (DEST_REG,
1065                          mv_getReg64int (SRC1_REG) << shift);
1066        printfdbg ("\t%llx\n", mv_getReg64int(DEST_REG));
1067        break;
1068
1069      case 3:
1070        switch (opcode2)
1071          {
1072          case 0: /* cfabs32 */
1073            DSPregs[DEST_REG].lower.i = (DSPregs[SRC1_REG].lower.i < 0
1074              ? -DSPregs[SRC1_REG].lower.i : DSPregs[SRC1_REG].lower.i);
1075            printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n",
1076                       DEST_REG,
1077                       SRC1_REG,
1078                       SRC2_REG,
1079                       DSPregs[DEST_REG].lower.i);
1080            break;
1081            
1082          case 1: /* cfabs64 */
1083            mv_setReg64int (DEST_REG,
1084                            (mv_getReg64int (SRC1_REG) < 0
1085                             ? -mv_getReg64int (SRC1_REG)
1086                             : mv_getReg64int (SRC1_REG)));
1087            printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n",
1088                       DEST_REG,
1089                       SRC1_REG,
1090                       SRC2_REG,
1091                       mv_getReg64int (DEST_REG));
1092            break;
1093            
1094          case 2: /* cfneg32 */
1095            DSPregs[DEST_REG].lower.i = -DSPregs[SRC1_REG].lower.i;
1096            printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n",
1097                       DEST_REG,
1098                       SRC1_REG,
1099                       SRC2_REG,
1100                       DSPregs[DEST_REG].lower.i);
1101            break;
1102            
1103          case 3: /* cfneg64 */
1104            mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG));
1105            printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n",
1106                       DEST_REG,
1107                       SRC1_REG,
1108                       SRC2_REG,
1109                       mv_getReg64int (DEST_REG));
1110            break;
1111            
1112          case 4: /* cfadd32 */
1113            DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
1114              + DSPregs[SRC2_REG].lower.i;
1115            printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n",
1116                       DEST_REG,
1117                       SRC1_REG,
1118                       SRC2_REG,
1119                       DSPregs[DEST_REG].lower.i);
1120            break;
1121            
1122          case 5: /* cfadd64 */
1123            mv_setReg64int (DEST_REG,
1124                            mv_getReg64int (SRC1_REG)
1125                            + mv_getReg64int (SRC2_REG));
1126            printfdbg ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n",
1127                       DEST_REG,
1128                       SRC1_REG,
1129                       SRC2_REG,
1130                       mv_getReg64int (DEST_REG));
1131            break;
1132            
1133          case 6: /* cfsub32 */
1134            DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
1135              - DSPregs[SRC2_REG].lower.i;
1136            printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n",
1137                       DEST_REG,
1138                       SRC1_REG,
1139                       SRC2_REG,
1140                       DSPregs[DEST_REG].lower.i);
1141            break;
1142            
1143          case 7: /* cfsub64 */
1144            mv_setReg64int (DEST_REG,
1145                            mv_getReg64int (SRC1_REG)
1146                            - mv_getReg64int (SRC2_REG));
1147            printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n",
1148                       DEST_REG,
1149                       SRC1_REG,
1150                       SRC2_REG,
1151                       mv_getReg64int (DEST_REG));
1152            break;
1153          }
1154        break;
1155
1156      default:
1157        fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr);
1158        cirrus_not_implemented ("unknown");
1159        break;
1160      }
1161
1162   return ARMul_DONE;
1163 }
1164
1165 unsigned
1166 DSPCDP6 (ARMul_State * state,
1167          unsigned      type,
1168          ARMword       instr)
1169 {
1170    int opcode2;
1171
1172    opcode2 = BITS (5,7);
1173
1174    switch (BITS (20,21))
1175      {
1176      case 0:
1177        /* cfmadd32 */
1178        cirrus_not_implemented ("cfmadd32");
1179        break;
1180        
1181      case 1:
1182        /* cfmsub32 */
1183        cirrus_not_implemented ("cfmsub32");
1184        break;
1185        
1186      case 2:
1187        /* cfmadda32 */
1188        cirrus_not_implemented ("cfmadda32");
1189        break;
1190        
1191      case 3:
1192        /* cfmsuba32 */
1193        cirrus_not_implemented ("cfmsuba32");
1194        break;
1195
1196      default:
1197        fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr);
1198      }
1199
1200    return ARMul_DONE;
1201 }
1202
1203 /* Conversion functions.
1204
1205    32-bit integers are stored in the LOWER half of a 64-bit physical
1206    register.
1207
1208    Single precision floats are stored in the UPPER half of a 64-bit
1209    physical register.  */
1210
1211 static double
1212 mv_getRegDouble (int regnum)
1213 {
1214   reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i;
1215   reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i;
1216   return reg_conv.d;
1217 }
1218
1219 static void
1220 mv_setRegDouble (int regnum, double val)
1221 {
1222   reg_conv.d = val;
1223   DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index];
1224   DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index];
1225 }
1226
1227 static long long
1228 mv_getReg64int (int regnum)
1229 {
1230   reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i;
1231   reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i;
1232   return reg_conv.ll;
1233 }
1234
1235 static void
1236 mv_setReg64int (int regnum, long long val)
1237 {
1238   reg_conv.ll = val;
1239   DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index];
1240   DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index];
1241 }
1242
1243 /* Compute LSW in a double and a long long.  */
1244
1245 void
1246 mv_compute_host_endianness (ARMul_State * state)
1247 {
1248   static union
1249   {
1250     long long ll;
1251     long ints[2];
1252     long i;
1253     double d;
1254     float floats[2];
1255     float f;
1256   } conv;
1257
1258   /* Calculate where's the LSW in a 64bit int.  */
1259   conv.ll = 45;
1260   
1261   if (conv.ints[0] == 0)
1262     {
1263       msw_int_index = 0;
1264       lsw_int_index = 1;
1265     }
1266   else
1267     {
1268       assert (conv.ints[1] == 0);
1269       msw_int_index = 1;
1270       lsw_int_index = 0;
1271     }
1272
1273   /* Calculate where's the LSW in a double.  */
1274   conv.d = 3.0;
1275   
1276   if (conv.ints[0] == 0)
1277     {
1278       msw_float_index = 0;
1279       lsw_float_index = 1;
1280     }
1281   else
1282     {
1283       assert (conv.ints[1] == 0);
1284       msw_float_index = 1;
1285       lsw_float_index = 0;
1286     }
1287
1288   printfdbg ("lsw_int_index   %d\n", lsw_int_index);
1289   printfdbg ("lsw_float_index %d\n", lsw_float_index);
1290 }