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