Add iWMMXt support to ARM simulator
authorNick Clifton <nickc@redhat.com>
Thu, 27 Mar 2003 17:13:33 +0000 (17:13 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 27 Mar 2003 17:13:33 +0000 (17:13 +0000)
14 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.c
sim/arm/arminit.c
sim/arm/armos.c
sim/arm/configure
sim/arm/configure.in
sim/arm/iwmmxt.c [new file with mode: 0644]
sim/arm/iwmmxt.h [new file with mode: 0644]
sim/arm/wrapper.c

index 97c2f443c38f2f1dacea8794107532de26ee149d..9a216a0f3e2f1d62f4d764953abf30ab87840eaf 100644 (file)
@@ -1,3 +1,7 @@
+2003-03-27  Nick Clifton  <nickc@redhat.com>
+
+       * sim-arm.h (sim_arm_regs): Add iWMMXt registers.
+
 2003-03-20  Nick Clifton  <nickc@redhat.com>
 
        * sim-arm.h (sim_arm_regs): Add Maverick co-processor
index fae11f0b16bbcac082cc2eb65a9770fbae5f4a1f..5598f73fa8faf72391b2874d268503191900125b 100644 (file)
@@ -72,7 +72,39 @@ enum sim_arm_regs
   SIM_ARM_MAVERIC_COP0R13_REGNUM,
   SIM_ARM_MAVERIC_COP0R14_REGNUM,
   SIM_ARM_MAVERIC_COP0R15_REGNUM,
-  SIM_ARM_MAVERIC_DSPSC_REGNUM
+  SIM_ARM_MAVERIC_DSPSC_REGNUM,
+  SIM_ARM_IWMMXT_COP0R0_REGNUM,
+  SIM_ARM_IWMMXT_COP0R1_REGNUM,
+  SIM_ARM_IWMMXT_COP0R2_REGNUM,
+  SIM_ARM_IWMMXT_COP0R3_REGNUM,
+  SIM_ARM_IWMMXT_COP0R4_REGNUM,
+  SIM_ARM_IWMMXT_COP0R5_REGNUM,
+  SIM_ARM_IWMMXT_COP0R6_REGNUM,
+  SIM_ARM_IWMMXT_COP0R7_REGNUM,
+  SIM_ARM_IWMMXT_COP0R8_REGNUM,
+  SIM_ARM_IWMMXT_COP0R9_REGNUM,
+  SIM_ARM_IWMMXT_COP0R10_REGNUM,
+  SIM_ARM_IWMMXT_COP0R11_REGNUM,
+  SIM_ARM_IWMMXT_COP0R12_REGNUM,
+  SIM_ARM_IWMMXT_COP0R13_REGNUM,
+  SIM_ARM_IWMMXT_COP0R14_REGNUM,
+  SIM_ARM_IWMMXT_COP0R15_REGNUM,
+  SIM_ARM_IWMMXT_COP1R0_REGNUM,
+  SIM_ARM_IWMMXT_COP1R1_REGNUM,
+  SIM_ARM_IWMMXT_COP1R2_REGNUM,
+  SIM_ARM_IWMMXT_COP1R3_REGNUM,
+  SIM_ARM_IWMMXT_COP1R4_REGNUM,
+  SIM_ARM_IWMMXT_COP1R5_REGNUM,
+  SIM_ARM_IWMMXT_COP1R6_REGNUM,
+  SIM_ARM_IWMMXT_COP1R7_REGNUM,
+  SIM_ARM_IWMMXT_COP1R8_REGNUM,
+  SIM_ARM_IWMMXT_COP1R9_REGNUM,
+  SIM_ARM_IWMMXT_COP1R10_REGNUM,
+  SIM_ARM_IWMMXT_COP1R11_REGNUM,
+  SIM_ARM_IWMMXT_COP1R12_REGNUM,
+  SIM_ARM_IWMMXT_COP1R13_REGNUM,
+  SIM_ARM_IWMMXT_COP1R14_REGNUM,
+  SIM_ARM_IWMMXT_COP1R15_REGNUM
 };
 
 #ifdef __cplusplus
index c6597defef5e5eebb4025a036dbe18f448476088..2249ade42b489c0e8e34f9a98ad8b7dac048d25e 100644 (file)
@@ -1,3 +1,28 @@
+2003-03-27  Nick Clifton  <nickc@redhat.com>
+
+       * configure.in: (CON_FLAGS): Define and intialise.
+       (COPRO): Add iwmmxt.o if configuring for XScale.
+       * configure: Regenerate.
+       * Makefile.in (iwmmxt.o): Add rule to build.
+       (COM_FLAGS): Define.
+       (ALL_FLAGS): Add CON_FLAGS.
+       * armcopro.c (ARMul_CoProInit): Initialise iWMMXt coprocessors.
+       * armdefs.h (struct ARMul_State): Add 'is_iWMMXt' field.
+       (ARM_iWMMXt_Prop): Define.
+       * armemu.c (ARMul_Emulate16): Intercept iWMMXt instructions and
+       pass to coprocessor.
+       * arminit.c (ARMul_NewState): Initialise 'is_iWMMXt'.
+       (ARMul_Abort): Catch branches through uninitialised vectors.
+       * armos.c (softevtorcode): Update comment.
+       (ARMul_OsInit): Use ARMUndefinedInstrV.
+       (ARMul_OsHandleSWI): Catch SWIs for unhandled vectors.
+       * wrapper.c (sim_create_inferior): Handle iWMMXt processor type.
+       (sim_store_register): Handle iWMMXt registers.
+       (sim_fetch_register): Handle iWMMXt registers.
+       * iwmmxt.h: New file. Exported iWMMXt coprocessor emulator
+       functions.
+       * iwmmxt.c: New file: iWMMXt emulator.
+
 2003-03-20  Nick Clifton  <nickc@redhat.com>
 
        * Contribute support for Cirrus Maverick ARM co-processor,
index 017a983289d3c60d91077949c1641c54445d6341..0218f7257ef71e2b7204c70ada83554d974ec72d 100644 (file)
@@ -32,6 +32,11 @@ armos.o: armos.c armdefs.h armos.h armfpe.h
 
 armcopro.o: armcopro.c armdefs.h
 maverick.o: maverick.c armdefs.h
+iwmmxt.o: iwmmxt.c iwmmxt.h armdefs.h
+
+CON_FLAGS=@CON_FLAGS@
+
+ALL_CFLAGS += $(CON_FLAGS)
 
 armemu26.o: armemu.c armdefs.h armemu.h 
        $(CC) -c $(srcdir)/armemu.c -o armemu26.o $(ALL_CFLAGS)
index b97478948696c5b86f8b33484a2e5248f9f7c15a..5fb72bfeb487a651d7c87a2aa84c0385f1ea82f3 100644 (file)
@@ -19,6 +19,9 @@
 #include "armos.h"
 #include "armemu.h"
 #include "ansidecl.h"
+#ifdef __IWMMXT__
+#include "iwmmxt.h"
+#endif
 
 /* Dummy Co-processors.  */
 
@@ -1365,6 +1368,16 @@ ARMul_CoProInit (ARMul_State * state)
                         MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
     }
 
+#ifdef __IWMMXT__
+  if (state->is_iWMMXt)
+    {
+      ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC,
+                        NULL, NULL, IwmmxtCDP, NULL, NULL);
+
+      ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL,
+                        IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, NULL);
+    }
+#endif
   /* No handlers below here.  */
 
   /* Call all the initialisation routines.  */
index 0f252226dd9aca159114d4c06a7288545808603a..a2ea405903775fde51bc3776f6b2651844079a41 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_iWMMXt;          /* Are we emulating an iWMMXt co-processor ?  */
   unsigned is_ep9312;          /* Are we emulating a Cirrus Maverick co-processor ?  */
   unsigned verbose;            /* Print various messages like the banner */
 };
@@ -164,6 +165,7 @@ struct ARMul_State
 #define ARM_v5e_Prop     0x100
 #define ARM_XScale_Prop  0x200
 #define ARM_ep9312_Prop  0x400
+#define ARM_iWMMXt_Prop  0x800
 
 /***************************************************************************\
 *                   Macros to extract instruction fields                    *
index 44943c4ecde25584344fbd99d8699b9a6344f53d..53fc9925d110e1f3730d303d330e00e881c8d36f 100644 (file)
@@ -19,6 +19,9 @@
 #include "armdefs.h"
 #include "armemu.h"
 #include "armos.h"
+#ifdef __IWMMXT__
+#include "iwmmxt.h"
+#endif
 
 static ARMword  GetDPRegRHS         (ARMul_State *, ARMword);
 static ARMword  GetDPSRegRHS        (ARMul_State *, ARMword);
@@ -379,6 +382,20 @@ ARMul_Emulate26 (ARMul_State * state)
       fprintf (stderr, "pc: %x, instr: %x\n", pc & ~1, instr);
       if (instr == 0)
        abort ();
+#endif
+#ifdef __IWMMXT__
+#if 0
+      {
+       static ARMword old_sp = -1;
+
+       if (old_sp != state->Reg[13])
+         {
+           old_sp = state->Reg[13];
+           fprintf (stderr, "pc: %08x: SP set to %08x%s\n",
+                    pc & ~1, old_sp, (old_sp % 8) ? " [UNALIGNED!]" : "");
+         }
+      }
+#endif
 #endif
 
       if (state->Exception)
@@ -492,6 +509,12 @@ ARMul_Emulate26 (ARMul_State * state)
              else if ((instr & 0xFC70F000) == 0xF450F000)
                /* The PLD instruction.  Ignored.  */
                goto donext;
+#ifdef __IWMMXT__
+             else if (   ((instr & 0xfe500f00) == 0xfc100100)
+                      || ((instr & 0xfe500f00) == 0xfc000100))
+               /* wldrw and wstrw are unconditional.  */
+               goto mainswitch;
+#endif
              else
                /* UNDEFINED in v5, UNPREDICTABLE in v3, v4, non executed in v1, v2.  */
                ARMul_UndefInstr (state, instr);
@@ -689,6 +712,10 @@ check_PMUintr:
                      goto donext;
                    }
                }
+#ifdef __IWMMXT__
+             if (ARMul_HandleIwmmxt (state, instr))
+               goto donext;
+#endif
            }
 
          switch ((int) BITS (20, 27))
index 04399900c959047fe01963d108579c4a0e5debb4..45887879c311235ea1c2a4cc6707af9b91909e08 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "armdefs.h"
 #include "armemu.h"
+#include "dbg_rdi.h"
 
 /***************************************************************************\
 *                 Definitions for the emulator architecture                 *
@@ -127,6 +128,7 @@ ARMul_NewState (void)
   state->is_v5 = LOW;
   state->is_v5e = LOW;
   state->is_XScale = LOW;
+  state->is_iWMMXt = LOW;
 
   ARMul_Reset (state);
 
@@ -157,6 +159,7 @@ 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_iWMMXt = (properties & ARM_iWMMXt_Prop) ? HIGH : LOW;
   state->is_ep9312 = (properties & ARM_ep9312_Prop) ? HIGH : LOW;
 
   /* Only initialse the coprocessor support once we
@@ -323,4 +326,24 @@ ARMul_Abort (ARMul_State * state, ARMword vector)
     ARMul_SetR15 (state, vector);
   else
     ARMul_SetR15 (state, R15CCINTMODE | vector);
+
+  if (ARMul_ReadWord (state, ARMul_GetPC (state)) == 0)
+    {
+      /* No vector has been installed.  Rather than simulating whatever
+        random bits might happen to be at address 0x20 onwards we elect
+        to stop.  */
+      switch (vector)
+       {
+       case ARMul_ResetV: state->EndCondition = RDIError_Reset; break;
+       case ARMul_UndefinedInstrV: state->EndCondition = RDIError_UndefinedInstruction; break;
+       case ARMul_SWIV: state->EndCondition = RDIError_SoftwareInterrupt; break;
+       case ARMul_PrefetchAbortV: state->EndCondition = RDIError_PrefetchAbort; break;
+       case ARMul_DataAbortV: state->EndCondition = RDIError_DataAbort; break;
+       case ARMul_AddrExceptnV: state->EndCondition = RDIError_AddressException; break;
+       case ARMul_IRQV: state->EndCondition = RDIError_IRQ; break;
+       case ARMul_FIQV: state->EndCondition = RDIError_FIQ; break;
+       default: break;
+       }
+      state->Emulate = FALSE;
+    }
 }
index 04916d6ad72f20c465b10340d35a4cbc22f8402e..613d07eda1712f67f7e5bab04aaf953d2953cd47 100644 (file)
@@ -131,8 +131,11 @@ unsigned int swi_mask = -1;
 
 static ARMword softvectorcode[] =
 {
-  /* Basic: swi tidyexception + event; mov pc, lr;
-     ldmia r11,{r11,pc}; swi generateexception  + event.  */
+  /* Installed instructions:
+       swi    tidyexception + event;
+       mov    lr, pc;
+       ldmia  fp, {fp, pc};
+       swi    generateexception  + event.  */
   0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /* Reset */
   0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /* Undef */
   0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /* SWI */
@@ -205,11 +208,15 @@ ARMul_OSInit (ARMul_State * state)
     /* Copy the code.  */
     ARMul_WriteWord (state, FPESTART + i, fpecode[i >> 2]);
 
+  /* Scan backwards from the end of the code.  */
   for (i = FPESTART + fpesize;; i -= 4)
     {
-      /* Reverse the error strings.  */
+      /* When we reach the marker value, break out of
+        the loop, leaving i pointing at the maker.  */
       if ((j = ARMul_ReadWord (state, i)) == 0xffffffff)
        break;
+
+      /* If necessary, reverse the error strings.  */
       if (state->bigendSig && j < 0x80000000)
        {
          /* It's part of the string so swap it.  */
@@ -221,9 +228,9 @@ ARMul_OSInit (ARMul_State * state)
     }
 
   /* Copy old illegal instr vector.  */
-  ARMul_WriteWord (state, FPEOLDVECT, ARMul_ReadWord (state, 4));
+  ARMul_WriteWord (state, FPEOLDVECT, ARMul_ReadWord (state, ARMUndefinedInstrV));
   /* Install new vector.  */
-  ARMul_WriteWord (state, 4, FPENEWVECT (ARMul_ReadWord (state, i - 4)));
+  ARMul_WriteWord (state, ARMUndefinedInstrV, FPENEWVECT (ARMul_ReadWord (state, i - 4)));
   ARMul_ConsolePrint (state, ", FPE");
 
 /* #endif  ASIM */
@@ -692,12 +699,34 @@ ARMul_OSHandleSWI (ARMul_State * state, ARMword number)
        unhandled = TRUE;
       break;
 
-    case 0x90:
-    case 0x91:
-    case 0x92:
-      /* These are used by the FPE code.  */
+      /* The following SWIs are generated by the softvectorcode[]
+        installed by default by the simulator.  */
+    case 0x91: /* Undefined Instruction.  */
+      {
+       ARMword addr = state->RegBank[UNDEFBANK][14] - 4;
+       
+       sim_callback->printf_filtered
+         (sim_callback, "sim: exception: Unhandled Instruction '0x%08x' at 0x%08x.  Stopping.\n",
+          ARMul_ReadWord (state, addr), addr);
+       state->EndCondition = RDIError_SoftwareInterrupt;
+       state->Emulate = FALSE;
+       return FALSE;
+      }      
+
+    case 0x90: /* Reset.  */
+    case 0x92: /* SWI.  */
+      /* These two can be safely ignored.  */
       break;
-      
+
+    case 0x93: /* Prefetch Abort.  */
+    case 0x94: /* Data Abort.  */
+    case 0x95: /* Address Exception.  */
+    case 0x96: /* IRQ.  */
+    case 0x97: /* FIQ.  */
+    case 0x98: /* Error.  */
+      unhandled = TRUE;
+      break;
+
     case -1:
       /* This can happen when a SWI is interrupted (eg receiving a
         ctrl-C whilst processing SWIRead()).  The SWI will complete
index 26fd5f5d6d1bc682e0a0e57af0f502d4950ee5cf..8f79c259f4306aa882db4092dfda425497306865 100755 (executable)
@@ -3535,6 +3535,14 @@ done
 
 
 COPRO="armcopro.o maverick.o"
+CON_FLAGS=  
+case x$target_alias in
+       xxscale-*)
+               COPRO="armcopro.o maverick.o iwmmxt.o"
+               CON_FLAGS=-D__IWMMXT__
+               ;;
+esac
+
 
 
 
@@ -3748,6 +3756,7 @@ s%@sim_stdio@%$sim_stdio%g
 s%@sim_trace@%$sim_trace%g
 s%@sim_profile@%$sim_profile%g
 s%@EXEEXT@%$EXEEXT%g
+s%@CON_FLAGS@%$CON_FLAGS%g
 s%@COPRO@%$COPRO%g
 
 CEOF
index 73fa0a0a6439eed0bb19b63d4f7a251bcff4d641..c0010683199d883a5f1d8a9d8b97fcd9b007eb97 100644 (file)
@@ -8,7 +8,15 @@ SIM_AC_COMMON
 AC_CHECK_HEADERS(unistd.h)
 
 COPRO="armcopro.o maverick.o"
+CON_FLAGS=  
+case x$target_alias in
+       xxscale-*)
+               COPRO="armcopro.o maverick.o iwmmxt.o"
+               CON_FLAGS=-D__IWMMXT__
+               ;;
+esac
 
+AC_SUBST(CON_FLAGS)
 AC_SUBST(COPRO)
 
 SIM_AC_OUTPUT
diff --git a/sim/arm/iwmmxt.c b/sim/arm/iwmmxt.c
new file mode 100644 (file)
index 0000000..72444f6
--- /dev/null
@@ -0,0 +1,3730 @@
+/*  iwmmxt.c -- Intel(r) Wireless MMX(tm) technology co-processor interface.
+    Copyright (C) 2002 Free Software Foundation, Inc.
+    Contributed by matthew green (mrg@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 "armdefs.h"
+#include "armos.h"
+#include "armemu.h"
+#include "ansidecl.h"
+#include "iwmmxt.h"
+
+/* #define DEBUG 1 */
+
+/* Intel(r) Wireless MMX(tm) technology co-processor.  
+   It uses co-processor numbers (0 and 1).  There are 16 vector registers wRx
+   and 16 control registers wCx.  Co-processors 0 and 1 are used in MCR/MRC
+   to access wRx and wCx respectively.  */
+
+static ARMdword wR[16];
+static ARMword  wC[16] = { 0x69051010 };
+
+#define SUBSTR(w,t,m,n) ((t)(w <<  ((sizeof (t) * 8 - 1) - (n))) \
+                               >> (((sizeof (t) * 8 - 1) - (n)) + (m)))
+#define wCBITS(w,x,y)   SUBSTR (wC[w], ARMword, x, y)
+#define wRBITS(w,x,y)   SUBSTR (wR[w], ARMdword, x, y)
+#define wCID   0
+#define wCon   1
+#define wCSSF  2
+#define wCASF  3
+#define wCGR0  8
+#define wCGR1  9
+#define wCGR2 10
+#define wCGR3 11
+
+/* Bits in the wCon register.  */
+#define WCON_CUP       (1 << 0)
+#define WCON_MUP       (1 << 1)
+
+/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations.  */
+#define SIMD8_SET(x,  v, n, b) (x) |= ((v != 0) << ((((b) + 1) * 4) + (n)))
+#define SIMD16_SET(x, v, n, h) (x) |= ((v != 0) << ((((h) + 1) * 8) + (n)))
+#define SIMD32_SET(x, v, n, w) (x) |= ((v != 0) << ((((w) + 1) * 16) + (n)))
+#define SIMD64_SET(x, v, n)    (x) |= ((v != 0) << (32 + (n)))
+
+/* Flags to pass as "n" above.  */
+#define SIMD_NBIT      -1
+#define SIMD_ZBIT      -2
+#define SIMD_CBIT      -3
+#define SIMD_VBIT      -4
+
+/* Various status bit macros.  */
+#define NBIT8(x)       ((x) & 0x80)
+#define NBIT16(x)      ((x) & 0x8000)
+#define NBIT32(x)      ((x) & 0x80000000)
+#define NBIT64(x)      ((x) & 0x8000000000000000ULL)
+#define ZBIT8(x)       (((x) & 0xff) == 0)
+#define ZBIT16(x)      (((x) & 0xffff) == 0)
+#define ZBIT32(x)      (((x) & 0xffffffff) == 0)
+#define ZBIT64(x)      (x == 0)
+
+/* Access byte/half/word "n" of register "x".  */
+#define wRBYTE(x,n)    wRBITS ((x), (n) * 8, (n) * 8 + 7)
+#define wRHALF(x,n)    wRBITS ((x), (n) * 16, (n) * 16 + 15)
+#define wRWORD(x,n)    wRBITS ((x), (n) * 32, (n) * 32 + 31)
+
+/* Macro to handle how the G bit selects wCGR registers.  */
+#define DECODE_G_BIT(state, instr, shift)      \
+{                                              \
+  unsigned int reg;                            \
+                                               \
+  reg = BITS (0, 3);                           \
+                                               \
+  if (BIT (8)) /* G */                         \
+    {                                          \
+      if (reg < wCGR0 || reg > wCGR3)          \
+       {                                       \
+         ARMul_UndefInstr (state, instr);      \
+         return ARMul_DONE;                    \
+       }                                       \
+      shift = wC [reg];                                \
+    }                                          \
+  else                                         \
+    shift = wR [reg];                          \
+                                               \
+  shift &= 0xff;                               \
+}
+
+/* Index calculations for the satrv[] array.  */
+#define BITIDX8(x)     (x)
+#define BITIDX16(x)    (((x) + 1) * 2 - 1)
+#define BITIDX32(x)    (((x) + 1) * 4 - 1)
+
+/* Sign extension macros.  */
+#define EXTEND8(a)     ((a) & 0x80 ? ((a) | 0xffffff00) : (a))
+#define EXTEND16(a)    ((a) & 0x8000 ? ((a) | 0xffff0000) : (a))
+#define EXTEND32(a)    ((a) & 0x80000000ULL ? ((a) | 0xffffffff00000000ULL) : (a))
+
+/* Set the wCSSF from 8 values.  */
+#define SET_wCSSF(a,b,c,d,e,f,g,h) \
+  wC[wCSSF] = (((h) != 0) << 7) | (((g) != 0) << 6) \
+            | (((f) != 0) << 5) | (((e) != 0) << 4) \
+            | (((d) != 0) << 3) | (((c) != 0) << 2) \
+            | (((b) != 0) << 1) | (((a) != 0) << 0);
+
+/* Set the wCSSR from an array with 8 values.  */
+#define SET_wCSSFvec(v) \
+  SET_wCSSF((v)[0],(v)[1],(v)[2],(v)[3],(v)[4],(v)[5],(v)[6],(v)[7])
+
+/* Size qualifiers for vector operations.  */
+#define Bqual                  0
+#define Hqual                  1
+#define Wqual                  2
+#define Dqual                  3
+
+/* Saturation qualifiers for vector operations.  */
+#define NoSaturation           0
+#define UnsignedSaturation     1
+#define SignedSaturation       3
+
+\f
+/* Prototypes.  */
+static ARMword         Add32  (ARMword,  ARMword,  int *, int *, ARMword);
+static ARMdword        AddS32 (ARMdword, ARMdword, int *, int *);
+static ARMdword        AddU32 (ARMdword, ARMdword, int *, int *);
+static ARMword         AddS16 (ARMword,  ARMword,  int *, int *);
+static ARMword         AddU16 (ARMword,  ARMword,  int *, int *);
+static ARMword         AddS8  (ARMword,  ARMword,  int *, int *);
+static ARMword         AddU8  (ARMword,  ARMword,  int *, int *);
+static ARMword         Sub32  (ARMword,  ARMword,  int *, int *, ARMword);
+static ARMdword        SubS32 (ARMdword, ARMdword, int *, int *);
+static ARMdword        SubU32 (ARMdword, ARMdword, int *, int *);
+static ARMword         SubS16 (ARMword,  ARMword,  int *, int *);
+static ARMword         SubS8  (ARMword,  ARMword,  int *, int *);
+static ARMword         SubU16 (ARMword,  ARMword,  int *, int *);
+static ARMword         SubU8  (ARMword,  ARMword,  int *, int *);
+static unsigned char   IwmmxtSaturateU8  (signed short, int *);
+static signed char     IwmmxtSaturateS8  (signed short, int *);
+static unsigned short  IwmmxtSaturateU16 (signed int, int *);
+static signed short    IwmmxtSaturateS16 (signed int, int *);
+static unsigned long   IwmmxtSaturateU32 (signed long long, int *);
+static signed long     IwmmxtSaturateS32 (signed long long, int *);
+static ARMword         Compute_Iwmmxt_Address   (ARMul_State *, ARMword, int *);
+static ARMdword        Iwmmxt_Load_Double_Word  (ARMul_State *, ARMword);
+static ARMword         Iwmmxt_Load_Word         (ARMul_State *, ARMword);
+static ARMword         Iwmmxt_Load_Half_Word    (ARMul_State *, ARMword);
+static ARMword         Iwmmxt_Load_Byte         (ARMul_State *, ARMword);
+static void            Iwmmxt_Store_Double_Word (ARMul_State *, ARMword, ARMdword);
+static void            Iwmmxt_Store_Word        (ARMul_State *, ARMword, ARMword);
+static void            Iwmmxt_Store_Half_Word   (ARMul_State *, ARMword, ARMword);
+static void            Iwmmxt_Store_Byte        (ARMul_State *, ARMword, ARMword);
+static int             Process_Instruction      (ARMul_State *, ARMword);
+
+static int TANDC    (ARMul_State *, ARMword);
+static int TBCST    (ARMul_State *, ARMword);
+static int TEXTRC   (ARMul_State *, ARMword);
+static int TEXTRM   (ARMul_State *, ARMword);
+static int TINSR    (ARMul_State *, ARMword);
+static int TMCR     (ARMul_State *, ARMword);
+static int TMCRR    (ARMul_State *, ARMword);
+static int TMIA     (ARMul_State *, ARMword);
+static int TMIAPH   (ARMul_State *, ARMword);
+static int TMIAxy   (ARMul_State *, ARMword);
+static int TMOVMSK  (ARMul_State *, ARMword);
+static int TMRC     (ARMul_State *, ARMword);
+static int TMRRC    (ARMul_State *, ARMword);
+static int TORC     (ARMul_State *, ARMword);
+static int WACC     (ARMul_State *, ARMword);
+static int WADD     (ARMul_State *, ARMword);
+static int WALIGNI  (ARMword);
+static int WALIGNR  (ARMul_State *, ARMword);
+static int WAND     (ARMword);
+static int WANDN    (ARMword);
+static int WAVG2    (ARMword);
+static int WCMPEQ   (ARMul_State *, ARMword);
+static int WCMPGT   (ARMul_State *, ARMword);
+static int WLDR     (ARMul_State *, ARMword);
+static int WMAC     (ARMword);
+static int WMADD    (ARMword);
+static int WMAX     (ARMul_State *, ARMword);
+static int WMIN     (ARMul_State *, ARMword);
+static int WMUL     (ARMword);
+static int WOR      (ARMword);
+static int WPACK    (ARMul_State *, ARMword);
+static int WROR     (ARMul_State *, ARMword);
+static int WSAD     (ARMword);
+static int WSHUFH   (ARMword);
+static int WSLL     (ARMul_State *, ARMword);
+static int WSRA     (ARMul_State *, ARMword);
+static int WSRL     (ARMul_State *, ARMword);
+static int WSTR     (ARMul_State *, ARMword);
+static int WSUB     (ARMul_State *, ARMword);
+static int WUNPCKEH (ARMul_State *, ARMword);
+static int WUNPCKEL (ARMul_State *, ARMword);
+static int WUNPCKIH (ARMul_State *, ARMword);
+static int WUNPCKIL (ARMul_State *, ARMword);
+static int WXOR     (ARMword);
+\f
+/* This function does the work of adding two 32bit values
+   together, and calculating if a carry has occurred.  */
+
+static ARMword
+Add32 (ARMword a1,
+       ARMword a2,
+       int * carry_ptr,
+       int * overflow_ptr,
+       ARMword sign_mask)
+{
+  ARMword result = (a1 + a2);
+  unsigned int uresult = (unsigned int) result;
+  unsigned int ua1 = (unsigned int) a1;
+
+  /* If (result == a1) and (a2 == 0),
+     or (result > a2) then we have no carry.  */
+  * carry_ptr = ((uresult == ua1) ? (a2 != 0) : (uresult < ua1));
+
+  /* Overflow occurs when both arguments are the
+     same sign, but the result is a different sign.  */
+  * overflow_ptr = (   ( (result & sign_mask) && !(a1 & sign_mask) && !(a2 & sign_mask))
+                   || (!(result & sign_mask) &&  (a1 & sign_mask) &&  (a2 & sign_mask)));
+  
+  return result;
+}
+
+static ARMdword
+AddS32 (ARMdword a1, ARMdword a2, int * carry_ptr, int * overflow_ptr)
+{
+  ARMdword     result;
+  unsigned int uresult;
+  unsigned int ua1;
+
+  a1 = EXTEND32 (a1);
+  a2 = EXTEND32 (a2);
+
+  result  = a1 + a2;
+  uresult = (unsigned int) result;
+  ua1     = (unsigned int) a1;
+
+  * carry_ptr = ((uresult == a1) ? (a2 != 0) : (uresult < ua1));
+
+  * overflow_ptr = (   ( (result & 0x80000000ULL) && !(a1 & 0x80000000ULL) && !(a2 & 0x80000000ULL))
+                   || (!(result & 0x80000000ULL) &&  (a1 & 0x80000000ULL) &&  (a2 & 0x80000000ULL)));
+
+  return result;
+}
+
+static ARMdword
+AddU32 (ARMdword a1, ARMdword a2, int * carry_ptr, int * overflow_ptr)
+{
+  ARMdword     result;
+  unsigned int uresult;
+  unsigned int ua1;
+
+  a1 &= 0xffffffff;
+  a2 &= 0xffffffff;
+
+  result  = a1 + a2;
+  uresult = (unsigned int) result;
+  ua1     = (unsigned int) a1;
+
+  * carry_ptr = ((uresult == a1) ? (a2 != 0) : (uresult < ua1));
+
+  * overflow_ptr = (   ( (result & 0x80000000ULL) && !(a1 & 0x80000000ULL) && !(a2 & 0x80000000ULL))
+                   || (!(result & 0x80000000ULL) &&  (a1 & 0x80000000ULL) &&  (a2 & 0x80000000ULL)));
+
+  return result;
+}
+
+static ARMword
+AddS16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 = EXTEND16 (a1);
+  a2 = EXTEND16 (a2);
+
+  return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x8000);
+}
+
+static ARMword
+AddU16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 &= 0xffff;
+  a2 &= 0xffff;
+
+  return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x8000);
+}
+
+static ARMword
+AddS8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 = EXTEND8 (a1);
+  a2 = EXTEND8 (a2);
+
+  return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x80);
+}
+
+static ARMword
+AddU8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 &= 0xff;
+  a2 &= 0xff;
+
+  return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x80);
+}
+
+static ARMword
+Sub32 (ARMword a1,
+       ARMword a2,
+       int * borrow_ptr,
+       int * overflow_ptr,
+       ARMword sign_mask)
+{
+  ARMword result = (a1 - a2);
+  unsigned int ua1 = (unsigned int) a1;
+  unsigned int ua2 = (unsigned int) a2;
+
+  /* A borrow occurs if a2 is (unsigned) larger than a1.
+     However the carry flag is *cleared* if a borrow occurs.  */
+  * borrow_ptr = ! (ua2 > ua1);
+
+  /* Overflow occurs when a negative number is subtracted from a
+     positive number and the result is negative or a positive
+     number is subtracted from a negative number and the result is
+     positive.  */
+  * overflow_ptr = ( (! (a1 & sign_mask) &&   (a2 & sign_mask) &&   (result & sign_mask))
+                   || ((a1 & sign_mask) && ! (a2 & sign_mask) && ! (result & sign_mask)));
+
+  return result;
+}
+
+static ARMdword
+SubS32 (ARMdword a1, ARMdword a2, int * borrow_ptr, int * overflow_ptr)
+{
+  ARMdword     result;
+  unsigned int ua1;
+  unsigned int ua2;
+
+  a1 = EXTEND32 (a1);
+  a2 = EXTEND32 (a2);
+
+  result = a1 - a2;
+  ua1    = (unsigned int) a1;
+  ua2    = (unsigned int) a2;
+
+  * borrow_ptr = ! (ua2 > ua1);
+
+  * overflow_ptr = ( (! (a1 & 0x80000000ULL) &&   (a2 & 0x80000000ULL) &&   (result & 0x80000000ULL))
+                   || ((a1 & 0x80000000ULL) && ! (a2 & 0x80000000ULL) && ! (result & 0x80000000ULL)));
+
+  return result;
+}
+
+static ARMword
+SubS16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 = EXTEND16 (a1);
+  a2 = EXTEND16 (a2);
+
+  return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x8000);
+}
+
+static ARMword
+SubS8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 = EXTEND8 (a1);
+  a2 = EXTEND8 (a2);
+
+  return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x80);
+}
+
+static ARMword
+SubU16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 &= 0xffff;
+  a2 &= 0xffff;
+
+  return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x8000);
+}
+
+static ARMword
+SubU8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr)
+{
+  a1 &= 0xff;
+  a2 &= 0xff;
+
+  return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x80);
+}
+
+static ARMdword
+SubU32 (ARMdword a1, ARMdword a2, int * borrow_ptr, int * overflow_ptr)
+{
+  ARMdword     result;
+  unsigned int ua1;
+  unsigned int ua2;
+
+  a1 &= 0xffffffff;
+  a2 &= 0xffffffff;
+
+  result = a1 - a2;
+  ua1    = (unsigned int) a1;
+  ua2    = (unsigned int) a2;
+
+  * borrow_ptr = ! (ua2 > ua1);
+
+  * overflow_ptr = ( (! (a1 & 0x80000000ULL) &&   (a2 & 0x80000000ULL) &&   (result & 0x80000000ULL))
+                   || ((a1 & 0x80000000ULL) && ! (a2 & 0x80000000ULL) && ! (result & 0x80000000ULL)));
+
+  return result;
+}
+
+/* For the saturation.  */
+
+static unsigned char
+IwmmxtSaturateU8 (signed short val, int * sat)
+{
+  unsigned char rv;
+
+  if (val < 0)
+    {
+      rv = 0;
+      *sat = 1;
+    }
+  else if (val > 0xff)
+    {
+      rv = 0xff;
+      *sat = 1;
+    }
+  else
+    {
+      rv = val & 0xff;
+      *sat = 0;
+    }
+  return rv;
+}
+
+static signed char
+IwmmxtSaturateS8 (signed short val, int * sat)
+{
+  signed char rv;
+
+  if (val < -0x80)
+    {
+      rv = -0x80;
+      *sat = 1;
+    }
+  else if (val > 0x7f)
+    {
+      rv = 0x7f;
+      *sat = 1;
+    }
+  else
+    {
+      rv = val & 0xff;
+      *sat = 0;
+    }
+  return rv;
+}
+
+static unsigned short
+IwmmxtSaturateU16 (signed int val, int * sat)
+{
+  unsigned short rv;
+
+  if (val < 0)
+    {
+      rv = 0;
+      *sat = 1;
+    }
+  else if (val > 0xffff)
+    {
+      rv = 0xffff;
+      *sat = 1;
+    }
+  else
+    {
+      rv = val & 0xffff;
+      *sat = 0;
+    }
+  return rv;
+}
+
+static signed short
+IwmmxtSaturateS16 (signed int val, int * sat)
+{
+  signed short rv;
+  
+  if (val < -0x8000)
+    {
+      rv = - 0x8000;
+      *sat = 1;
+    }
+  else if (val > 0x7fff)
+    {
+      rv = 0x7fff;
+      *sat = 1;
+    }
+  else
+    {
+      rv = val & 0xffff;
+      *sat = 0;
+    }
+  return rv;
+}
+
+static unsigned long
+IwmmxtSaturateU32 (signed long long val, int * sat)
+{
+  unsigned long rv;
+
+  if (val < 0)
+    {
+      rv = 0;
+      *sat = 1;
+    }
+  else if (val > 0xffffffff)
+    {
+      rv = 0xffffffff;
+      *sat = 1;
+    }
+  else
+    {
+      rv = val & 0xffffffff;
+      *sat = 0;
+    }
+  return rv;
+}
+
+static signed long
+IwmmxtSaturateS32 (signed long long val, int * sat)
+{
+  signed long rv;
+  
+  if (val < -0x80000000LL)
+    {
+      rv = -0x80000000;
+      *sat = 1;
+    }
+  else if (val > 0x7fffffff)
+    {
+      rv = 0x7fffffff;
+      *sat = 1;
+    }
+  else
+    {
+      rv = val & 0xffffffff;
+      *sat = 0;
+    }
+  return rv;
+}
+
+/* Intel(r) Wireless MMX(tm) technology Acessor functions.  */
+
+unsigned
+IwmmxtLDC (ARMul_State * state ATTRIBUTE_UNUSED,
+          unsigned      type  ATTRIBUTE_UNUSED,
+          ARMword       instr,
+          ARMword       data)
+{
+  return ARMul_CANT;
+}
+
+unsigned
+IwmmxtSTC (ARMul_State * state ATTRIBUTE_UNUSED,
+          unsigned      type  ATTRIBUTE_UNUSED,
+          ARMword       instr,
+          ARMword *     data)
+{
+  return ARMul_CANT;
+}
+
+unsigned
+IwmmxtMRC (ARMul_State * state ATTRIBUTE_UNUSED,
+          unsigned      type  ATTRIBUTE_UNUSED,
+          ARMword       instr,
+          ARMword *     value)
+{
+  return ARMul_CANT;
+}
+
+unsigned
+IwmmxtMCR (ARMul_State * state ATTRIBUTE_UNUSED,
+          unsigned      type  ATTRIBUTE_UNUSED,
+          ARMword       instr,
+          ARMword       value)
+{
+  return ARMul_CANT;
+}
+
+unsigned
+IwmmxtCDP (ARMul_State * state, unsigned type, ARMword instr)
+{
+  return ARMul_CANT;
+}
+
+/* Intel(r) Wireless MMX(tm) technology instruction implementations.  */
+
+static int
+TANDC (ARMul_State * state, ARMword instr)
+{
+  ARMword cpsr;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tandc\n");
+#endif  
+
+  /* The Rd field must be r15.  */
+  if (BITS (12, 15) != 15)
+    return ARMul_CANT;
+
+  /* The CRn field must be r3.  */
+  if (BITS (16, 19) != 3)
+    return ARMul_CANT;
+
+  /* The CRm field must be r0.  */
+  if (BITS (0, 3) != 0)
+    return ARMul_CANT;
+
+  cpsr = ARMul_GetCPSR (state) & 0x0fffffff;
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      cpsr |= (  (wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 24, 27)
+               & wCBITS (wCASF, 20, 23) & wCBITS (wCASF, 16, 19)
+               & wCBITS (wCASF, 12, 15) & wCBITS (wCASF,  8, 11)
+               & wCBITS (wCASF,  4,  7) & wCBITS (wCASF,  0,  3)) << 28);
+      break;
+
+    case Hqual:
+      cpsr |= (  (wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 20, 23)
+               & wCBITS (wCASF, 12, 15) & wCBITS (wCASF,  4, 7)) << 28);
+      break;
+
+    case Wqual:
+      cpsr |= ((wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 12, 15)) << 28);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+  
+  ARMul_SetCPSR (state, cpsr);
+
+  return ARMul_DONE;
+}
+
+static int
+TBCST (ARMul_State * state, ARMword instr)
+{
+  ARMdword Rn;
+  int wRd;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tbcst\n");
+#endif  
+
+  Rn  = state->Reg [BITS (12, 15)];
+  if (BITS (12, 15) == 15)
+    Rn &= 0xfffffffc;
+
+  wRd = BITS (16, 19);
+
+  switch (BITS (6, 7))
+    {
+    case Bqual:
+      Rn &= 0xff;
+      wR [wRd] = (Rn << 56) | (Rn << 48) | (Rn << 40) | (Rn << 32)
+              | (Rn << 24) | (Rn << 16) | (Rn << 8) | Rn;
+      break;
+
+    case Hqual:
+      Rn &= 0xffff;
+      wR [wRd] = (Rn << 48) | (Rn << 32) | (Rn << 16) | Rn;
+      break;
+
+    case Wqual:
+      Rn &= 0xffffffff;
+      wR [wRd] = (Rn << 32) | Rn;
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      break;
+    }
+
+  wC [wCon] |= WCON_MUP;
+  return ARMul_DONE;
+}
+
+static int
+TEXTRC (ARMul_State * state, ARMword instr)
+{
+  ARMword cpsr;
+  ARMword selector;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "textrc\n");
+#endif  
+
+  /* The Rd field must be r15.  */
+  if (BITS (12, 15) != 15)
+    return ARMul_CANT;
+
+  /* The CRn field must be r3.  */
+  if (BITS (16, 19) != 3)
+    return ARMul_CANT;
+
+  /* The CRm field must be 0xxx.  */
+  if (BIT (3) != 0)
+    return ARMul_CANT;
+
+  selector = BITS (0, 2);
+  cpsr = ARMul_GetCPSR (state) & 0x0fffffff;
+
+  switch (BITS (22, 23))
+    {
+    case Bqual: selector *= 4; break;
+    case Hqual: selector = ((selector & 3) * 8) + 4; break;
+    case Wqual: selector = ((selector & 1) * 16) + 12; break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+  
+  cpsr |= wCBITS (wCASF, selector, selector + 3) << 28;
+  ARMul_SetCPSR (state, cpsr);
+
+  return ARMul_DONE;
+}
+
+static int
+TEXTRM (ARMul_State * state, ARMword instr)
+{
+  ARMword Rd;
+  int     offset;
+  int     wRn;
+  int     sign;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "textrm\n");
+#endif  
+
+  wRn    = BITS (16, 19);
+  sign   = BIT (3);
+  offset = BITS (0, 2);
+  
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      offset *= 8;
+      Rd = wRBITS (wRn, offset, offset + 7);
+      if (sign)
+       Rd = EXTEND8 (Rd);
+      break;
+
+    case Hqual:
+      offset = (offset & 3) * 16;
+      Rd = wRBITS (wRn, offset, offset + 15);
+      if (sign)
+       Rd = EXTEND16 (Rd);
+      break;
+
+    case Wqual:
+      offset = (offset & 1) * 32;
+      Rd = wRBITS (wRn, offset, offset + 31);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  if (BITS (12, 15) == 15)
+    ARMul_UndefInstr (state, instr);
+  else
+    state->Reg [BITS (12, 15)] = Rd;
+
+  return ARMul_DONE;
+}
+
+static int
+TINSR (ARMul_State * state, ARMword instr)
+{
+  ARMdword data;
+  ARMword  offset;
+  int      wRd;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tinsr\n");
+#endif
+
+  wRd = BITS (16, 19);
+  data = state->Reg [BITS (12, 15)];
+  offset = BITS (0, 2);
+
+  switch (BITS (6, 7))
+    {
+    case Bqual:
+      data &= 0xff;
+      switch (offset)
+       {
+       case 0: wR [wRd] = data | (wRBITS (wRd, 8, 63) << 8); break;
+       case 1: wR [wRd] = wRBITS (wRd, 0,  7) | (data <<  8) | (wRBITS (wRd, 16, 63) << 16); break;
+       case 2: wR [wRd] = wRBITS (wRd, 0, 15) | (data << 16) | (wRBITS (wRd, 24, 63) << 24); break;
+       case 3: wR [wRd] = wRBITS (wRd, 0, 23) | (data << 24) | (wRBITS (wRd, 32, 63) << 32); break;
+       case 4: wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32) | (wRBITS (wRd, 40, 63) << 40); break;
+       case 5: wR [wRd] = wRBITS (wRd, 0, 39) | (data << 40) | (wRBITS (wRd, 48, 63) << 48); break;
+       case 6: wR [wRd] = wRBITS (wRd, 0, 47) | (data << 48) | (wRBITS (wRd, 56, 63) << 56); break;
+       case 7: wR [wRd] = wRBITS (wRd, 0, 55) | (data << 56); break;
+       }
+      break;
+
+    case Hqual:
+      data &= 0xffff;
+
+      switch (offset & 3)
+       {
+       case 0: wR [wRd] = data | (wRBITS (wRd, 16, 63) << 16); break;    
+       case 1: wR [wRd] = wRBITS (wRd, 0, 15) | (data << 16) | (wRBITS (wRd, 32, 63) << 32); break;
+       case 2: wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32) | (wRBITS (wRd, 48, 63) << 48); break;
+       case 3: wR [wRd] = wRBITS (wRd, 0, 47) | (data << 48); break;
+       }
+      break;
+
+    case Wqual:
+      if (offset & 1)
+       wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32);
+      else
+       wR [wRd] = (wRBITS (wRd, 32, 63) << 32) | data;
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      break;
+    }
+
+  wC [wCon] |= WCON_MUP;
+  return ARMul_DONE;
+}
+
+static int
+TMCR (ARMul_State * state, ARMword instr)
+{
+  ARMword val;
+  int     wCreg;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmcr\n");
+#endif  
+
+  if (BITS (0, 3) != 0)
+    return ARMul_CANT;
+
+  val = state->Reg [BITS (12, 15)];
+  if (BITS (12, 15) == 15)
+    val &= 0xfffffffc;
+
+  wCreg = BITS (16, 19);
+
+  switch (wCreg)
+    {
+    case wCID:
+      /* The wCID register is read only.  */
+      break;
+
+    case wCon:
+      /* Writing to the MUP or CUP bits clears them.  */
+      wC [wCon] &= ~ (val & 0x3);
+      break;
+      
+    case wCSSF:
+      /* Only the bottom 8 bits can be written to.
+          The higher bits write as zero.  */
+      wC [wCSSF] = (val & 0xff);
+      wC [wCon] |= WCON_CUP;
+      break;
+      
+    default:
+      wC [wCreg] = val;
+      wC [wCon] |= WCON_CUP;
+      break;
+    }
+
+  return ARMul_DONE;
+}
+
+static int
+TMCRR (ARMul_State * state, ARMword instr)
+{
+  ARMdword RdHi = state->Reg [BITS (16, 19)];
+  ARMword  RdLo = state->Reg [BITS (12, 15)];
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmcrr\n");
+#endif  
+
+  if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15))
+    return ARMul_CANT;
+
+  wR [BITS (0, 3)] = (RdHi << 32) | RdLo;
+
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+TMIA (ARMul_State * state, ARMword instr)
+{
+  signed long long a, b;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmia\n");
+#endif  
+
+  if ((BITS (0, 3) == 15) || (BITS (12, 15) == 15))
+    {
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  a = state->Reg [BITS (0, 3)];
+  b = state->Reg [BITS (12, 15)];
+
+  a = EXTEND32 (a);
+  b = EXTEND32 (b);
+
+  wR [BITS (5, 8)] += a * b;
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+TMIAPH (ARMul_State * state, ARMword instr)
+{
+  signed long a, b, result;
+  signed long long r;
+  ARMword Rm = state->Reg [BITS (0, 3)];
+  ARMword Rs = state->Reg [BITS (12, 15)];
+  
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmiaph\n");
+#endif  
+
+  if (BITS (0, 3) == 15 || BITS (12, 15) == 15)
+    {
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  a = SUBSTR (Rs, ARMword, 16, 31);
+  b = SUBSTR (Rm, ARMword, 16, 31);
+
+  a = EXTEND16 (a);
+  b = EXTEND16 (b);
+
+  result = a * b;
+
+  r = result;
+  r = EXTEND32 (r);
+  
+  wR [BITS (5, 8)] += r;
+
+  a = SUBSTR (Rs, ARMword,  0, 15);
+  b = SUBSTR (Rm, ARMword,  0, 15);
+
+  a = EXTEND16 (a);
+  b = EXTEND16 (b);
+
+  result = a * b;
+
+  r = result;
+  r = EXTEND32 (r);
+  
+  wR [BITS (5, 8)] += r;
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+TMIAxy (ARMul_State * state, ARMword instr)
+{
+  ARMword Rm;
+  ARMword Rs;
+  long long temp;
+  
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmiaxy\n");
+#endif  
+
+  if (BITS (0, 3) == 15 || BITS (12, 15) == 15)
+    {
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  Rm = state->Reg [BITS (0, 3)];
+  if (BIT (17))
+    Rm >>= 16;
+  else
+    Rm &= 0xffff;
+
+  Rs = state->Reg [BITS (12, 15)];
+  if (BIT (16))
+    Rs >>= 16;
+  else
+    Rs &= 0xffff;
+
+  if (Rm & (1 << 15))
+    Rm -= 1 << 16;
+
+  if (Rs & (1 << 15))
+    Rs -= 1 << 16;
+
+  Rm *= Rs;
+  temp = Rm;
+
+  if (temp & (1 << 31))
+    temp -= 1ULL << 32;
+
+  wR [BITS (5, 8)] += temp;
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+TMOVMSK (ARMul_State * state, ARMword instr)
+{
+  ARMdword result;
+  int      wRn;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmovmsk\n");
+#endif  
+
+  /* The CRm field must be r0.  */
+  if (BITS (0, 3) != 0)
+    return ARMul_CANT;
+
+  wRn = BITS (16, 19);
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      result = (  (wRBITS (wRn, 63, 63) << 7)
+               | (wRBITS (wRn, 55, 55) << 6)
+               | (wRBITS (wRn, 47, 47) << 5)
+               | (wRBITS (wRn, 39, 39) << 4)
+               | (wRBITS (wRn, 31, 31) << 3)
+               | (wRBITS (wRn, 23, 23) << 2)
+               | (wRBITS (wRn, 15, 15) << 1)
+               | (wRBITS (wRn,  7,  7) << 0));
+      break;
+
+    case Hqual:
+      result = (  (wRBITS (wRn, 63, 63) << 3)
+               | (wRBITS (wRn, 47, 47) << 2)
+               | (wRBITS (wRn, 31, 31) << 1)
+               | (wRBITS (wRn, 15, 15) << 0));
+      break;
+
+    case Wqual:
+      result = (wRBITS (wRn, 63, 63) << 1) | wRBITS (wRn, 31, 31);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  state->Reg [BITS (12, 15)] = result;
+
+  return ARMul_DONE;
+}
+
+static int
+TMRC (ARMul_State * state, ARMword instr)
+{
+  int reg = BITS (12, 15);
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmrc\n");
+#endif  
+
+  if (BITS (0, 3) != 0)
+    return ARMul_CANT;
+
+  if (reg == 15)
+    ARMul_UndefInstr (state, instr);
+  else
+    state->Reg [reg] = wC [BITS (16, 19)];
+
+  return ARMul_DONE;
+}
+
+static int
+TMRRC (ARMul_State * state, ARMword instr)
+{
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "tmrrc\n");
+#endif  
+
+  if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15) || (BITS (4, 11) != 0))
+    ARMul_UndefInstr (state, instr);
+  else
+    {
+      state->Reg [BITS (16, 19)] = wRBITS (BITS (0, 3), 32, 63);
+      state->Reg [BITS (12, 15)] = wRBITS (BITS (0, 3),  0, 31);
+    }
+
+  return ARMul_DONE;
+}
+
+static int
+TORC (ARMul_State * state, ARMword instr)
+{
+  ARMword cpsr = ARMul_GetCPSR (state);
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "torc\n");
+#endif  
+
+  /* The Rd field must be r15.  */
+  if (BITS (12, 15) != 15)
+    return ARMul_CANT;
+  
+  /* The CRn field must be r3.  */
+  if (BITS (16, 19) != 3)
+    return ARMul_CANT;
+  
+  /* The CRm field must be r0.  */
+  if (BITS (0, 3) != 0)
+    return ARMul_CANT;
+
+  cpsr &= 0x0fffffff;
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      cpsr |= (  (wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 24, 27)
+               | wCBITS (wCASF, 20, 23) | wCBITS (wCASF, 16, 19)
+               | wCBITS (wCASF, 12, 15) | wCBITS (wCASF,  8, 11)
+               | wCBITS (wCASF,  4,  7) | wCBITS (wCASF,  0,  3)) << 28);
+      break;
+
+    case Hqual:
+      cpsr |= (  (wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 20, 23)
+               | wCBITS (wCASF, 12, 15) | wCBITS (wCASF,  4,  7)) << 28);
+      break;
+
+    case Wqual:
+      cpsr |= ((wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 12, 15)) << 28);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+  
+  ARMul_SetCPSR (state, cpsr);
+
+  return ARMul_DONE;
+}
+
+static int
+WACC (ARMul_State * state, ARMword instr)
+{
+  int wRn;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wacc\n");
+#endif  
+
+  wRn = BITS (16, 19);
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      wR [BITS (12, 15)] =
+         wRBITS (wRn, 56, 63) + wRBITS (wRn, 48, 55)
+       + wRBITS (wRn, 40, 47) + wRBITS (wRn, 32, 39)
+       + wRBITS (wRn, 24, 31) + wRBITS (wRn, 16, 23)
+       + wRBITS (wRn,  8, 15) + wRBITS (wRn,  0,  7);
+      break;
+
+    case Hqual:
+      wR [BITS (12, 15)] =
+         wRBITS (wRn, 48, 63) + wRBITS (wRn, 32, 47)
+       + wRBITS (wRn, 16, 31) + wRBITS (wRn,  0, 15);
+      break;
+
+    case Wqual:
+      wR [BITS (12, 15)] = wRBITS (wRn, 32, 63) + wRBITS (wRn, 0, 31);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      break;
+    }
+
+  wC [wCon] |= WCON_MUP;
+  return ARMul_DONE;
+}
+
+static int
+WADD (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMdword x;
+  ARMdword s;
+  ARMword  psr = 0;
+  int      i;
+  int      carry;
+  int      overflow;
+  int      satrv[8];
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wadd\n");
+#endif  
+
+  /* Add two numbers using the specified function,
+     leaving setting the carry bit as required.  */
+#define ADDx(x, y, m, f) \
+   (*f) (wRBITS (BITS (16, 19), (x), (y)) & (m), \
+         wRBITS (BITS ( 0,  3), (x), (y)) & (m), \
+        & carry, & overflow)
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 8; i++)
+        {
+         switch (BITS (20, 21))
+           {
+           case NoSaturation:
+             s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddS8);
+             satrv [BITIDX8 (i)] = 0;
+             r |= (s & 0xff) << (i * 8);
+             SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i);
+             SIMD8_SET (psr, carry,     SIMD_CBIT, i);
+             SIMD8_SET (psr, overflow,  SIMD_VBIT, i);
+             break;
+
+           case UnsignedSaturation:
+             s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddU8);
+             x = IwmmxtSaturateU8 (s, satrv + BITIDX8 (i));
+             r |= (x & 0xff) << (i * 8);
+             SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX8 (i)])
+               {
+                 SIMD8_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD8_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           case SignedSaturation:
+             s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddS8);
+             x = IwmmxtSaturateS8 (s, satrv + BITIDX8 (i));
+             r |= (x & 0xff) << (i * 8);
+             SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX8 (i)])
+               {
+                 SIMD8_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD8_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+       }
+      break;
+
+    case Hqual:
+      satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0;
+
+      for (i = 0; i < 4; i++)
+       {
+         switch (BITS (20, 21))
+           {
+           case NoSaturation:
+             s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddS16);
+             satrv [BITIDX16 (i)] = 0;
+             r |= (s & 0xffff) << (i * 16);
+             SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+             SIMD16_SET (psr, carry,      SIMD_CBIT, i);
+             SIMD16_SET (psr, overflow,   SIMD_VBIT, i);
+             break;
+
+           case UnsignedSaturation:
+             s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddU16);
+             x = IwmmxtSaturateU16 (s, satrv + BITIDX16 (i));
+             r |= (x & 0xffff) << (i * 16);
+             SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX16 (i)])
+               {
+                 SIMD16_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD16_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           case SignedSaturation:
+             s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddS16);
+             x = IwmmxtSaturateS16 (s, satrv + BITIDX16 (i));
+             r |= (x & 0xffff) << (i * 16);
+             SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX16 (i)])
+               {
+                 SIMD16_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD16_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+       }
+      break;
+
+    case Wqual:
+      satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0;
+
+      for (i = 0; i < 2; i++)
+       {
+         switch (BITS (20, 21))
+           {
+           case NoSaturation:
+             s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddS32);
+             satrv [BITIDX32 (i)] = 0;
+             r |= (s & 0xffffffff) << (i * 32);
+             SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+             SIMD32_SET (psr, carry,      SIMD_CBIT, i);
+             SIMD32_SET (psr, overflow,   SIMD_VBIT, i);
+             break;
+
+           case UnsignedSaturation:
+             s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddU32);
+             x = IwmmxtSaturateU32 (s, satrv + BITIDX32 (i));
+             r |= (x & 0xffffffff) << (i * 32);
+             SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX32 (i)])
+               {
+                 SIMD32_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD32_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           case SignedSaturation:
+             s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddS32);
+             x = IwmmxtSaturateS32 (s, satrv + BITIDX32 (i));
+             r |= (x & 0xffffffff) << (i * 32);
+             SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX32 (i)])
+               {
+                 SIMD32_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD32_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+       }
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_MUP | WCON_CUP);
+
+  SET_wCSSFvec (satrv);
+  
+#undef ADDx
+
+  return ARMul_DONE;
+}
+
+static int
+WALIGNI (ARMword instr)
+{
+  int shift = BITS (20, 22) * 8;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "waligni\n");
+#endif  
+
+  if (shift)
+    wR [BITS (12, 15)] =
+      wRBITS (BITS (16, 19), shift, 63)
+      | (wRBITS (BITS (0, 3), 0, shift) << ((64 - shift)));
+  else
+    wR [BITS (12, 15)] = wR [BITS (16, 19)];
+          
+  wC [wCon] |= WCON_MUP;
+  return ARMul_DONE;
+}
+
+static int
+WALIGNR (ARMul_State * state, ARMword instr)
+{
+  int shift = (wC [BITS (20, 21) + 8] & 0x7) * 8;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "walignr\n");
+#endif  
+
+  if (shift)
+    wR [BITS (12, 15)] =
+      wRBITS (BITS (16, 19), shift, 63)
+      | (wRBITS (BITS (0, 3), 0, shift) << ((64 - shift)));
+  else
+    wR [BITS (12, 15)] = wR [BITS (16, 19)];
+
+  wC [wCon] |= WCON_MUP;
+  return ARMul_DONE;
+}
+
+static int
+WAND (ARMword instr)
+{
+  ARMdword result;
+  ARMword  psr = 0;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wand\n");
+#endif  
+
+  result = wR [BITS (16, 19)] & wR [BITS (0, 3)];
+  wR [BITS (12, 15)] = result;
+
+  SIMD64_SET (psr, (result == 0), SIMD_ZBIT);
+  SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT);
+  
+  wC [wCASF] = psr;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WANDN (ARMword instr)
+{
+  ARMdword result;
+  ARMword  psr = 0;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wandn\n");
+#endif  
+
+  result = wR [BITS (16, 19)] & ~ wR [BITS (0, 3)];
+  wR [BITS (12, 15)] = result;
+
+  SIMD64_SET (psr, (result == 0), SIMD_ZBIT);
+  SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT);
+  
+  wC [wCASF] = psr;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WAVG2 (ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+  int      round = BIT (20) ? 1 : 0;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wavg2\n");
+#endif  
+
+#define AVG2x(x, y, m) (((wRBITS (BITS (16, 19), (x), (y)) & (m)) \
+                      + (wRBITS (BITS ( 0,  3), (x), (y)) & (m)) \
+                      + round) / 2)
+
+  if (BIT (22))
+    {
+      for (i = 0; i < 4; i++)
+       {
+         s = AVG2x ((i * 16), (i * 16) + 15, 0xffff) & 0xffff;
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+         r |= s << (i * 16);
+       }
+    }
+  else
+    {
+      for (i = 0; i < 8; i++)
+       {
+         s = AVG2x ((i * 8), (i * 8) + 7, 0xff) & 0xff;
+         SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i);
+         r |= s << (i * 8);
+       }
+    }
+
+  wR [BITS (12, 15)] = r;
+  wC [wCASF] = psr;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WCMPEQ (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wcmpeq\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 8; i++)
+       {
+         s = wRBYTE (BITS (16, 19), i) == wRBYTE (BITS (0, 3), i) ? 0xff : 0;
+         r |= s << (i * 8);
+         SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i);
+         SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Hqual:
+      for (i = 0; i < 4; i++)
+       {
+         s = wRHALF (BITS (16, 19), i) == wRHALF (BITS (0, 3), i) ? 0xffff : 0;
+         r |= s << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      for (i = 0; i < 2; i++)
+       {
+         s = wRWORD (BITS (16, 19), i) == wRWORD (BITS (0, 3), i) ? 0xffffffff : 0;
+         r |= s << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WCMPGT (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wcmpgt\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      if (BIT (21))
+       {
+         /* Use a signed comparison.  */
+         for (i = 0; i < 8; i++)
+           {
+             signed char a, b;
+             
+             a = wRBYTE (BITS (16, 19), i);
+             b = wRBYTE (BITS (0, 3), i);
+
+             s = (a > b) ? 0xff : 0;
+             r |= s << (i * 8);
+             SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i);
+           }
+       }
+      else
+       {
+         for (i = 0; i < 8; i++)
+           {
+             s = (wRBYTE (BITS (16, 19), i) > wRBYTE (BITS (0, 3), i))
+               ? 0xff : 0;
+             r |= s << (i * 8);
+             SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i);
+           }
+       }
+      break;
+
+    case Hqual:
+      if (BIT (21))
+       {
+         for (i = 0; i < 4; i++)
+           {
+             signed int a, b;
+
+             a = wRHALF (BITS (16, 19), i);
+             a = EXTEND16 (a);
+
+             b = wRHALF (BITS (0, 3), i);
+             b = EXTEND16 (b);
+
+             s = (a > b) ? 0xffff : 0;         
+             r |= s << (i * 16);
+             SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+           }
+       }
+      else
+       {
+         for (i = 0; i < 4; i++)
+           {
+             s = (wRHALF (BITS (16, 19), i) > wRHALF (BITS (0, 3), i))
+               ? 0xffff : 0;
+             r |= s << (i * 16);
+             SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+           }
+       }
+      break;
+
+    case Wqual:
+      if (BIT (21))
+       {
+         for (i = 0; i < 2; i++)
+           {
+             signed long a, b;
+
+             a = wRWORD (BITS (16, 19), i);
+             b = wRWORD (BITS (0, 3), i);
+
+             s = (a > b) ? 0xffffffff : 0;
+             r |= s << (i * 32);
+             SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+           }
+       }
+      else
+       {
+         for (i = 0; i < 2; i++)
+           {
+             s = (wRWORD (BITS (16, 19), i) > wRWORD (BITS (0, 3), i))
+               ? 0xffffffff : 0;
+             r |= s << (i * 32);
+             SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+           }
+       }
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static ARMword
+Compute_Iwmmxt_Address (ARMul_State * state, ARMword instr, int * pFailed)
+{
+  ARMword  Rn;
+  ARMword  addr;
+  ARMword  offset;
+  ARMword  multiplier;
+
+  * pFailed  = 0;
+  Rn         = BITS (16, 19);
+  addr       = state->Reg [Rn];
+  offset     = BITS (0, 7);
+  multiplier = BIT (8) ? 4 : 1;
+
+  if (BIT (24)) /* P */
+    {
+      /* Pre Indexed Addressing.  */
+      if (BIT (23))
+       addr += offset * multiplier;
+      else
+       addr -= offset * multiplier;
+
+      /* Immediate Pre-Indexed.  */
+      if (BIT (21)) /* W */
+       {
+         if (Rn == 15)
+           {
+             /* Writeback into R15 is UNPREDICTABLE.  */
+#ifdef DEBUG
+             fprintf (stderr, "iWMMXt: writeback into r15\n");
+#endif
+             * pFailed = 1;
+           }
+         else
+           state->Reg [Rn] = addr;
+       }
+    }
+  else
+    {
+      /* Post Indexed Addressing.  */
+      if (BIT (21)) /* W */
+       {
+         /* Handle the write back of the final address.  */
+         if (Rn == 15)
+           {
+             /* Writeback into R15 is UNPREDICTABLE.  */
+#ifdef DEBUG
+             fprintf (stderr, "iWMMXt: writeback into r15\n");
+#endif  
+             * pFailed = 1;
+           }
+         else
+           {
+             ARMword  increment;
+
+             if (BIT (23))
+               increment = offset * multiplier;
+             else
+               increment = - (offset * multiplier);
+
+             state->Reg [Rn] = addr + increment;
+           }
+       }
+      else
+       {
+         /* P == 0, W == 0, U == 0 is UNPREDICTABLE.  */
+         if (BIT (23) == 0)
+           {
+#ifdef DEBUG
+             fprintf (stderr, "iWMMXt: undefined addressing mode\n");
+#endif  
+             * pFailed = 1;
+           }
+       }
+    }
+
+  return addr;
+}
+
+static ARMdword
+Iwmmxt_Load_Double_Word (ARMul_State * state, ARMword address)
+{
+  ARMdword value;
+  
+  /* The address must be aligned on a 8 byte boundary.  */
+  if (address & 0x7)
+    {
+      fprintf (stderr, "iWMMXt: At addr 0x%x: Unaligned double word load from 0x%x\n",
+              (state->Reg[15] - 8) & ~0x3, address);
+#ifdef DEBUG
+#endif
+      /* No need to check for alignment traps.  An unaligned
+        double word load with alignment trapping disabled is
+        UNPREDICTABLE.  */
+      ARMul_Abort (state, ARMul_DataAbortV);
+    }
+
+  /* Load the words.  */
+  if (! state->bigendSig)
+    {
+      value = ARMul_LoadWordN (state, address + 4);
+      value <<= 32;
+      value |= ARMul_LoadWordN (state, address);
+    }
+  else
+    {
+      value = ARMul_LoadWordN (state, address);
+      value <<= 32;
+      value |= ARMul_LoadWordN (state, address + 4);
+    }
+
+  /* Check for data aborts.  */
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+  else
+    ARMul_Icycles (state, 2, 0L);
+
+  return value;
+}
+
+static ARMword
+Iwmmxt_Load_Word (ARMul_State * state, ARMword address)
+{
+  ARMword value;
+
+  /* Check for a misaligned address.  */
+  if (address & 3)
+    {
+      if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN))
+       ARMul_Abort (state, ARMul_DataAbortV);
+      else
+       address &= ~ 3;
+    }
+  
+  value = ARMul_LoadWordN (state, address);
+
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+  else
+    ARMul_Icycles (state, 1, 0L);
+
+  return value;
+}
+
+static ARMword
+Iwmmxt_Load_Half_Word (ARMul_State * state, ARMword address)
+{
+  ARMword value;
+
+  /* Check for a misaligned address.  */
+  if (address & 1)
+    {
+      if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN))
+       ARMul_Abort (state, ARMul_DataAbortV);
+      else
+       address &= ~ 1;
+    }
+
+  value = ARMul_LoadHalfWord (state, address);
+
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+  else
+    ARMul_Icycles (state, 1, 0L);
+
+  return value;
+}
+
+static ARMword
+Iwmmxt_Load_Byte (ARMul_State * state, ARMword address)
+{
+  ARMword value;
+
+  value = ARMul_LoadByte (state, address);
+
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+  else
+    ARMul_Icycles (state, 1, 0L);
+
+  return value;
+}
+
+static void
+Iwmmxt_Store_Double_Word (ARMul_State * state, ARMword address, ARMdword value)
+{
+  /* The address must be aligned on a 8 byte boundary.  */
+  if (address & 0x7)
+    {
+      fprintf (stderr, "iWMMXt: At addr 0x%x: Unaligned double word store to 0x%x\n",
+              (state->Reg[15] - 8) & ~0x3, address);
+#ifdef DEBUG
+#endif
+      /* No need to check for alignment traps.  An unaligned
+        double word store with alignment trapping disabled is
+        UNPREDICTABLE.  */
+      ARMul_Abort (state, ARMul_DataAbortV);
+    }
+
+  /* Store the words.  */
+  if (! state->bigendSig)
+    {
+      ARMul_StoreWordN (state, address, value);
+      ARMul_StoreWordN (state, address + 4, value >> 32);
+    }
+  else
+    {
+      ARMul_StoreWordN (state, address + 4, value);
+      ARMul_StoreWordN (state, address, value >> 32);
+    }
+
+  /* Check for data aborts.  */
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+  else
+    ARMul_Icycles (state, 2, 0L);
+}
+
+static void
+Iwmmxt_Store_Word (ARMul_State * state, ARMword address, ARMword value)
+{
+  /* Check for a misaligned address.  */
+  if (address & 3)
+    {
+      if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN))
+       ARMul_Abort (state, ARMul_DataAbortV);
+      else
+       address &= ~ 3;
+    }
+
+  ARMul_StoreWordN (state, address, value);
+
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+}
+
+static void
+Iwmmxt_Store_Half_Word (ARMul_State * state, ARMword address, ARMword value)
+{
+  /* Check for a misaligned address.  */
+  if (address & 1)
+    {
+      if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN))
+       ARMul_Abort (state, ARMul_DataAbortV);
+      else
+       address &= ~ 1;
+    }
+
+  ARMul_StoreHalfWord (state, address, value);
+
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+}
+
+static void
+Iwmmxt_Store_Byte (ARMul_State * state, ARMword address, ARMword value)
+{
+  ARMul_StoreByte (state, address, value);
+
+  if (state->Aborted)
+    ARMul_Abort (state, ARMul_DataAbortV);
+}
+
+static int
+WLDR (ARMul_State * state, ARMword instr)
+{
+  ARMword address;
+  int failed;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wldr\n");
+#endif  
+
+  address = Compute_Iwmmxt_Address (state, instr, & failed);
+  if (failed)
+    return ARMul_CANT;
+
+  if (BITS (28, 31) == 0xf)
+    {
+      /* WLDRW wCx */
+      wC [BITS (12, 15)] = Iwmmxt_Load_Word (state, address);
+    }
+  else if (BIT (8) == 0)
+    {
+      if (BIT (22) == 0)
+       /* WLDRB */
+       wR [BITS (12, 15)] = Iwmmxt_Load_Byte (state, address);
+      else
+       /* WLDRH */
+       wR [BITS (12, 15)] = Iwmmxt_Load_Half_Word (state, address);
+    }
+  else
+    {
+      if (BIT (22) == 0)
+       /* WLDRW wRd */
+       wR [BITS (12, 15)] = Iwmmxt_Load_Word (state, address);
+      else
+       /* WLDRD */
+       wR [BITS (12, 15)] = Iwmmxt_Load_Double_Word (state, address);
+    }
+
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+WMAC (ARMword instr)
+{
+  int      i;
+  ARMdword t = 0;
+  ARMword  a, b;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wmac\n");
+#endif  
+
+  for (i = 0; i < 4; i++)
+    {
+      if (BIT (21))
+        {
+         /* Signed.  */
+         signed long s;
+
+         a = wRHALF (BITS (16, 19), i);
+         a = EXTEND16 (a);
+
+         b = wRHALF (BITS (0, 3), i);
+         b = EXTEND16 (b);
+
+         s = (signed long) a * (signed long) b;
+
+         (signed long long) t += s;
+        }
+      else
+        {
+         /* Unsigned.  */
+         a = wRHALF (BITS (16, 19), i);
+         b = wRHALF (BITS ( 0,  3), i);
+
+         t += a * b;
+        }
+    }
+
+  if (BIT (20))
+    wR [BITS (12, 15)] = 0;
+
+  if (BIT (21))        /* Signed.  */
+    (signed long long) wR[BITS (12, 15)] += (signed long long) t;
+  else
+    wR [BITS (12, 15)] += t;
+
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+WMADD (ARMword instr)
+{
+  ARMdword r = 0;
+  int i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wmadd\n");
+#endif  
+
+  for (i = 0; i < 2; i++)
+    {
+      ARMdword s1, s2;
+
+      if (BIT (21))    /* Signed.  */
+        {
+         signed long a, b;
+
+         a = wRHALF (BITS (16, 19), i * 2);
+         a = EXTEND16 (a);
+
+         b = wRHALF (BITS (0, 3), i * 2);
+         b = EXTEND16 (b);
+
+         (signed long) s1 = a * b;
+
+         a = wRHALF (BITS (16, 19), i * 2 + 1);
+         a = EXTEND16 (a);
+
+         b = wRHALF (BITS (0, 3), i * 2 + 1);
+         b = EXTEND16 (b);
+
+         (signed long) s2 = a * b;
+        }
+      else                     /* Unsigned.  */
+        {
+         unsigned long a, b;
+
+         a = wRHALF (BITS (16, 19), i * 2);
+         b = wRHALF (BITS ( 0,  3), i * 2);
+
+         (unsigned long) s1 = a * b;
+
+         a = wRHALF (BITS (16, 19), i * 2 + 1);
+         b = wRHALF (BITS ( 0,  3), i * 2 + 1);
+
+         (signed long) s2 = a * b;
+        }
+
+      r |= (ARMdword) ((s1 + s2) & 0xffffffff) << (i ? 32 : 0);
+    }
+
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+WMAX (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wmax\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 8; i++)
+       if (BIT (21))   /* Signed.  */
+         {
+           int a, b;
+
+           a = wRBYTE (BITS (16, 19), i);
+           a = EXTEND8 (a);
+
+           b = wRBYTE (BITS (0, 3), i);
+           b = EXTEND8 (b);
+
+           if (a > b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xff) << (i * 8);
+         }
+       else            /* Unsigned.  */
+         {
+           unsigned int a, b;
+
+           a = wRBYTE (BITS (16, 19), i);
+           b = wRBYTE (BITS (0, 3), i);
+
+           if (a > b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xff) << (i * 8);
+          }
+      break;
+
+    case Hqual:
+      for (i = 0; i < 4; i++)
+       if (BIT (21))   /* Signed.  */
+         {
+           int a, b;
+
+           a = wRHALF (BITS (16, 19), i);
+           a = EXTEND16 (a);
+
+           b = wRHALF (BITS (0, 3), i);
+           b = EXTEND16 (b);
+
+           if (a > b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffff) << (i * 16);
+         }
+       else            /* Unsigned.  */
+         {
+           unsigned int a, b;
+
+           a = wRHALF (BITS (16, 19), i);
+           b = wRHALF (BITS (0, 3), i);
+
+           if (a > b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffff) << (i * 16);
+          }
+      break;
+
+    case Wqual:
+      for (i = 0; i < 2; i++)
+       if (BIT (21))   /* Signed.  */
+         {
+           int a, b;
+
+           a = wRWORD (BITS (16, 19), i);
+           b = wRWORD (BITS (0, 3), i);
+
+           if (a > b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffffffff) << (i * 32);
+         }
+       else
+         {
+           unsigned int a, b;
+
+           a = wRWORD (BITS (16, 19), i);
+           b = wRWORD (BITS (0, 3), i);
+
+           if (a > b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffffffff) << (i * 32);
+          }
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+WMIN (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wmin\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 8; i++)
+       if (BIT (21))   /* Signed.  */
+         {
+           int a, b;
+
+           a = wRBYTE (BITS (16, 19), i);
+           a = EXTEND8 (a);
+
+           b = wRBYTE (BITS (0, 3), i);
+           b = EXTEND8 (b);
+
+           if (a < b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xff) << (i * 8);
+         }
+       else            /* Unsigned.  */
+         {
+           unsigned int a, b;
+
+           a = wRBYTE (BITS (16, 19), i);
+           b = wRBYTE (BITS (0, 3), i);
+
+           if (a < b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xff) << (i * 8);
+          }
+      break;
+
+    case Hqual:
+      for (i = 0; i < 4; i++)
+       if (BIT (21))   /* Signed.  */
+         {
+           int a, b;
+
+           a = wRHALF (BITS (16, 19), i);
+           a = EXTEND16 (a);
+
+           b = wRHALF (BITS (0, 3), i);
+           b = EXTEND16 (b);
+
+           if (a < b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffff) << (i * 16);
+         }
+       else
+         {
+           /* Unsigned.  */
+           unsigned int a, b;
+
+           a = wRHALF (BITS (16, 19), i);
+           b = wRHALF (BITS ( 0,  3), i);
+
+           if (a < b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffff) << (i * 16);
+          }
+      break;
+
+    case Wqual:
+      for (i = 0; i < 2; i++)
+       if (BIT (21))   /* Signed.  */
+         {
+           int a, b;
+
+           a = wRWORD (BITS (16, 19), i);
+           b = wRWORD (BITS ( 0,  3), i);
+
+           if (a < b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffffffff) << (i * 32);
+         }
+       else
+         {
+           unsigned int a, b;
+
+           a = wRWORD (BITS (16, 19), i);
+           b = wRWORD (BITS (0, 3), i);
+
+           if (a < b)
+             s = a;
+           else
+             s = b;
+
+           r |= (s & 0xffffffff) << (i * 32);
+          }
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= WCON_MUP;
+  
+  return ARMul_DONE;
+}
+
+static int
+WMUL (ARMword instr)
+{
+  ARMdword r = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wmul\n");
+#endif  
+
+  for (i = 0; i < 4; i++)
+    if (BIT (21))      /* Signed.  */
+      {
+       long a, b;
+
+       a = wRHALF (BITS (16, 19), i);
+       a = EXTEND16 (a);
+
+       b = wRHALF (BITS (0, 3), i);
+       b = EXTEND16 (b);
+
+       s = a * b;
+
+       if (BIT (20))
+         r |= ((s >> 16) & 0xffff) << (i * 16);
+       else
+         r |= (s & 0xffff) << (i * 16);
+      }
+    else               /* Unsigned.  */
+      {
+       unsigned long a, b;
+
+       a = wRHALF (BITS (16, 19), i);
+       b = wRHALF (BITS (0, 3), i);
+
+       s = a * b;
+
+       if (BIT (20))
+         r |= ((s >> 16) & 0xffff) << (i * 16);
+       else
+         r |= (s & 0xffff) << (i * 16);
+      }
+
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+WOR (ARMword instr)
+{
+  ARMword psr = 0;
+  ARMdword result;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wor\n");
+#endif  
+
+  result = wR [BITS (16, 19)] | wR [BITS (0, 3)];
+  wR [BITS (12, 15)] = result;
+
+  SIMD64_SET (psr, (result == 0), SIMD_ZBIT);
+  SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT);
+  
+  wC [wCASF] = psr;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WPACK (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword x;
+  ARMdword s;
+  int      i;
+  int      satrv[8];
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wpack\n");
+#endif  
+  switch (BITS (22, 23))
+    {
+    case Hqual:
+      for (i = 0; i < 8; i++)
+       {
+         x = wRHALF (i < 4 ? BITS (16, 19) : BITS (0, 3), i & 3);
+
+         switch (BITS (20, 21))
+           {
+           case UnsignedSaturation:
+             s = IwmmxtSaturateU8 (x, satrv + BITIDX8 (i));
+             break;
+
+           case SignedSaturation:
+             s = IwmmxtSaturateS8 (x, satrv + BITIDX8 (i));
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+
+         r |= (s & 0xff) << (i * 8);
+         SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i);
+         SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0;
+
+      for (i = 0; i < 4; i++)
+       {
+         x = wRWORD (i < 2 ? BITS (16, 19) : BITS (0, 3), i & 1);
+
+         switch (BITS (20, 21))
+           {
+           case UnsignedSaturation:
+             s = IwmmxtSaturateU16 (x, satrv + BITIDX16 (i));
+             break;
+
+           case SignedSaturation:
+             s = IwmmxtSaturateS16 (x, satrv + BITIDX16 (i));
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+
+         r |= (s & 0xffff) << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Dqual:
+      satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0;
+
+      for (i = 0; i < 2; i++)
+       {
+         x = wR [i ? BITS (0, 3) : BITS (16, 19)];
+
+         switch (BITS (20, 21))
+           {
+           case UnsignedSaturation:
+             s = IwmmxtSaturateU32 (x, satrv + BITIDX32 (i));
+             break;
+
+           case SignedSaturation:
+             s = IwmmxtSaturateS32 (x, satrv + BITIDX32 (i));
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  SET_wCSSFvec (satrv);
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WROR (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMdword s;
+  ARMword  psr = 0;
+  int      i;
+  int      shift;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wror\n");
+#endif  
+
+  DECODE_G_BIT (state, instr, shift);
+
+  switch (BITS (22, 23))
+    {
+    case Hqual:
+      shift &= 0xf;
+      for (i = 0; i < 4; i++)
+       {
+         s = ((wRHALF (BITS (16, 19), i) & 0xffff) << (16 - shift))
+           | ((wRHALF (BITS (16, 19), i) & 0xffff) >> shift);
+         r |= (s & 0xffff) << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      shift &= 0x1f;
+      for (i = 0; i < 2; i++)
+       {
+         s = ((wRWORD (BITS (16, 19), i) & 0xffffffff) << (32 - shift))
+           | ((wRWORD (BITS (16, 19), i) & 0xffffffff) >> shift);
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Dqual:
+      shift &= 0x3f;
+      r = (wR [BITS (16, 19)] >> shift)
+       | (wR [BITS (16, 19)] << (64 - shift));
+
+      SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT);
+      SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WSAD (ARMword instr)
+{
+  ARMdword r;
+  int      s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wsad\n");
+#endif  
+
+  /* Z bit.  */
+  r = BIT (20) ? 0 : (wR [BITS (12, 15)] & 0xffffffff);
+
+  if (BIT (22))
+    /* Half.  */
+    for (i = 0; i < 4; i++)
+      {
+       s = (wRHALF (BITS (16, 19), i) - wRHALF (BITS (0, 3), i));
+       r += abs (s);
+      }
+  else
+    /* Byte.  */
+    for (i = 0; i < 8; i++)
+      {
+       s = (wRBYTE (BITS (16, 19), i) - wRBYTE (BITS (0, 3), i));
+       r += abs (s);
+      }
+
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= WCON_MUP;
+
+  return ARMul_DONE;
+}
+
+static int
+WSHUFH (ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+  int      imm8;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wshufh\n");
+#endif  
+
+  imm8 = (BITS (20, 23) << 4) | BITS (0, 3);
+
+  for (i = 0; i < 4; i++)
+    {
+      s = wRHALF (BITS (16, 19), ((imm8 >> (i * 2) & 3)) & 0xff);
+      r |= (s & 0xffff) << (i * 16);
+      SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+      SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WSLL (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMdword s;
+  ARMword  psr = 0;
+  int      i;
+  unsigned shift;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wsll\n");
+#endif  
+
+  DECODE_G_BIT (state, instr, shift);
+
+  switch (BITS (22, 23))
+    {
+    case Hqual:
+      for (i = 0; i < 4; i++)
+       {
+         if (shift > 15)
+           s = 0;
+         else
+           s = ((wRHALF (BITS (16, 19), i) & 0xffff) << shift);
+         r |= (s & 0xffff) << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      for (i = 0; i < 2; i++)
+       {
+         if (shift > 31)
+           s = 0;
+         else
+           s = ((wRWORD (BITS (16, 19), i) & 0xffffffff) << shift);
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Dqual:
+      if (shift > 63)
+       r = 0;
+      else
+       r = ((wR[BITS (16, 19)] & 0xffffffffffffffff) << shift);
+
+      SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT);
+      SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WSRA (ARMul_State * state, ARMword instr)
+{
+  ARMdword     r = 0;
+  ARMdword     s;
+  ARMword      psr = 0;
+  int          i;
+  unsigned     shift;
+  signed long  t;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wsra\n");
+#endif  
+
+  DECODE_G_BIT (state, instr, shift);
+
+  switch (BITS (22, 23))
+    {
+    case Hqual:
+      for (i = 0; i < 4; i++)
+       {
+         if (shift > 15)
+           t = (wRHALF (BITS (16, 19), i) & 0x8000) ? 0xffff : 0;
+         else
+           {
+             t = wRHALF (BITS (16, 19), i);
+             t = EXTEND16 (t);
+             t >>= shift;
+           }
+
+         s = t;
+         r |= (s & 0xffff) << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      for (i = 0; i < 2; i++)
+       {
+         if (shift > 31)
+           t = (wRWORD (BITS (16, 19), i) & 0x80000000) ? 0xffffffff : 0;
+         else
+           {
+             t = wRWORD (BITS (16, 19), i);
+             t >>= shift;
+           }
+         s = t;
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+      
+    case Dqual:
+      if (shift > 63)
+       r = (wR [BITS (16, 19)] & 0x8000000000000000) ? 0xffffffffffffffff : 0;
+      else
+       r = ((signed long long) (wR[BITS (16, 19)] & 0xffffffffffffffff) >> shift);
+      SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT);
+      SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WSRL (ARMul_State * state, ARMword instr)
+{
+  ARMdword     r = 0;
+  ARMdword     s;
+  ARMword      psr = 0;
+  int          i;
+  unsigned int shift;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wsrl\n");
+#endif
+
+  DECODE_G_BIT (state, instr, shift);
+
+  switch (BITS (22, 23))
+    {
+    case Hqual:
+      for (i = 0; i < 4; i++)
+       {
+         if (shift > 15)
+           s = 0;
+         else
+           s = ((unsigned) (wRHALF (BITS (16, 19), i) & 0xffff) >> shift);
+
+         r |= (s & 0xffff) << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      for (i = 0; i < 2; i++)
+       {
+         if (shift > 31)
+           s = 0;
+         else
+           s = ((unsigned long) (wRWORD (BITS (16, 19), i) & 0xffffffff) >> shift);
+
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Dqual:
+      if (shift > 63)
+       r = 0;
+      else
+       r = (wR [BITS (16, 19)] & 0xffffffffffffffff) >> shift;
+
+      SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT);
+      SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WSTR (ARMul_State * state, ARMword instr)
+{
+  ARMword address;
+  int failed;
+
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wstr\n");
+#endif
+  
+  address = Compute_Iwmmxt_Address (state, instr, & failed);
+  if (failed)
+    return ARMul_CANT;
+
+  if (BITS (28, 31) == 0xf)
+    {
+      /* WSTRW wCx */
+      Iwmmxt_Store_Word (state, address, wC [BITS (12, 15)]);
+    }
+  else if (BIT (8) == 0)
+    {
+      if (BIT (22) == 0)
+       /* WSTRB */
+       Iwmmxt_Store_Byte (state, address, wR [BITS (12, 15)]);
+      else
+       /* WSTRH */
+       Iwmmxt_Store_Half_Word (state, address, wR [BITS (12, 15)]);
+    }
+  else
+    {
+      if (BIT (22) == 0)
+       /* WSTRW wRd */
+       Iwmmxt_Store_Word (state, address, wR [BITS (12, 15)]);
+      else
+       /* WSTRD */
+       Iwmmxt_Store_Double_Word (state, address, wR [BITS (12, 15)]);
+    }
+
+  return ARMul_DONE;
+}
+
+static int
+WSUB (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword x;
+  ARMdword s;
+  int      i;
+  int      carry;
+  int      overflow;
+  int      satrv[8];
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wsub\n");
+#endif  
+
+/* Subtract two numbers using the specified function,
+   leaving setting the carry bit as required.  */
+#define SUBx(x, y, m, f) \
+   (*f) (wRBITS (BITS (16, 19), (x), (y)) & (m), \
+         wRBITS (BITS ( 0,  3), (x), (y)) & (m), & carry, & overflow)
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 8; i++)
+        {
+         switch (BITS (20, 21))
+           {
+           case NoSaturation:
+             s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubS8);
+             satrv [BITIDX8 (i)] = 0;
+             r |= (s & 0xff) << (i * 8);
+             SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i);
+             SIMD8_SET (psr, carry, SIMD_CBIT, i);
+             SIMD8_SET (psr, overflow, SIMD_VBIT, i);
+             break;
+
+           case UnsignedSaturation:
+             s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubU8);
+             x = IwmmxtSaturateU8 (s, satrv + BITIDX8 (i));
+             r |= (x & 0xff) << (i * 8);
+             SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX8 (i)])
+               {
+                 SIMD8_SET (psr, carry,     SIMD_CBIT, i);
+                 SIMD8_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           case SignedSaturation:
+             s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubS8);
+             x = IwmmxtSaturateS8 (s, satrv + BITIDX8 (i));
+             r |= (x & 0xff) << (i * 8);
+             SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i);
+             SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX8 (i)])
+               {
+                 SIMD8_SET (psr, carry,     SIMD_CBIT, i);
+                 SIMD8_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+       }
+      break;
+
+    case Hqual:
+      satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0;
+
+      for (i = 0; i < 4; i++)
+       {
+         switch (BITS (20, 21))
+           {
+           case NoSaturation:
+             s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubU16);
+             satrv [BITIDX16 (i)] = 0;
+             r |= (s & 0xffff) << (i * 16);
+             SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+             SIMD16_SET (psr, carry,      SIMD_CBIT, i);
+             SIMD16_SET (psr, overflow,   SIMD_VBIT, i);
+             break;
+
+           case UnsignedSaturation:
+             s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubU16);
+             x = IwmmxtSaturateU16 (s, satrv + BITIDX16 (i));
+             r |= (x & 0xffff) << (i * 16);
+             SIMD16_SET (psr, NBIT16 (x & 0xffff), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX16 (i)])
+               {
+                 SIMD16_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD16_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           case SignedSaturation:
+             s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubS16);
+             x = IwmmxtSaturateS16 (s, satrv + BITIDX16 (i));
+             r |= (x & 0xffff) << (i * 16);
+             SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i);
+             SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX16 (i)])
+               {
+                 SIMD16_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD16_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+       }
+      break;
+
+    case Wqual:
+      satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0;
+
+      for (i = 0; i < 2; i++)
+       {
+         switch (BITS (20, 21))
+           {
+           case NoSaturation:
+             s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubU32);
+             satrv[BITIDX32 (i)] = 0;
+             r |= (s & 0xffffffff) << (i * 32);
+             SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+             SIMD32_SET (psr, carry,      SIMD_CBIT, i);
+             SIMD32_SET (psr, overflow,   SIMD_VBIT, i);
+             break;
+
+           case UnsignedSaturation:
+             s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubU32);
+             x = IwmmxtSaturateU32 (s, satrv + BITIDX32 (i));
+             r |= (x & 0xffffffff) << (i * 32);
+             SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX32 (i)])
+               {
+                 SIMD32_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD32_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           case SignedSaturation:
+             s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubS32);
+             x = IwmmxtSaturateS32 (s, satrv + BITIDX32 (i));
+             r |= (x & 0xffffffff) << (i * 32);
+             SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i);
+             SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i);
+             if (! satrv [BITIDX32 (i)])
+               {
+                 SIMD32_SET (psr, carry,    SIMD_CBIT, i);
+                 SIMD32_SET (psr, overflow, SIMD_VBIT, i);
+               }
+             break;
+
+           default:
+             ARMul_UndefInstr (state, instr);
+             return ARMul_DONE;
+           }
+       }
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wR [BITS (12, 15)] = r;
+  wC [wCASF] = psr;
+  SET_wCSSFvec (satrv);
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+#undef SUBx
+
+  return ARMul_DONE;
+}
+
+static int
+WUNPCKEH (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wunpckeh\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 4; i++)
+       {
+         s = wRBYTE (BITS (16, 19), i + 4);
+
+         if (BIT (21) && NBIT8 (s))
+           s |= 0xff00;
+
+         r |= (s & 0xffff) << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Hqual:
+      for (i = 0; i < 2; i++)
+       {
+         s = wRHALF (BITS (16, 19), i + 2);
+
+         if (BIT (21) && NBIT16 (s))
+           s |= 0xffff0000;
+
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      r = wRWORD (BITS (16, 19), 1);
+
+      if (BIT (21) && NBIT32 (r))
+       r |= 0xffffffff00000000;
+
+      SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT);
+      SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WUNPCKEL (ARMul_State * state, ARMword instr)
+{
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wunpckel\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 4; i++)
+       {
+         s = wRBYTE (BITS (16, 19), i);
+
+         if (BIT (21) && NBIT8 (s))
+           s |= 0xff00;
+
+         r |= (s & 0xffff) << (i * 16);
+         SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i);
+         SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Hqual:
+      for (i = 0; i < 2; i++)
+       {
+         s = wRHALF (BITS (16, 19), i);
+
+         if (BIT (21) && NBIT16 (s))
+           s |= 0xffff0000;
+
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i);
+         SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i);
+       }
+      break;
+
+    case Wqual:
+      r = wRWORD (BITS (16, 19), 0);
+
+      if (BIT (21) && NBIT32 (r))
+       r |= 0xffffffff00000000;
+
+      SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT);
+      SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WUNPCKIH (ARMul_State * state, ARMword instr)
+{
+  ARMword  a, b;
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wunpckih\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 4; i++)
+       {
+         a = wRBYTE (BITS (16, 19), i + 4);
+         b = wRBYTE (BITS ( 0,  3), i + 4);
+         s = a | (b << 8);
+         r |= (s & 0xffff) << (i * 16);
+         SIMD8_SET (psr, NBIT8 (a), SIMD_NBIT, i * 2);
+         SIMD8_SET (psr, ZBIT8 (a), SIMD_ZBIT, i * 2);
+         SIMD8_SET (psr, NBIT8 (b), SIMD_NBIT, (i * 2) + 1);
+         SIMD8_SET (psr, ZBIT8 (b), SIMD_ZBIT, (i * 2) + 1);
+       }
+      break;
+      
+    case Hqual:
+      for (i = 0; i < 2; i++)
+       {
+         a = wRHALF (BITS (16, 19), i + 2);
+         b = wRHALF (BITS ( 0,  3), i + 2);
+         s = a | (b << 16);
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD16_SET (psr, NBIT16 (a), SIMD_NBIT, (i * 2));
+         SIMD16_SET (psr, ZBIT16 (a), SIMD_ZBIT, (i * 2));
+         SIMD16_SET (psr, NBIT16 (b), SIMD_NBIT, (i * 2) + 1);
+         SIMD16_SET (psr, ZBIT16 (b), SIMD_ZBIT, (i * 2) + 1);
+       }
+      break;
+
+    case Wqual:
+      a = wRWORD (BITS (16, 19), 1);
+      s = wRWORD (BITS ( 0,  3), 1);
+      r = a | (s << 32);
+
+      SIMD32_SET (psr, NBIT32 (a), SIMD_NBIT, 0);
+      SIMD32_SET (psr, ZBIT32 (a), SIMD_ZBIT, 0);
+      SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, 1);
+      SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, 1);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WUNPCKIL (ARMul_State * state, ARMword instr)
+{
+  ARMword  a, b;
+  ARMdword r = 0;
+  ARMword  psr = 0;
+  ARMdword s;
+  int      i;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wunpckil\n");
+#endif  
+
+  switch (BITS (22, 23))
+    {
+    case Bqual:
+      for (i = 0; i < 4; i++)
+       {
+         a = wRBYTE (BITS (16, 19), i);
+         b = wRBYTE (BITS ( 0,  3), i);
+         s = a | (b << 8);
+         r |= (s & 0xffff) << (i * 16);
+         SIMD8_SET (psr, NBIT8 (a), SIMD_NBIT, i * 2);
+         SIMD8_SET (psr, ZBIT8 (a), SIMD_ZBIT, i * 2);
+         SIMD8_SET (psr, NBIT8 (b), SIMD_NBIT, (i * 2) + 1);
+         SIMD8_SET (psr, ZBIT8 (b), SIMD_ZBIT, (i * 2) + 1);
+       }
+      break;
+
+    case Hqual:
+      for (i = 0; i < 2; i++)
+       {
+         a = wRHALF (BITS (16, 19), i);
+         b = wRHALF (BITS ( 0,  3), i);
+         s = a | (b << 16);
+         r |= (s & 0xffffffff) << (i * 32);
+         SIMD16_SET (psr, NBIT16 (a), SIMD_NBIT, (i * 2));
+         SIMD16_SET (psr, ZBIT16 (a), SIMD_ZBIT, (i * 2));
+         SIMD16_SET (psr, NBIT16 (b), SIMD_NBIT, (i * 2) + 1);
+         SIMD16_SET (psr, ZBIT16 (b), SIMD_ZBIT, (i * 2) + 1);
+       }
+      break;
+
+    case Wqual:
+      a = wRWORD (BITS (16, 19), 0);
+      s = wRWORD (BITS ( 0,  3), 0);
+      r = a | (s << 32);
+
+      SIMD32_SET (psr, NBIT32 (a), SIMD_NBIT, 0);
+      SIMD32_SET (psr, ZBIT32 (a), SIMD_ZBIT, 0);
+      SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, 1);
+      SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, 1);
+      break;
+
+    default:
+      ARMul_UndefInstr (state, instr);
+      return ARMul_DONE;
+    }
+
+  wC [wCASF] = psr;
+  wR [BITS (12, 15)] = r;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+static int
+WXOR (ARMword instr)
+{
+  ARMword psr = 0;
+  ARMdword result;
+
+  if ((read_cp15_reg (15, 0, 1) & 3) != 3)
+    return ARMul_CANT;
+
+#ifdef DEBUG
+  fprintf (stderr, "wxor\n");
+#endif  
+
+  result = wR [BITS (16, 19)] ^ wR [BITS (0, 3)];
+  wR [BITS (12, 15)] = result;
+
+  SIMD64_SET (psr, (result == 0), SIMD_ZBIT);
+  SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT);
+  
+  wC [wCASF] = psr;
+  wC [wCon] |= (WCON_CUP | WCON_MUP);
+
+  return ARMul_DONE;
+}
+
+/* This switch table is moved to a seperate function in order
+   to work around a compiler bug in the host compiler...  */
+
+static int
+Process_Instruction (ARMul_State * state, ARMword instr)
+{
+  int status = ARMul_BUSY;
+
+  switch ((BITS (20, 23) << 8) | BITS (4, 11))
+    {
+    case 0x000: status = WOR (instr); break;
+    case 0x011: status = TMCR (state, instr); break;
+    case 0x100: status = WXOR (instr); break;
+    case 0x111: status = TMRC (state, instr); break;
+    case 0x300: status = WANDN (instr); break;
+    case 0x200: status = WAND (instr); break;
+
+    case 0x810: case 0xa10:
+      status = WMADD (instr); break;
+
+    case 0x10e: case 0x50e: case 0x90e: case 0xd0e:
+      status = WUNPCKIL (state, instr); break;   
+    case 0x10c: case 0x50c: case 0x90c: case 0xd0c:
+      status = WUNPCKIH (state, instr); break;
+    case 0x012: case 0x112: case 0x412: case 0x512:
+      status = WSAD (instr); break;
+    case 0x010: case 0x110: case 0x210: case 0x310:
+      status = WMUL (instr); break;
+    case 0x410: case 0x510: case 0x610: case 0x710:
+      status = WMAC (instr); break;
+    case 0x006: case 0x406: case 0x806: case 0xc06:
+      status = WCMPEQ (state, instr); break;
+    case 0x800: case 0x900: case 0xc00: case 0xd00:
+      status = WAVG2 (instr); break;
+    case 0x802: case 0x902: case 0xa02: case 0xb02:
+      status = WALIGNR (state, instr); break;
+    case 0x601: case 0x605: case 0x609: case 0x60d:
+      status = TINSR (state, instr); break;
+    case 0x107: case 0x507: case 0x907: case 0xd07:
+      status = TEXTRM (state, instr); break;
+    case 0x117: case 0x517: case 0x917: case 0xd17:
+      status = TEXTRC (state, instr); break;
+    case 0x401: case 0x405: case 0x409: case 0x40d:
+      status = TBCST (state, instr); break;
+    case 0x113: case 0x513: case 0x913: case 0xd13:
+      status = TANDC (state, instr); break;
+    case 0x01c: case 0x41c: case 0x81c: case 0xc1c:
+      status = WACC (state, instr); break;
+    case 0x115: case 0x515: case 0x915: case 0xd15:
+      status = TORC (state, instr); break;
+    case 0x103: case 0x503: case 0x903: case 0xd03:
+      status = TMOVMSK (state, instr); break;
+    case 0x106: case 0x306: case 0x506: case 0x706:
+    case 0x906: case 0xb06: case 0xd06: case 0xf06:
+      status = WCMPGT (state, instr); break;
+    case 0x00e: case 0x20e: case 0x40e: case 0x60e:
+    case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
+      status = WUNPCKEL (state, instr); break;
+    case 0x00c: case 0x20c: case 0x40c: case 0x60c:
+    case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
+      status = WUNPCKEH (state, instr); break;
+    case 0x204: case 0x604: case 0xa04: case 0xe04:
+    case 0x214: case 0x614: case 0xa14: case 0xe14:
+      status = WSRL (state, instr); break;
+    case 0x004: case 0x404: case 0x804: case 0xc04:
+    case 0x014: case 0x414: case 0x814: case 0xc14:
+      status = WSRA (state, instr); break;
+    case 0x104: case 0x504: case 0x904: case 0xd04:
+    case 0x114: case 0x514: case 0x914: case 0xd14:
+      status = WSLL (state, instr); break;
+    case 0x304: case 0x704: case 0xb04: case 0xf04:
+    case 0x314: case 0x714: case 0xb14: case 0xf14:
+      status = WROR (state, instr); break;
+    case 0x116: case 0x316: case 0x516: case 0x716:
+    case 0x916: case 0xb16: case 0xd16: case 0xf16:
+      status = WMIN (state, instr); break;
+    case 0x016: case 0x216: case 0x416: case 0x616:
+    case 0x816: case 0xa16: case 0xc16: case 0xe16:
+      status = WMAX (state, instr); break;
+    case 0x002: case 0x102: case 0x202: case 0x302:
+    case 0x402: case 0x502: case 0x602: case 0x702:
+      status = WALIGNI (instr); break;
+    case 0x01a: case 0x11a: case 0x21a: case 0x31a:
+    case 0x41a: case 0x51a: case 0x61a: case 0x71a:
+    case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
+    case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
+      status = WSUB (state, instr); break;
+    case 0x01e: case 0x11e: case 0x21e: case 0x31e:      
+    case 0x41e: case 0x51e: case 0x61e: case 0x71e:
+    case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
+    case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
+      status = WSHUFH (instr); break;
+    case 0x018: case 0x118: case 0x218: case 0x318:
+    case 0x418: case 0x518: case 0x618: case 0x718:
+    case 0x818: case 0x918: case 0xa18: case 0xb18:
+    case 0xc18: case 0xd18: case 0xe18: case 0xf18:
+      status = WADD (state, instr); break;
+    case 0x008: case 0x108: case 0x208: case 0x308:
+    case 0x408: case 0x508: case 0x608: case 0x708:
+    case 0x808: case 0x908: case 0xa08: case 0xb08:
+    case 0xc08: case 0xd08: case 0xe08: case 0xf08:
+      status = WPACK (state, instr); break;
+    case 0x201: case 0x203: case 0x205: case 0x207:
+    case 0x209: case 0x20b: case 0x20d: case 0x20f:
+    case 0x211: case 0x213: case 0x215: case 0x217:      
+    case 0x219: case 0x21b: case 0x21d: case 0x21f:      
+      switch (BITS (16, 19))
+       {
+       case 0x0: status = TMIA (state, instr); break;
+       case 0x8: status = TMIAPH (state, instr); break;
+       case 0xc:
+       case 0xd:
+       case 0xe:
+       case 0xf: status = TMIAxy (state, instr); break;
+       default: break;
+       }
+      break;
+    default:
+      break;
+    }
+  return status;
+}
+
+/* Process a possibly Intel(r) Wireless MMX(tm) technology instruction.
+   Return true if the instruction was handled.  */
+
+int
+ARMul_HandleIwmmxt (ARMul_State * state, ARMword instr)
+{     
+  int status = ARMul_BUSY;
+
+  if (BITS (24, 27) == 0xe)
+    {
+      status = Process_Instruction (state, instr);
+    }
+  else if (BITS (25, 27) == 0x6)
+    {
+      if (BITS (4, 11) == 0x0 && BITS (20, 24) == 0x4)
+       status = TMCRR (state, instr);
+      else if (BITS (9, 11) == 0x0)
+       {
+         if (BIT (20) == 0x0)
+           status = WSTR (state, instr);
+         else if (BITS (20, 24) == 0x5)
+           status = TMRRC (state, instr);
+         else
+           status = WLDR (state, instr);
+       }
+    }
+
+  if (status == ARMul_CANT)
+    {
+      /* If the instruction was a recognised but illegal,
+        perform the abort here rather than returning false.
+        If we return false then ARMul_MRC may be called which
+        will still abort, but which also perform the register
+        transfer...  */
+      ARMul_Abort (state, ARMul_UndefinedInstrV);
+      status = ARMul_DONE;
+    }
+
+  return status == ARMul_DONE;
+}
+
+int
+Fetch_Iwmmxt_Register (unsigned int regnum, unsigned char * memory)
+{
+  if (regnum >= 16)
+    {
+      memcpy (memory, wC + (regnum - 16), sizeof wC [0]);
+      return sizeof wC [0];
+    }
+  else
+    {
+      memcpy (memory, wR + regnum, sizeof wR [0]);
+      return sizeof wR [0];
+    }
+}
+
+int
+Store_Iwmmxt_Register (unsigned int regnum, unsigned char * memory)
+{
+  if (regnum >= 16)
+    {
+      memcpy (wC + (regnum - 16), memory, sizeof wC [0]);
+      return sizeof wC [0];
+    }
+  else
+    {
+      memcpy (wR + regnum, memory, sizeof wR [0]);
+      return sizeof wR [0];
+    }
+}
diff --git a/sim/arm/iwmmxt.h b/sim/arm/iwmmxt.h
new file mode 100644 (file)
index 0000000..e25feab
--- /dev/null
@@ -0,0 +1,28 @@
+/*  iwmmxt.h -- Intel(r) Wireless MMX(tm) technology co-processor interface.
+    Copyright (C) 2002 Free Software Foundation, Inc.
+    Contributed by matthew green (mrg@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. */
+
+extern unsigned IwmmxtLDC (ARMul_State *, unsigned, ARMword, ARMword);
+extern unsigned IwmmxtSTC (ARMul_State *, unsigned, ARMword, ARMword *);
+extern unsigned IwmmxtMCR (ARMul_State *, unsigned, ARMword, ARMword);
+extern unsigned IwmmxtMRC (ARMul_State *, unsigned, ARMword, ARMword *);
+extern unsigned IwmmxtCDP (ARMul_State *, unsigned, ARMword);
+
+extern int ARMul_HandleIwmmxt (ARMul_State *, ARMword);
+
+extern int Fetch_Iwmmxt_Register (unsigned int, unsigned char *);
+extern int Store_Iwmmxt_Register (unsigned int, unsigned char *);
index f13d32928b06585db22c7df394ddbb6539b1354f..46410c3f877092a90f4708d3f0c858556e5e46aa 100644 (file)
@@ -263,10 +263,34 @@ sim_create_inferior (sd, abfd, argv, env)
       /* We wouldn't set the machine type with earlier toolchains, so we
         explicitly select a processor capable of supporting all ARMs in
         32bit mode.  */
+      /* We choose the XScale rather than the iWMMXt, because the iWMMXt
+        removes the FPE emulator, since it conflicts with its coprocessors.
+        For the most generic ARM support, we want the FPE emulator in place.  */
     case bfd_mach_arm_XScale:
       ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop);
       break;
 
+    case bfd_mach_arm_iWMMXt:
+      {
+       extern int SWI_vector_installed;
+       ARMword i;
+
+       if (! SWI_vector_installed)
+         {
+           /* Intialise the hardware vectors to zero.  */
+           if (! SWI_vector_installed)
+             for (i = ARMul_ResetV; i <= ARMFIQV; i += 4)
+               ARMul_WriteWord (state, i, 0);
+
+           /* ARM_WriteWord will have detected the write to the SWI vector,
+              but we want SWI_vector_installed to remain at 0 so that thumb
+              mode breakpoints will work.  */
+           SWI_vector_installed = 0;
+         }
+      }
+      ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop | ARM_iWMMXt_Prop);
+      break;
+
     case bfd_mach_arm_ep9312:
       ARMul_SelectProcessor (state, ARM_v4_Prop | ARM_ep9312_Prop);
       break;
@@ -481,6 +505,41 @@ sim_store_register (sd, rn, memory, length)
       memcpy (&DSPsc, memory, sizeof DSPsc);
       return sizeof DSPsc;
 
+#ifdef __IWMMXT__
+    case SIM_ARM_IWMMXT_COP0R0_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R1_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R2_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R3_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R4_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R5_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R6_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R7_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R8_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R9_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R10_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R11_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R12_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R13_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R14_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R15_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R0_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R1_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R2_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R3_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R4_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R5_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R6_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R7_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R8_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R9_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R10_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R11_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R12_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R13_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R14_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R15_REGNUM:
+      return Store_Iwmmxt_Register (rn - SIM_ARM_IWMMXT_COP0R0_REGNUM, memory);
+#endif
     default:
       return 0;
     }
@@ -560,6 +619,41 @@ sim_fetch_register (sd, rn, memory, length)
       memcpy (memory, & DSPsc, sizeof DSPsc);
       return sizeof DSPsc;
 
+#ifdef __IWMMXT__
+    case SIM_ARM_IWMMXT_COP0R0_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R1_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R2_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R3_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R4_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R5_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R6_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R7_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R8_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R9_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R10_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R11_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R12_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R13_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R14_REGNUM:
+    case SIM_ARM_IWMMXT_COP0R15_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R0_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R1_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R2_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R3_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R4_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R5_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R6_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R7_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R8_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R9_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R10_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R11_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R12_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R13_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R14_REGNUM:
+    case SIM_ARM_IWMMXT_COP1R15_REGNUM:
+      return Fetch_Iwmmxt_Register (rn - SIM_ARM_IWMMXT_COP0R0_REGNUM, memory);
+#endif
     default:
       return 0;
     }
@@ -822,6 +916,9 @@ sim_stop_reason (sd, reason, sigrc)
       *reason = sim_stopped;
       if (state->EndCondition == RDIError_BreakpointReached)
        *sigrc = SIGTRAP;
+      else if (   state->EndCondition == RDIError_DataAbort
+              || state->EndCondition == RDIError_AddressException)
+       *sigrc = SIGBUS;
       else
        *sigrc = 0;
     }