1/*  maverick.c -- Cirrus/DSP co-processor interface.
2    Copyright (C) 2003-2023 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.  */
41struct maverick_regs DSPregs[16];
42union maverick_acc_regs DSPacc[4];
43ARMword DSPsc;
44
45#define DEST_REG	(BITS (12, 15))
46#define SRC1_REG	(BITS (16, 19))
47#define SRC2_REG	(BITS (0, 3))
48
49static int lsw_int_index, msw_int_index;
50static int lsw_float_index, msw_float_index;
51
52static double mv_getRegDouble (int);
53static long long mv_getReg64int (int);
54static void mv_setRegDouble (int, double val);
55static void mv_setReg64int (int, long long val);
56
57static union
58{
59  double d;
60  long long ll;
61  int ints[2];
62} reg_conv;
63
64static void
65printf_nothing (void * foo, ...)
66{
67}
68
69static void
70cirrus_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
78unsigned
79DSPMRC4 (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
199unsigned
200DSPMRC5 (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
293unsigned
294DSPMRC6 (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
334unsigned
335DSPMCR4 (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
371unsigned
372DSPMCR5 (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
428unsigned
429DSPMCR6 (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
469unsigned
470DSPLDC4 (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
533unsigned
534DSPLDC5 (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
595unsigned
596DSPSTC4 (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
655unsigned
656DSPSTC5 (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
714unsigned
715DSPCDP4 (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
918unsigned
919DSPCDP5 (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
1138unsigned
1139DSPCDP6 (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
1180static double
1181mv_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
1188static void
1189mv_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
1196static long long
1197mv_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
1204static void
1205mv_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