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.  */
38struct maverick_regs DSPregs[16];
39union maverick_acc_regs DSPacc[4];
40ARMword DSPsc;
41
42#define DEST_REG	(BITS (12, 15))
43#define SRC1_REG	(BITS (16, 19))
44#define SRC2_REG	(BITS (0, 3))
45
46static int lsw_int_index, msw_int_index;
47static int lsw_float_index, msw_float_index;
48
49static double mv_getRegDouble (int);
50static long long mv_getReg64int (int);
51static void mv_setRegDouble (int, double val);
52static void mv_setReg64int (int, long long val);
53
54static union
55{
56  double d;
57  long long ll;
58  int ints[2];
59} reg_conv;
60
61static void
62printf_nothing (void * foo, ...)
63{
64}
65
66static void
67cirrus_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
75unsigned
76DSPMRC4 (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
196unsigned
197DSPMRC5 (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
290unsigned
291DSPMRC6 (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
331unsigned
332DSPMCR4 (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
368unsigned
369DSPMCR5 (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
425unsigned
426DSPMCR6 (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
466unsigned
467DSPLDC4 (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
530unsigned
531DSPLDC5 (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
592unsigned
593DSPSTC4 (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
652unsigned
653DSPSTC5 (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
711unsigned
712DSPCDP4 (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
915unsigned
916DSPCDP5 (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
1135unsigned
1136DSPCDP6 (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
1177static double
1178mv_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
1185static void
1186mv_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
1193static long long
1194mv_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
1201static void
1202mv_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