xref: /netbsd-src/external/gpl3/gdb/dist/sim/arm/maverick.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*  maverick.c -- Cirrus/DSP co-processor interface.
2     Copyright (C) 2003-2017 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 }
1233