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