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