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