Add Cirrus Maverick support to arm simulator
authorNick Clifton <nickc@redhat.com>
Thu, 20 Mar 2003 12:25:07 +0000 (12:25 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 20 Mar 2003 12:25:07 +0000 (12:25 +0000)
12 files changed:
include/gdb/ChangeLog
include/gdb/sim-arm.h
sim/arm/ChangeLog
sim/arm/Makefile.in
sim/arm/armcopro.c
sim/arm/armdefs.h
sim/arm/armemu.h
sim/arm/arminit.c
sim/arm/configure
sim/arm/configure.in
sim/arm/maverick.c [new file with mode: 0644]
sim/arm/wrapper.c

index f60f7b169f7fbeb0d96504431d61999b3504ca58..97c2f443c38f2f1dacea8794107532de26ee149d 100644 (file)
@@ -1,3 +1,8 @@
+2003-03-20  Nick Clifton  <nickc@redhat.com>
+
+       * sim-arm.h (sim_arm_regs): Add Maverick co-processor
+       registers.
+
 2003-02-27  Andrew Cagney  <cagney@redhat.com>
 
        * remote-sim.h (sim_open, sim_load, sim_create_inferior): Rename
index 6d80700ad7e58e19e0a1d6e2e33412c02a63d6f4..fae11f0b16bbcac082cc2eb65a9770fbae5f4a1f 100644 (file)
@@ -1,6 +1,6 @@
 /* This file defines the interface between the Arm simulator and GDB.
 
-   Copyright 2002 Free Software Foundation, Inc.
+   Copyright 2002, 2003 Free Software Foundation, Inc.
 
    Contributed by Red Hat.
 
@@ -55,7 +55,24 @@ enum sim_arm_regs
   SIM_ARM_FP6_REGNUM,
   SIM_ARM_FP7_REGNUM,
   SIM_ARM_FPS_REGNUM,
-  SIM_ARM_PS_REGNUM
+  SIM_ARM_PS_REGNUM,
+  SIM_ARM_MAVERIC_COP0R0_REGNUM,
+  SIM_ARM_MAVERIC_COP0R1_REGNUM,
+  SIM_ARM_MAVERIC_COP0R2_REGNUM,
+  SIM_ARM_MAVERIC_COP0R3_REGNUM,
+  SIM_ARM_MAVERIC_COP0R4_REGNUM,
+  SIM_ARM_MAVERIC_COP0R5_REGNUM,
+  SIM_ARM_MAVERIC_COP0R6_REGNUM,
+  SIM_ARM_MAVERIC_COP0R7_REGNUM,
+  SIM_ARM_MAVERIC_COP0R8_REGNUM,
+  SIM_ARM_MAVERIC_COP0R9_REGNUM,
+  SIM_ARM_MAVERIC_COP0R10_REGNUM,
+  SIM_ARM_MAVERIC_COP0R11_REGNUM,
+  SIM_ARM_MAVERIC_COP0R12_REGNUM,
+  SIM_ARM_MAVERIC_COP0R13_REGNUM,
+  SIM_ARM_MAVERIC_COP0R14_REGNUM,
+  SIM_ARM_MAVERIC_COP0R15_REGNUM,
+  SIM_ARM_MAVERIC_DSPSC_REGNUM
 };
 
 #ifdef __cplusplus
index 5e4b316ca863d5cf858030dbecbbc74410d841f5..8ae1f70436e46b2da8667e681108e7f41b452c32 100644 (file)
@@ -1,3 +1,27 @@
+2003-02-10  Nick Clifton  <nickc@redhat.com>
+
+       * Contribute support for Cirrus Maverick ARM co-processor,
+        written by Aldy Hernandez  <aldyh@redhat.com> and
+        Andrew Cagney  <cagney@redhat.com>:
+
+       * maverick.c: New file: Support for Maverick floating point
+       co-processor. 
+        * Makefile.in: Add maverick.o target.
+        * configure.in (COPRO): Add maverick.o.
+        * configure: Regenerate.
+        * armcopro.c (ARMul_CoProInit): Only initialise co-processors
+       available on target processor.  Add code to initialse Maverick
+       co-processor support code.
+        * armdefs.h (ARMul_state): Add is_ep9312 field.
+        (ARM_ep9312_Prop): Define.
+        * armemu.h: Add prototypes for Maverick co-processor
+       functions.
+        * arminit.c (ARMul_SelectProcessor): Initialise the
+       co-processor support once the chip has been selected.
+        * wrapper.c: Add support for Maverick co-processor.
+        (init): Do not call ARMul_CoProInit.  Delays this until the
+       chip has been selected.
+
 2003-03-02  Nick Clifton  <nickc@redhat.com>
 
        * armos.c (SWIWrite0): Catch big-endian bug when printing
index 0da765fd7035ca1835d1ebc248aae16f964f0a48..017a983289d3c60d91077949c1641c54445d6341 100644 (file)
@@ -31,6 +31,7 @@ SIM_OBJS = armemu26.o armemu32.o arminit.o armos.o armsupp.o \
 armos.o: armos.c armdefs.h armos.h armfpe.h
 
 armcopro.o: armcopro.c armdefs.h
+maverick.o: maverick.c armdefs.h
 
 armemu26.o: armemu.c armdefs.h armemu.h 
        $(CC) -c $(srcdir)/armemu.c -o armemu26.o $(ALL_CFLAGS)
index 2c2ca8505a6c4c9c77dd7a45d8765f9792a6ec20..b97478948696c5b86f8b33484a2e5248f9f7c15a 100644 (file)
@@ -1322,34 +1322,48 @@ ARMul_CoProInit (ARMul_State * state)
 
   /* Install CoPro Instruction handlers here.
      The format is:
-     ARMul_CoProAttach (state, CP Number,
-                        Init routine, Exit routine
-                        LDC routine, STC routine,
-                       MRC routine, MCR routine,
-                        CDP routine,
-                       Read Reg routine, Write Reg routine).  */
-  ARMul_CoProAttach (state, 4, NULL, NULL,
-                    ValLDC, ValSTC, ValMRC, ValMCR, ValCDP, NULL, NULL);
-
-  ARMul_CoProAttach (state, 5, NULL, NULL,
-                    NULL, NULL, ValMRC, ValMCR, IntCDP, NULL, NULL);
-
-  ARMul_CoProAttach (state, 15, MMUInit, NULL,
-                    NULL, NULL, MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
-
-  ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL,
-                    XScale_cp13_LDC, XScale_cp13_STC, XScale_cp13_MRC,
-                    XScale_cp13_MCR, NULL, XScale_cp13_read_reg,
-                    XScale_cp13_write_reg);
-
-  ARMul_CoProAttach (state, 14, XScale_cp14_init, NULL,
-                    XScale_cp14_LDC, XScale_cp14_STC, XScale_cp14_MRC,
-                    XScale_cp14_MCR, NULL, XScale_cp14_read_reg,
-                    XScale_cp14_write_reg);
-
-  ARMul_CoProAttach (state, 15, XScale_cp15_init, NULL,
-                    NULL, NULL, XScale_cp15_MRC, XScale_cp15_MCR,
-                    NULL, XScale_cp15_read_reg, XScale_cp15_write_reg);
+     ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
+                        LDC routine, STC routine, MRC routine, MCR routine,
+                        CDP routine, Read Reg routine, Write Reg routine).  */
+  if (state->is_ep9312)
+    {
+      ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4,
+                        DSPMRC4, DSPMCR4, DSPCDP4, NULL, NULL);
+      ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5,
+                        DSPMRC5, DSPMCR5, DSPCDP5, NULL, NULL);
+      ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL,
+                        DSPMRC6, DSPMCR6, DSPCDP6, NULL, NULL);
+    }
+  else
+    {
+      ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC,
+                        ValMRC, ValMCR, ValCDP, NULL, NULL);
+
+      ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL,
+                        ValMRC, ValMCR, IntCDP, NULL, NULL);
+    }
+
+  if (state->is_XScale)
+    {
+      ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL,
+                        XScale_cp13_LDC, XScale_cp13_STC, XScale_cp13_MRC,
+                        XScale_cp13_MCR, NULL, XScale_cp13_read_reg,
+                        XScale_cp13_write_reg);
+
+      ARMul_CoProAttach (state, 14, XScale_cp14_init, NULL,
+                        XScale_cp14_LDC, XScale_cp14_STC, XScale_cp14_MRC,
+                        XScale_cp14_MCR, NULL, XScale_cp14_read_reg,
+                        XScale_cp14_write_reg);
+
+      ARMul_CoProAttach (state, 15, XScale_cp15_init, NULL,
+                        NULL, NULL, XScale_cp15_MRC, XScale_cp15_MCR,
+                        NULL, XScale_cp15_read_reg, XScale_cp15_write_reg);
+    }
+  else
+    {
+      ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
+                        MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
+    }
 
   /* No handlers below here.  */
 
index fde312516338164f16c4277e0d3475939362bc29..0f252226dd9aca159114d4c06a7288545808603a 100644 (file)
@@ -135,6 +135,7 @@ struct ARMul_State
   unsigned is_v5;              /* Are we emulating a v5 architecture ?  */
   unsigned is_v5e;             /* Are we emulating a v5e architecture ?  */
   unsigned is_XScale;          /* Are we emulating an XScale architecture ?  */
+  unsigned is_ep9312;          /* Are we emulating a Cirrus Maverick co-processor ?  */
   unsigned verbose;            /* Print various messages like the banner */
 };
 
@@ -162,6 +163,7 @@ struct ARMul_State
 #define ARM_v5_Prop      0x80
 #define ARM_v5e_Prop     0x100
 #define ARM_XScale_Prop  0x200
+#define ARM_ep9312_Prop  0x400
 
 /***************************************************************************\
 *                   Macros to extract instruction fields                    *
index 385924bd68984fe3508ddb5de9ccbc9ede76f921..dfaafb03bbcc62ca5d21899cb28dadbc5a57bd77 100644 (file)
@@ -530,3 +530,16 @@ extern void     ARMul_CoProAttach   (ARMul_State *, unsigned, ARMul_CPInits *, A
 extern void     ARMul_CoProDetach   (ARMul_State *, unsigned);
 extern ARMword  read_cp15_reg       (unsigned, unsigned, unsigned);
 
+extern unsigned DSPLDC4 (ARMul_State *, unsigned, ARMword, ARMword);
+extern unsigned DSPMCR4 (ARMul_State *, unsigned, ARMword, ARMword);
+extern unsigned DSPMRC4 (ARMul_State *, unsigned, ARMword, ARMword *);
+extern unsigned        DSPSTC4 (ARMul_State *, unsigned, ARMword, ARMword *);
+extern unsigned        DSPCDP4 (ARMul_State *, unsigned, ARMword);
+extern unsigned DSPMCR5 (ARMul_State *, unsigned, ARMword, ARMword);
+extern unsigned DSPMRC5 (ARMul_State *, unsigned, ARMword, ARMword *);
+extern unsigned DSPLDC5 (ARMul_State *, unsigned, ARMword, ARMword);
+extern unsigned        DSPSTC5 (ARMul_State *, unsigned, ARMword, ARMword *);
+extern unsigned        DSPCDP5 (ARMul_State *, unsigned, ARMword);
+extern unsigned DSPMCR6 (ARMul_State *, unsigned, ARMword, ARMword);
+extern unsigned DSPMRC6 (ARMul_State *, unsigned, ARMword, ARMword *);
+extern unsigned        DSPCDP6 (ARMul_State *, unsigned, ARMword);
index c0312e95239d79ec82e174a1986b0d34ceebda6a..04399900c959047fe01963d108579c4a0e5debb4 100644 (file)
@@ -157,6 +157,11 @@ ARMul_SelectProcessor (ARMul_State * state, unsigned properties)
   state->is_v5 = (properties & ARM_v5_Prop) ? HIGH : LOW;
   state->is_v5e = (properties & ARM_v5e_Prop) ? HIGH : LOW;
   state->is_XScale = (properties & ARM_XScale_Prop) ? HIGH : LOW;
+  state->is_ep9312 = (properties & ARM_ep9312_Prop) ? HIGH : LOW;
+
+  /* Only initialse the coprocessor support once we
+     know what kind of chip we are dealing with.  */
+  ARMul_CoProInit (state);
 }
 
 /***************************************************************************\
index 65f0825ff8c34297a5f9be93cdc7b83898d652b9..26fd5f5d6d1bc682e0a0e57af0f502d4950ee5cf 100755 (executable)
@@ -3534,7 +3534,8 @@ fi
 done
 
 
-COPRO=armcopro.o
+COPRO="armcopro.o maverick.o"
+
 
 
 
index cbfac44e4cd0287da1119eb9333054831e3d676b..73fa0a0a6439eed0bb19b63d4f7a251bcff4d641 100644 (file)
@@ -7,7 +7,8 @@ SIM_AC_COMMON
 
 AC_CHECK_HEADERS(unistd.h)
 
-COPRO=armcopro.o
+COPRO="armcopro.o maverick.o"
+
 AC_SUBST(COPRO)
 
 SIM_AC_OUTPUT
diff --git a/sim/arm/maverick.c b/sim/arm/maverick.c
new file mode 100644 (file)
index 0000000..82871f9
--- /dev/null
@@ -0,0 +1,1291 @@
+/*  maverick.c -- Cirrus/DSP co-processor interface.
+    Copyright (C) 2003 Free Software Foundation, Inc.
+    Contributed by Aldy Hernandez (aldyh@redhat.com).
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include "armdefs.h"
+#include "ansidecl.h"
+#include "armemu.h"
+
+/*#define CIRRUS_DEBUG 1       /**/
+#if CIRRUS_DEBUG
+#  define printfdbg printf
+#else
+#  define printfdbg printf_nothing
+#endif
+
+#define POS64(i) ( (~(i)) >> 63 )
+#define NEG64(i) ( (i) >> 63 )
+
+/* Define Co-Processor instruction handlers here.  */
+
+/* Here's ARMulator's DSP definition.  A few things to note:
+   1) it has 16 64-bit registers and 4 72-bit accumulators
+   2) you can only access its registers with MCR and MRC.  */
+
+/* We can't define these in here because this file might not be linked
+   unless the target is arm9e-*.  They are defined in wrapper.c.
+   Eventually the simulator should be made to handle any coprocessor
+   at run time.  */
+struct maverick_regs
+{
+  union
+  {
+    int i;
+    float f;
+  } upper;
+  
+  union
+  {
+    int i;
+    float f;
+  } lower;
+};
+
+union maverick_acc_regs
+{
+  long double ld;              /* Acc registers are 72-bits.  */
+};
+
+struct maverick_regs DSPregs[16];
+union maverick_acc_regs DSPacc[4];
+ARMword DSPsc;
+
+#define DEST_REG       (BITS (12, 15))
+#define SRC1_REG       (BITS (16, 19))
+#define SRC2_REG       (BITS (0, 3))
+
+static int lsw_int_index, msw_int_index;
+static int lsw_float_index, msw_float_index;
+
+static double mv_getRegDouble (int);
+static long long mv_getReg64int (int);
+static void mv_setRegDouble (int, double val);
+static void mv_setReg64int (int, long long val);
+
+static union
+{
+  double d;
+  long long ll;
+  int ints[2];
+} reg_conv;
+
+static void
+printf_nothing (void * foo, ...)
+{
+}
+
+static void
+cirrus_not_implemented (char * insn)
+{
+  fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn);
+  fprintf (stderr, "aborting!\n");
+  
+  exit (1);
+}
+
+static unsigned
+DSPInit (ARMul_State * state)
+{
+  ARMul_ConsolePrint (state, ", DSP present");
+  return TRUE;
+}
+
+unsigned
+DSPMRC4 (ARMul_State * state ATTRIBUTE_UNUSED,
+        unsigned      type  ATTRIBUTE_UNUSED,
+        ARMword       instr,
+        ARMword *     value)
+{
+  switch (BITS (5, 7))
+    {
+    case 0: /* cfmvrdl */
+      /* Move lower half of a DF stored in a DSP reg into an Arm reg.  */
+      printfdbg ("cfmvrdl\n");
+      printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i);
+      printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
+      
+      *value = (ARMword) DSPregs[SRC1_REG].lower.i;
+      break;
+      
+    case 1: /* cfmvrdh */
+      /* Move upper half of a DF stored in a DSP reg into an Arm reg.  */
+      printfdbg ("cfmvrdh\n");
+      printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i);
+      printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
+      
+      *value = (ARMword) DSPregs[SRC1_REG].upper.i;
+      break;
+      
+    case 2: /* cfmvrs */
+      /* Move SF from upper half of a DSP register to an Arm register.  */
+      *value = (ARMword) DSPregs[SRC1_REG].upper.i;
+      printfdbg ("cfmvrs = mvf%d <-- %f\n",
+                SRC1_REG,
+                DSPregs[SRC1_REG].upper.f);
+      break;
+      
+#ifdef doesnt_work
+    case 4: /* cfcmps */
+      {
+       float a, b;
+       int n, z, c, v;
+
+       a = DSPregs[SRC1_REG].upper.f;
+       b = DSPregs[SRC2_REG].upper.f;
+
+       printfdbg ("cfcmps\n");
+       printfdbg ("\tcomparing %f and %f\n", a, b);
+
+       z = a == b;             /* zero */
+       n = a != b;             /* negative */
+       v = a > b;              /* overflow */
+       c = 0;                  /* carry */
+       *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
+       break;
+      }
+      
+    case 5: /* cfcmpd */
+      {
+       double a, b;
+       int n, z, c, v;
+
+       a = mv_getRegDouble (SRC1_REG);
+       b = mv_getRegDouble (SRC2_REG);
+
+       printfdbg ("cfcmpd\n");
+       printfdbg ("\tcomparing %g and %g\n", a, b);
+
+       z = a == b;             /* zero */
+       n = a != b;             /* negative */
+       v = a > b;              /* overflow */
+       c = 0;                  /* carry */
+       *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
+       break;
+      }
+#else
+      case 4: /* cfcmps */
+        {
+         float a, b;
+         int n, z, c, v;
+
+         a = DSPregs[SRC1_REG].upper.f;
+         b = DSPregs[SRC2_REG].upper.f;
+  
+         printfdbg ("cfcmps\n");
+         printfdbg ("\tcomparing %f and %f\n", a, b);
+
+         z = a == b;           /* zero */
+         n = a < b;            /* negative */
+         c = a > b;            /* carry */
+         v = 0;                /* fixme */
+         printfdbg ("\tz = %d, n = %d\n", z, n);
+         *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
+         break;
+        }
+       
+      case 5: /* cfcmpd */
+        {
+         double a, b;
+         int n, z, c, v;
+
+         a = mv_getRegDouble (SRC1_REG);
+         b = mv_getRegDouble (SRC2_REG);
+  
+         printfdbg ("cfcmpd\n");
+         printfdbg ("\tcomparing %g and %g\n", a, b);
+  
+         z = a == b;           /* zero */
+         n = a < b;            /* negative */
+         c = a > b;            /* carry */
+         v = 0;                /* fixme */
+         *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
+         break;
+        }
+#endif
+    default:
+      fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr);
+      cirrus_not_implemented ("unknown");
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPMRC5 (ARMul_State * state ATTRIBUTE_UNUSED,
+        unsigned      type  ATTRIBUTE_UNUSED,
+        ARMword       instr,
+        ARMword *     value)
+{
+  switch (BITS (5, 7))
+    {
+    case 0: /* cfmvr64l */
+      /* Move lower half of 64bit int from Cirrus to Arm.  */
+      *value = (ARMword) DSPregs[SRC1_REG].lower.i;
+      printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n",
+                DEST_REG,
+                (int) *value);
+      break;
+      
+    case 1: /* cfmvr64h */
+      /* Move upper half of 64bit int from Cirrus to Arm.  */
+      *value = (ARMword) DSPregs[SRC1_REG].upper.i;
+      printfdbg ("cfmvr64h <-- %d\n", (int) *value);
+      break;
+      
+    case 4: /* cfcmp32 */
+      {
+       int res;
+       int n, z, c, v;
+       unsigned int a, b;
+
+       printfdbg ("cfcmp32 mvfx%d - mvfx%d\n",
+                  SRC1_REG,
+                  SRC2_REG);
+
+       /* FIXME: see comment for cfcmps.  */
+       a = DSPregs[SRC1_REG].lower.i;
+       b = DSPregs[SRC2_REG].lower.i;
+
+       res = DSPregs[SRC1_REG].lower.i - DSPregs[SRC2_REG].lower.i;
+       /* zero */
+       z = res == 0;
+       /* negative */
+       n = res < 0;
+       /* overflow */
+       v = SubOverflow (DSPregs[SRC1_REG].lower.i, DSPregs[SRC2_REG].lower.i,
+                        res);
+       /* carry */
+       c = (NEG (a) && POS (b) ||
+            (NEG (a) && POS (res)) || (POS (b) && POS (res)));
+
+       *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
+       break;
+      }
+      
+    case 5: /* cfcmp64 */
+      {
+       long long res;
+       int n, z, c, v;
+       unsigned long long a, b;
+
+       printfdbg ("cfcmp64 mvdx%d - mvdx%d\n",
+                  SRC1_REG,
+                  SRC2_REG);
+
+       /* fixme: see comment for cfcmps.  */
+
+       a = mv_getReg64int (SRC1_REG);
+       b = mv_getReg64int (SRC2_REG);
+
+       res = mv_getReg64int (SRC1_REG) - mv_getReg64int (SRC2_REG);
+       /* zero */
+       z = res == 0;
+       /* negative */
+       n = res < 0;
+       /* overflow */
+       v = ((NEG64 (a) && POS64 (b) && POS64 (res))
+            || (POS64 (a) && NEG64 (b) && NEG64 (res)));
+       /* carry */
+       c = (NEG64 (a) && POS64 (b) ||
+            (NEG64 (a) && POS64 (res)) || (POS64 (b) && POS64 (res)));
+
+       *value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
+       break;
+      }
+      
+    default:
+      fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr);
+      cirrus_not_implemented ("unknown");
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPMRC6 (ARMul_State * state ATTRIBUTE_UNUSED,
+        unsigned      type  ATTRIBUTE_UNUSED,
+        ARMword       instr,
+        ARMword *     value)
+{
+  switch (BITS (5, 7))
+    {
+    case 0: /* cfmval32 */
+      cirrus_not_implemented ("cfmval32");
+      break;
+      
+    case 1: /* cfmvam32 */
+      cirrus_not_implemented ("cfmvam32");
+      break;
+      
+    case 2: /* cfmvah32 */
+      cirrus_not_implemented ("cfmvah32");
+      break;
+      
+    case 3: /* cfmva32 */
+      cirrus_not_implemented ("cfmva32");
+      break;
+      
+    case 4: /* cfmva64 */
+      cirrus_not_implemented ("cfmva64");
+      break;
+      
+    case 5: /* cfmvsc32 */
+      cirrus_not_implemented ("cfmvsc32");
+      break;
+      
+    default:
+      fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr);
+      cirrus_not_implemented ("unknown");
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPMCR4 (ARMul_State * state,
+        unsigned      type ATTRIBUTE_UNUSED,
+        ARMword       instr,
+        ARMword       value)
+{
+  switch (BITS (5, 7))
+    {
+    case 0: /* cfmvdlr */
+      /* Move the lower half of a DF value from an Arm register into
+        the lower half of a Cirrus register.  */
+      printfdbg ("cfmvdlr <-- 0x%x\n", (int) value);
+      DSPregs[SRC1_REG].lower.i = (int) value;
+      break;
+      
+    case 1: /* cfmvdhr */
+      /* Move the upper half of a DF value from an Arm register into
+        the upper half of a Cirrus register.  */
+      printfdbg ("cfmvdhr <-- 0x%x\n", (int) value);
+      DSPregs[SRC1_REG].upper.i = (int) value;
+      break;
+      
+    case 2: /* cfmvsr */
+      /* Move SF from Arm register into upper half of Cirrus register.  */
+      printfdbg ("cfmvsr <-- 0x%x\n", (int) value);
+      DSPregs[SRC1_REG].upper.i = (int) value;
+      break;
+      
+    default:
+      fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr);
+      cirrus_not_implemented ("unknown");
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPMCR5 (ARMul_State * state,
+        unsigned      type   ATTRIBUTE_UNUSED,
+        ARMword       instr,
+        ARMword       value)
+{
+  union
+  {
+    int s;
+    unsigned int us;
+  } val;
+
+  switch (BITS (5, 7))
+    {
+    case 0: /* cfmv64lr */
+      /* Move lower half of a 64bit int from an ARM register into the
+         lower half of a DSP register and sign extend it.  */
+      printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, (int) value);
+      DSPregs[SRC1_REG].lower.i = (int) value;
+      break;
+      
+    case 1: /* cfmv64hr */
+      /* Move upper half of a 64bit int from an ARM register into the
+        upper half of a DSP register.  */
+      printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n",
+                SRC1_REG,
+                (int) value);
+      DSPregs[SRC1_REG].upper.i = (int) value;
+      break;
+      
+    case 2: /* cfrshl32 */
+      printfdbg ("cfrshl32\n");
+      val.us = value;
+      if (val.s > 0)
+       DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i << value;
+      else
+       DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -value;
+      break;
+      
+    case 3: /* cfrshl64 */
+      printfdbg ("cfrshl64\n");
+      val.us = value;
+      if (val.s > 0)
+       mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) << value);
+      else
+       mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) >> -value);
+      break;
+      
+    default:
+      fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr);
+      cirrus_not_implemented ("unknown");
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPMCR6 (ARMul_State * state,
+        unsigned      type   ATTRIBUTE_UNUSED,
+        ARMword       instr,
+        ARMword       value)
+{
+  switch (BITS (5, 7))
+    {
+    case 0: /* cfmv32al */
+      cirrus_not_implemented ("cfmv32al");
+      break;
+      
+    case 1: /* cfmv32am */
+      cirrus_not_implemented ("cfmv32am");
+      break;
+      
+    case 2: /* cfmv32ah */
+      cirrus_not_implemented ("cfmv32ah");
+      break;
+      
+    case 3: /* cfmv32a */
+      cirrus_not_implemented ("cfmv32a");
+      break;
+      
+    case 4: /* cfmv64a */
+      cirrus_not_implemented ("cfmv64a");
+      break;
+      
+    case 5: /* cfmv32sc */
+      cirrus_not_implemented ("cfmv32sc");
+      break;
+      
+    default:
+      fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr);
+      cirrus_not_implemented ("unknown");
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPLDC4 (ARMul_State * state ATTRIBUTE_UNUSED,
+        unsigned      type,
+        ARMword       instr,
+        ARMword       data)
+{
+  static unsigned words;
+
+  if (type != ARMul_DATA)
+    {
+      words = 0;
+      return ARMul_DONE;
+    }
+  
+  if (BIT (22))
+    {                          /* it's a long access, get two words */
+      /* cfldrd */
+
+      printfdbg ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n",
+                data, words, state->bigendSig, DEST_REG);
+      
+      if (words == 0)
+       {
+         if (state->bigendSig)
+           DSPregs[DEST_REG].upper.i = (int) data;
+         else
+           DSPregs[DEST_REG].lower.i = (int) data;
+       }
+      else
+       {
+         if (state->bigendSig)
+           DSPregs[DEST_REG].lower.i = (int) data;
+         else
+           DSPregs[DEST_REG].upper.i = (int) data;
+       }
+      
+      ++ words;
+      
+      if (words == 2)
+       {
+         printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG,
+                    mv_getRegDouble (DEST_REG));
+         
+         return ARMul_DONE;
+       }
+      else
+       return ARMul_INC;
+    }
+  else
+    {
+      /* Get just one word.  */
+      
+      /* cfldrs */
+      printfdbg ("cfldrs\n");
+
+      DSPregs[DEST_REG].upper.i = (int) data;
+
+      printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG,
+                DSPregs[DEST_REG].upper.f);
+
+      return ARMul_DONE;
+    }
+}
+
+unsigned
+DSPLDC5 (ARMul_State * state ATTRIBUTE_UNUSED,
+        unsigned      type,
+        ARMword       instr,
+        ARMword       data)
+{
+  static unsigned words;
+
+  if (type != ARMul_DATA)
+    {
+      words = 0;
+      return ARMul_DONE;
+    }
+  
+  if (BIT (22))
+    {
+      /* It's a long access, get two words.  */
+      
+      /* cfldr64 */
+      printfdbg ("cfldr64: %d\n", data);
+
+      if (words == 0)
+       {
+         if (state->bigendSig)
+           DSPregs[DEST_REG].upper.i = (int) data;
+         else
+           DSPregs[DEST_REG].lower.i = (int) data;
+       }
+      else
+       {
+         if (state->bigendSig)
+           DSPregs[DEST_REG].lower.i = (int) data;
+         else
+           DSPregs[DEST_REG].upper.i = (int) data;
+       }
+      
+      ++ words;
+      
+      if (words == 2)
+       {
+         printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG,
+                    mv_getReg64int (DEST_REG));
+         
+         return ARMul_DONE;
+       }
+      else
+       return ARMul_INC;
+    }
+  else
+    {
+      /* Get just one word.  */
+      
+      /* cfldr32 */
+      printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data);
+      
+      /* 32bit ints should be sign extended to 64bits when loaded.  */
+      mv_setReg64int (DEST_REG, (long long) data);
+
+      return ARMul_DONE;
+    }
+}
+
+unsigned
+DSPSTC4 (ARMul_State * state ATTRIBUTE_UNUSED,
+        unsigned      type,
+        ARMword       instr,
+        ARMword *     data)
+{
+  static unsigned words;
+
+  if (type != ARMul_DATA)
+    {
+      words = 0;
+      return ARMul_DONE;
+    }
+  
+  if (BIT (22))
+    {
+      /* It's a long access, get two words.  */
+      /* cfstrd */
+      printfdbg ("cfstrd\n");
+
+      if (words == 0)
+       {
+         if (state->bigendSig)
+           *data = (ARMword) DSPregs[DEST_REG].upper.i;
+         else
+           *data = (ARMword) DSPregs[DEST_REG].lower.i;
+       }
+      else
+       {
+         if (state->bigendSig)
+           *data = (ARMword) DSPregs[DEST_REG].lower.i;
+         else
+           *data = (ARMword) DSPregs[DEST_REG].upper.i;
+       }
+      
+      ++ words;
+      
+      if (words == 2)
+       {
+         printfdbg ("\tmem = mvd%d = %g\n", DEST_REG,
+                    mv_getRegDouble (DEST_REG));
+         
+         return ARMul_DONE;
+       }
+      else
+       return ARMul_INC;
+    }
+  else
+    {
+      /* Get just one word.  */
+      /* cfstrs */
+      printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG,
+                DSPregs[DEST_REG].upper.f);
+
+      *data = (ARMword) DSPregs[DEST_REG].upper.i;
+
+      return ARMul_DONE;
+    }
+}
+
+unsigned
+DSPSTC5 (ARMul_State * state ATTRIBUTE_UNUSED,
+        unsigned      type,
+        ARMword       instr,
+        ARMword *     data)
+{
+  static unsigned words;
+
+  if (type != ARMul_DATA)
+    {
+      words = 0;
+      return ARMul_DONE;
+    }
+  
+  if (BIT (22))
+    {
+      /* It's a long access, store two words.  */
+      /* cfstr64 */
+      printfdbg ("cfstr64\n");
+
+      if (words == 0)
+       {
+         if (state->bigendSig)
+           *data = (ARMword) DSPregs[DEST_REG].upper.i;
+         else
+           *data = (ARMword) DSPregs[DEST_REG].lower.i;
+       }
+      else
+       {
+         if (state->bigendSig)
+           *data = (ARMword) DSPregs[DEST_REG].lower.i;
+         else
+           *data = (ARMword) DSPregs[DEST_REG].upper.i;
+       }
+      
+      ++ words;
+      
+      if (words == 2)
+       {
+         printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG,
+                    mv_getReg64int (DEST_REG));
+         
+         return ARMul_DONE;
+       }
+      else
+       return ARMul_INC;
+    }
+  else
+    {
+      /* Store just one word.  */
+      /* cfstr32 */
+      *data = (ARMword) DSPregs[DEST_REG].lower.i;
+      
+      printfdbg ("cfstr32 MEM = %d\n", (int) *data);
+
+      return ARMul_DONE;
+    }
+}
+
+unsigned
+DSPCDP4 (ARMul_State * state,
+        unsigned      type,
+        ARMword       instr)
+{
+  int opcode2;
+
+  opcode2 = BITS (5,7);
+
+  switch (BITS (20,21))
+    {
+    case 0:
+      switch (opcode2)
+       {
+       case 0: /* cfcpys */
+         printfdbg ("cfcpys mvf%d = mvf%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    DSPregs[SRC1_REG].upper.f);
+         DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f;
+         break;
+         
+       case 1: /* cfcpyd */
+         printfdbg ("cfcpyd mvd%d = mvd%d = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    mv_getRegDouble (SRC1_REG));
+         mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG));
+         break;
+         
+       case 2: /* cfcvtds */
+         printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    (float) mv_getRegDouble (SRC1_REG));
+         DSPregs[DEST_REG].upper.f = (float) mv_getRegDouble (SRC1_REG);
+         break;
+         
+       case 3: /* cfcvtsd */
+         printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    (double) DSPregs[SRC1_REG].upper.f);
+         mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].upper.f);
+         break;
+         
+       case 4: /* cfcvt32s */
+         printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    (float) DSPregs[SRC1_REG].lower.i);
+         DSPregs[DEST_REG].upper.f = (float) DSPregs[SRC1_REG].lower.i;
+         break;
+         
+       case 5: /* cfcvt32d */
+         printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    (double) DSPregs[SRC1_REG].lower.i);
+         mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].lower.i);
+         break;
+         
+       case 6: /* cfcvt64s */
+         printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    (float) mv_getReg64int (SRC1_REG));
+         DSPregs[DEST_REG].upper.f = (float) mv_getReg64int (SRC1_REG);
+         break;
+         
+       case 7: /* cfcvt64d */
+         printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    (double) mv_getReg64int (SRC1_REG));
+         mv_setRegDouble (DEST_REG, (double) mv_getReg64int (SRC1_REG));
+         break;
+       }
+      break;
+
+    case 1:
+      switch (opcode2)
+       {
+       case 0: /* cfmuls */
+         printfdbg ("cfmuls mvf%d = mvf%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    DSPregs[SRC1_REG].upper.f * DSPregs[SRC2_REG].upper.f);
+                    
+         DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
+           * DSPregs[SRC2_REG].upper.f;
+         break;
+         
+       case 1: /* cfmuld */
+         printfdbg ("cfmuld mvd%d = mvd%d = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    mv_getRegDouble (SRC1_REG) * mv_getRegDouble (SRC2_REG));
+
+         mv_setRegDouble (DEST_REG,
+                          mv_getRegDouble (SRC1_REG)
+                          * mv_getRegDouble (SRC2_REG));
+         break;
+         
+       default:
+         fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
+         cirrus_not_implemented ("unknown");
+         break;
+       }
+      break;
+
+    case 3:
+      switch (opcode2)
+       {
+       case 0: /* cfabss */
+         DSPregs[DEST_REG].upper.f = (DSPregs[SRC1_REG].upper.f < 0.0F ?
+                                      -DSPregs[SRC1_REG].upper.f
+                                      : DSPregs[SRC1_REG].upper.f);
+         printfdbg ("cfabss mvf%d = |mvf%d| = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    DSPregs[DEST_REG].upper.f);
+         break;
+         
+       case 1: /* cfabsd */
+         mv_setRegDouble (DEST_REG,
+                          (mv_getRegDouble (SRC1_REG) < 0.0 ?
+                           -mv_getRegDouble (SRC1_REG)
+                           : mv_getRegDouble (SRC1_REG)));
+         printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    mv_getRegDouble (DEST_REG));
+         break;
+         
+       case 2: /* cfnegs */
+         DSPregs[DEST_REG].upper.f = -DSPregs[SRC1_REG].upper.f;
+         printfdbg ("cfnegs mvf%d = -mvf%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    DSPregs[DEST_REG].upper.f);
+         break;
+         
+       case 3: /* cfnegd */
+         mv_setRegDouble (DEST_REG,
+                          -mv_getRegDouble (SRC1_REG));
+         printfdbg ("cfnegd mvd%d = -mvd%d = %g\n",
+                    DEST_REG,
+                    mv_getRegDouble (DEST_REG));
+         break;
+         
+       case 4: /* cfadds */
+         DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
+           + DSPregs[SRC2_REG].upper.f;
+         printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    SRC2_REG,
+                    DSPregs[DEST_REG].upper.f);
+         break;
+         
+       case 5: /* cfaddd */
+         mv_setRegDouble (DEST_REG,
+                          mv_getRegDouble (SRC1_REG)
+                          + mv_getRegDouble (SRC2_REG));
+         printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    SRC2_REG,
+                    mv_getRegDouble (DEST_REG));
+         break;
+         
+       case 6: /* cfsubs */
+         DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
+           - DSPregs[SRC2_REG].upper.f;
+         printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    SRC2_REG,
+                    DSPregs[DEST_REG].upper.f);
+         break;
+         
+       case 7: /* cfsubd */
+         mv_setRegDouble (DEST_REG,
+                          mv_getRegDouble (SRC1_REG)
+                          - mv_getRegDouble (SRC2_REG));
+         printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n",
+                    DEST_REG,
+                    SRC1_REG,
+                    SRC2_REG,
+                    mv_getRegDouble (DEST_REG));
+         break;
+       }
+      break;
+
+    default:
+      fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
+      cirrus_not_implemented ("unknown");
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPCDP5 (ARMul_State * state,
+        unsigned      type,
+        ARMword       instr)
+{
+   int opcode2;
+   char shift;
+
+   opcode2 = BITS (5,7);
+
+   /* Shift constants are 7bit signed numbers in bits 0..3|5..7.  */
+   shift = BITS (0, 3) | (BITS (5, 7)) << 4;
+   if (shift & 0x40)
+     shift |= 0xc0;
+
+   switch (BITS (20,21))
+     {
+     case 0:
+       /* cfsh32 */
+       printfdbg ("cfsh32 %s amount=%d\n", shift < 0 ? "right" : "left",
+                 shift);
+       if (shift < 0)
+        /* Negative shift is a right shift.  */
+        DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -shift;
+       else
+        /* Positive shift is a left shift.  */
+        DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i << shift;
+       break;
+
+     case 1:
+       switch (opcode2)
+         {
+         case 0: /* cfmul32 */
+          DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
+            * DSPregs[SRC2_REG].lower.i;
+          printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 1: /* cfmul64 */
+          mv_setReg64int (DEST_REG,
+                          mv_getReg64int (SRC1_REG)
+                          * mv_getReg64int (SRC2_REG));
+          printfdbg ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     mv_getReg64int (DEST_REG));
+           break;
+          
+         case 2: /* cfmac32 */
+          DSPregs[DEST_REG].lower.i
+            += DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i;
+          printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 3: /* cfmsc32 */
+          DSPregs[DEST_REG].lower.i
+            -= DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i;
+          printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 4: /* cfcvts32 */
+          /* fixme: this should round */
+          DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f;
+          printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 5: /* cfcvtd32 */
+          /* fixme: this should round */
+          DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG);
+          printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 6: /* cftruncs32 */
+          DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f;
+          printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 7: /* cftruncd32 */
+          DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG);
+          printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+         }
+       break;
+
+     case 2:
+       /* cfsh64 */
+       printfdbg ("cfsh64\n");
+       
+       if (shift < 0)
+        /* Negative shift is a right shift.  */
+        mv_setReg64int (DEST_REG,
+                        mv_getReg64int (SRC1_REG) >> -shift);
+       else
+        /* Positive shift is a left shift.  */
+        mv_setReg64int (DEST_REG,
+                        mv_getReg64int (SRC1_REG) << shift);
+       printfdbg ("\t%llx\n", mv_getReg64int(DEST_REG));
+       break;
+
+     case 3:
+       switch (opcode2)
+         {
+         case 0: /* cfabs32 */
+          DSPregs[DEST_REG].lower.i = (DSPregs[SRC1_REG].lower.i < 0
+            ? -DSPregs[SRC1_REG].lower.i : DSPregs[SRC1_REG].lower.i);
+          printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 1: /* cfabs64 */
+          mv_setReg64int (DEST_REG,
+                          (mv_getReg64int (SRC1_REG) < 0
+                           ? -mv_getReg64int (SRC1_REG)
+                           : mv_getReg64int (SRC1_REG)));
+          printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     mv_getReg64int (DEST_REG));
+           break;
+          
+         case 2: /* cfneg32 */
+          DSPregs[DEST_REG].lower.i = -DSPregs[SRC1_REG].lower.i;
+          printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 3: /* cfneg64 */
+          mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG));
+          printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     mv_getReg64int (DEST_REG));
+           break;
+          
+         case 4: /* cfadd32 */
+          DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
+            + DSPregs[SRC2_REG].lower.i;
+          printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 5: /* cfadd64 */
+          mv_setReg64int (DEST_REG,
+                          mv_getReg64int (SRC1_REG)
+                          + mv_getReg64int (SRC2_REG));
+          printfdbg ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     mv_getReg64int (DEST_REG));
+           break;
+          
+         case 6: /* cfsub32 */
+          DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
+            - DSPregs[SRC2_REG].lower.i;
+          printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     DSPregs[DEST_REG].lower.i);
+           break;
+          
+         case 7: /* cfsub64 */
+          mv_setReg64int (DEST_REG,
+                          mv_getReg64int (SRC1_REG)
+                          - mv_getReg64int (SRC2_REG));
+          printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n",
+                     DEST_REG,
+                     SRC1_REG,
+                     SRC2_REG,
+                     mv_getReg64int (DEST_REG));
+           break;
+         }
+       break;
+
+     default:
+       fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr);
+       cirrus_not_implemented ("unknown");
+       break;
+     }
+
+  return ARMul_DONE;
+}
+
+unsigned
+DSPCDP6 (ARMul_State * state,
+        unsigned      type,
+        ARMword       instr)
+{
+   int opcode2;
+
+   opcode2 = BITS (5,7);
+
+   switch (BITS (20,21))
+     {
+     case 0:
+       /* cfmadd32 */
+       cirrus_not_implemented ("cfmadd32");
+       break;
+       
+     case 1:
+       /* cfmsub32 */
+       cirrus_not_implemented ("cfmsub32");
+       break;
+       
+     case 2:
+       /* cfmadda32 */
+       cirrus_not_implemented ("cfmadda32");
+       break;
+       
+     case 3:
+       /* cfmsuba32 */
+       cirrus_not_implemented ("cfmsuba32");
+       break;
+
+     default:
+       fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr);
+     }
+
+   return ARMul_DONE;
+}
+
+/* Conversion functions.
+
+   32-bit integers are stored in the LOWER half of a 64-bit physical
+   register.
+
+   Single precision floats are stored in the UPPER half of a 64-bit
+   physical register.  */
+
+static double
+mv_getRegDouble (int regnum)
+{
+  reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i;
+  reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i;
+  return reg_conv.d;
+}
+
+static void
+mv_setRegDouble (int regnum, double val)
+{
+  reg_conv.d = val;
+  DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index];
+  DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index];
+}
+
+static long long
+mv_getReg64int (int regnum)
+{
+  reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i;
+  reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i;
+  return reg_conv.ll;
+}
+
+static void
+mv_setReg64int (int regnum, long long val)
+{
+  reg_conv.ll = val;
+  DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index];
+  DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index];
+}
+
+/* Compute LSW in a double and a long long.  */
+
+void
+mv_compute_host_endianness (ARMul_State * state)
+{
+  static union
+  {
+    long long ll;
+    long ints[2];
+    long i;
+    double d;
+    float floats[2];
+    float f;
+  } conv;
+
+  /* Calculate where's the LSW in a 64bit int.  */
+  conv.ll = 45;
+  
+  if (conv.ints[0] == 0)
+    {
+      msw_int_index = 0;
+      lsw_int_index = 1;
+    }
+  else
+    {
+      assert (conv.ints[1] == 0);
+      msw_int_index = 1;
+      lsw_int_index = 0;
+    }
+
+  /* Calculate where's the LSW in a double.  */
+  conv.d = 3.0;
+  
+  if (conv.ints[0] == 0)
+    {
+      msw_float_index = 0;
+      lsw_float_index = 1;
+    }
+  else
+    {
+      assert (conv.ints[1] == 0);
+      msw_float_index = 1;
+      lsw_float_index = 0;
+    }
+
+  printfdbg ("lsw_int_index   %d\n", lsw_int_index);
+  printfdbg ("lsw_float_index %d\n", lsw_float_index);
+}
index 244c475eb9353a5c51ef83d359d82fc60044d58e..f13d32928b06585db22c7df394ddbb6539b1354f 100644 (file)
@@ -59,6 +59,38 @@ static int big_endian;
 
 int stop_simulator;
 
+/* Cirrus DSP registers.
+
+   We need to define these registers outside of maverick.c because
+   maverick.c might not be linked in unless --target=arm9e-* in which
+   case wrapper.c will not compile because it tries to access Cirrus
+   registers.  This should all go away once we get the Cirrus and ARM
+   Coprocessor to coexist in armcopro.c-- aldyh.  */
+
+struct maverick_regs
+{
+  union
+  {
+    int i;
+    float f;
+  } upper;
+  
+  union
+  {
+    int i;
+    float f;
+  } lower;
+};
+
+union maverick_acc_regs
+{
+  long double ld;              /* Acc registers are 72-bits.  */
+};
+
+struct maverick_regs     DSPregs[16];
+union maverick_acc_regs  DSPacc[4];
+ARMword DSPsc;
+
 static void
 init ()
 {
@@ -71,7 +103,6 @@ init ()
       state->bigendSig = (big_endian ? HIGH : LOW);
       ARMul_MemoryInit (state, mem_size);
       ARMul_OSInit (state);
-      ARMul_CoProInit (state);
       state->verbose = verbosity;
       done = 1;
     }
@@ -236,6 +267,10 @@ sim_create_inferior (sd, abfd, argv, env)
       ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop);
       break;
 
+    case bfd_mach_arm_ep9312:
+      ARMul_SelectProcessor (state, ARM_v4_Prop | ARM_ep9312_Prop);
+      break;
+
     case bfd_mach_arm_5:
       if (bfd_family_coff (abfd))
        {
@@ -422,6 +457,30 @@ sim_store_register (sd, rn, memory, length)
       ARMul_CPSRAltered (state);
       break;
 
+    case SIM_ARM_MAVERIC_COP0R0_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R1_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R2_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R3_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R4_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R5_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R6_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R7_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R8_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R9_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R10_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R11_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R12_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R13_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R14_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R15_REGNUM:
+      memcpy (& DSPregs [rn - SIM_ARM_MAVERIC_COP0R0_REGNUM],
+             memory, sizeof (struct maverick_regs));
+      return sizeof (struct maverick_regs);
+
+    case SIM_ARM_MAVERIC_DSPSC_REGNUM:
+      memcpy (&DSPsc, memory, sizeof DSPsc);
+      return sizeof DSPsc;
+
     default:
       return 0;
     }
@@ -477,6 +536,30 @@ sim_fetch_register (sd, rn, memory, length)
       regval = ARMul_GetCPSR (state);
       break;
 
+    case SIM_ARM_MAVERIC_COP0R0_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R1_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R2_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R3_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R4_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R5_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R6_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R7_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R8_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R9_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R10_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R11_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R12_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R13_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R14_REGNUM:
+    case SIM_ARM_MAVERIC_COP0R15_REGNUM:
+      memcpy (memory, & DSPregs [rn - SIM_ARM_MAVERIC_COP0R0_REGNUM],
+             sizeof (struct maverick_regs));
+      return sizeof (struct maverick_regs);
+
+    case SIM_ARM_MAVERIC_DSPSC_REGNUM:
+      memcpy (memory, & DSPsc, sizeof DSPsc);
+      return sizeof DSPsc;
+
     default:
       return 0;
     }