xref: /netbsd-src/external/gpl3/gdb/dist/sim/arm/maverick.c (revision 4d1eaf9104083d3c1d72a17f5c414777b18c6935)
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
65 printf_nothing (void * foo, ...)
66 {
67 }
68 
69 static void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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