]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/arm/armemu.c
Fix invalid left shift of negative value
[thirdparty/binutils-gdb.git] / sim / arm / armemu.c
index 558e897582aec5da0418aa0e87756d73d4be0eaf..3826c78aa9e9f62e2c09ee48d24e7dcc9e579a56 100644 (file)
@@ -1,20 +1,19 @@
 /*  armemu.c -- Main instruction emulation:  ARM7 Instruction Emulator.
     Copyright (C) 1994 Advanced RISC Machines Ltd.
     Modifications to add arch. v4 support by <jsmith@cygnus.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
+    the Free Software Foundation; either version 3 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #include "armdefs.h"
 #include "armemu.h"
@@ -26,6 +25,7 @@ static ARMword  GetDPSRegRHS        (ARMul_State *, ARMword);
 static void     WriteR15            (ARMul_State *, ARMword);
 static void     WriteSR15           (ARMul_State *, ARMword);
 static void     WriteR15Branch      (ARMul_State *, ARMword);
+static void     WriteR15Load        (ARMul_State *, ARMword);
 static ARMword  GetLSRegRHS         (ARMul_State *, ARMword);
 static ARMword  GetLS7RHS           (ARMul_State *, ARMword);
 static unsigned LoadWord            (ARMul_State *, ARMword, ARMword);
@@ -48,17 +48,6 @@ static void     Handle_Store_Double (ARMul_State *, ARMword);
 #define LDEFAULT  (0)          /* default : do nothing */
 #define LSCC      (1)          /* set condition codes on result */
 
-#ifdef NEED_UI_LOOP_HOOK
-/* How often to run the ui_loop update, when in use.  */
-#define UI_LOOP_POLL_INTERVAL 0x32000
-
-/* Counter for the ui_loop_hook update.  */
-static long ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL;
-
-/* Actual hook to call to run through gdb's gui event loop.  */
-extern int (*deprecated_ui_loop_hook) (int);
-#endif /* NEED_UI_LOOP_HOOK */
-
 extern int stop_simulator;
 
 /* Short-hand macros for LDR/STR.  */
@@ -272,9 +261,15 @@ extern int stop_simulator;
 /* Attempt to emulate an ARMv6 instruction.
    Returns non-zero upon success.  */
 
+#ifdef MODE32
 static int
 handle_v6_insn (ARMul_State * state, ARMword instr)
 {
+  ARMword val;
+  ARMword Rd;
+  ARMword Rm;
+  ARMword Rn;
+
   switch (BITS (20, 27))
     {
 #if 0
@@ -290,31 +285,429 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
     case 0x1d: printf ("Unhandled v6 insn: ldrexb\n"); break;
     case 0x1e: printf ("Unhandled v6 insn: strexh\n"); break;
     case 0x1f: printf ("Unhandled v6 insn: ldrexh\n"); break;
-    case 0x30: printf ("Unhandled v6 insn: movw\n"); break;
     case 0x32: printf ("Unhandled v6 insn: nop/sev/wfe/wfi/yield\n"); break;
-    case 0x34: printf ("Unhandled v6 insn: movt\n"); break;
     case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break;
 #endif
     case 0x61: printf ("Unhandled v6 insn: sadd/ssub\n"); break;
-    case 0x62: printf ("Unhandled v6 insn: qadd/qsub\n"); break;
     case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); break;
-    case 0x65: printf ("Unhandled v6 insn: uadd/usub\n"); break;
-    case 0x66: printf ("Unhandled v6 insn: uqadd/uqsub\n"); break;
-    case 0x67: printf ("Unhandled v6 insn: uhadd/uhsub\n"); break;
-    case 0x68: printf ("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); break;
     case 0x6c: printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); break;
     case 0x70: printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); break;
     case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); break;
     case 0x75: printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); break;
     case 0x78: printf ("Unhandled v6 insn: usad/usada8\n"); break;
-    case 0x7a: printf ("Unhandled v6 insn: usbfx\n"); break;
-    case 0x7c: printf ("Unhandled v6 insn: bfc/bfi\n"); break;
+
+    case 0x30:
+      {
+       /* MOVW<c> <Rd>,#<imm16>
+          instr[31,28] = cond
+          instr[27,20] = 0011 0000
+          instr[19,16] = imm4
+          instr[15,12] = Rd
+          instr[11, 0] = imm12.  */
+       Rd = BITS (12, 15);
+       val = (BITS (16, 19) << 12) | BITS (0, 11);
+       state->Reg[Rd] = val;
+       return 1;
+      }
+
+    case 0x34:
+      {
+       /* MOVT<c> <Rd>,#<imm16>
+          instr[31,28] = cond
+          instr[27,20] = 0011 0100
+          instr[19,16] = imm4
+          instr[15,12] = Rd
+          instr[11, 0] = imm12.  */
+       Rd = BITS (12, 15);
+       val = (BITS (16, 19) << 12) | BITS (0, 11);
+       state->Reg[Rd] &= 0xFFFF;
+       state->Reg[Rd] |= val << 16;
+       return 1;
+      }
+
+    case 0x62:
+      {
+       ARMword val1;
+       ARMword val2;
+       ARMsword n, m, r;
+       int i;
+
+       Rd = BITS (12, 15);
+       Rn = BITS (16, 19);
+       Rm = BITS (0, 3);
+
+       if (Rd == 15 || Rn == 15 || Rm == 15)
+         break;
+
+       val1 = state->Reg[Rn];
+       val2 = state->Reg[Rm];
+
+       switch (BITS (4, 11))
+         {
+         case 0xF1: /* QADD16<c> <Rd>,<Rn>,<Rm>.  */
+           state->Reg[Rd] = 0;
+
+           for (i = 0; i < 32; i+= 16)
+             {
+               n = (val1 >> i) & 0xFFFF;
+               if (n & 0x8000)
+                 n |= -(1 << 16);
+
+               m = (val2 >> i) & 0xFFFF;
+               if (m & 0x8000)
+                 m |= -(1 << 16);
+
+               r = n + m;
+
+               if (r > 0x7FFF)
+                 r = 0x7FFF;
+               else if (r < -(0x8000))
+                 r = - 0x8000;
+
+               state->Reg[Rd] |= (r & 0xFFFF) << i;
+             } 
+           return 1;
+
+         case 0xF3: /* QASX<c> <Rd>,<Rn>,<Rm>.  */
+           n = val1 & 0xFFFF;
+           if (n & 0x8000)
+             n |= -(1 << 16);
+
+           m = (val2 >> 16) & 0xFFFF;
+           if (m & 0x8000)
+             m |= -(1 << 16);
+
+           r = n - m;
+
+           if (r > 0x7FFF)
+             r = 0x7FFF;
+           else if (r < -(0x8000))
+             r = - 0x8000;
+
+           state->Reg[Rd] = (r & 0xFFFF);
+
+           n = (val1 >> 16) & 0xFFFF;
+           if (n & 0x8000)
+             n |= -(1 << 16);
+
+           m = val2 & 0xFFFF;
+           if (m & 0x8000)
+             m |= -(1 << 16);
+
+           r = n + m;
+
+           if (r > 0x7FFF)
+             r = 0x7FFF;
+           else if (r < -(0x8000))
+             r = - 0x8000;
+
+           state->Reg[Rd] |= (r & 0xFFFF) << 16;
+           return 1;
+
+         case 0xF5: /* QSAX<c> <Rd>,<Rn>,<Rm>.  */
+           n = val1 & 0xFFFF;
+           if (n & 0x8000)
+             n |= -(1 << 16);
+
+           m = (val2 >> 16) & 0xFFFF;
+           if (m & 0x8000)
+             m |= -(1 << 16);
+
+           r = n + m;
+
+           if (r > 0x7FFF)
+             r = 0x7FFF;
+           else if (r < -(0x8000))
+             r = - 0x8000;
+
+           state->Reg[Rd] = (r & 0xFFFF);
+
+           n = (val1 >> 16) & 0xFFFF;
+           if (n & 0x8000)
+             n |= -(1 << 16);
+
+           m = val2 & 0xFFFF;
+           if (m & 0x8000)
+             m |= -(1 << 16);
+
+           r = n - m;
+
+           if (r > 0x7FFF)
+             r = 0x7FFF;
+           else if (r < -(0x8000))
+             r = - 0x8000;
+
+           state->Reg[Rd] |= (r & 0xFFFF) << 16;
+           return 1;
+
+         case 0xF7: /* QSUB16<c> <Rd>,<Rn>,<Rm>.  */
+           state->Reg[Rd] = 0;
+
+           for (i = 0; i < 32; i+= 16)
+             {
+               n = (val1 >> i) & 0xFFFF;
+               if (n & 0x8000)
+                 n |= -(1 << 16);
+
+               m = (val2 >> i) & 0xFFFF;
+               if (m & 0x8000)
+                 m |= -(1 << 16);
+
+               r = n - m;
+
+               if (r > 0x7FFF)
+                 r = 0x7FFF;
+               else if (r < -(0x8000))
+                 r = - 0x8000;
+
+               state->Reg[Rd] |= (r & 0xFFFF) << i;
+             } 
+           return 1;
+
+         case 0xF9: /* QADD8<c> <Rd>,<Rn>,<Rm>.  */
+           state->Reg[Rd] = 0;
+
+           for (i = 0; i < 32; i+= 8)
+             {
+               n = (val1 >> i) & 0xFF;
+               if (n & 0x80)
+                 n |= - (1 << 8);
+
+               m = (val2 >> i) & 0xFF;
+               if (m & 0x80)
+                 m |= - (1 << 8);
+
+               r = n + m;
+
+               if (r > 127)
+                 r = 127;
+               else if (r < -128)
+                 r = -128;
+
+               state->Reg[Rd] |= (r & 0xFF) << i;
+             } 
+           return 1;
+
+         case 0xFF: /* QSUB8<c> <Rd>,<Rn>,<Rm>.  */
+           state->Reg[Rd] = 0;
+
+           for (i = 0; i < 32; i+= 8)
+             {
+               n = (val1 >> i) & 0xFF;
+               if (n & 0x80)
+                 n |= - (1 << 8);
+
+               m = (val2 >> i) & 0xFF;
+               if (m & 0x80)
+                 m |= - (1 << 8);
+
+               r = n - m;
+
+               if (r > 127)
+                 r = 127;
+               else if (r < -128)
+                 r = -128;
+
+               state->Reg[Rd] |= (r & 0xFF) << i;
+             } 
+           return 1;
+
+         default:
+           break;
+         }
+       break;
+      }
+
+    case 0x65:
+      {
+       ARMword valn;
+       ARMword valm;
+       ARMword res1, res2, res3, res4;
+
+       /* U{ADD|SUB}{8|16}<c> <Rd>, <Rn>, <Rm>
+          instr[31,28] = cond
+          instr[27,20] = 0110 0101
+          instr[19,16] = Rn
+          instr[15,12] = Rd
+          instr[11, 8] = 1111
+          instr[ 7, 4] = opcode: UADD8 (1001), UADD16 (0001), USUB8 (1111), USUB16 (0111)
+          instr[ 3, 0] = Rm.  */
+       if (BITS (8, 11) != 0xF)
+         break;
+
+       Rn = BITS (16, 19);
+       Rd = BITS (12, 15);
+       Rm = BITS (0, 3);
+
+       if (Rn == 15 || Rd == 15 || Rm == 15)
+         {
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
+           break;
+         }
+
+       valn = state->Reg[Rn];
+       valm = state->Reg[Rm];
+       
+       switch (BITS (4, 7))
+         {
+         case 1:  /* UADD16.  */
+           res1 = (valn & 0xFFFF) + (valm & 0xFFFF);
+           if (res1 > 0xFFFF)
+             state->Cpsr |= (GE0 | GE1);
+           else
+             state->Cpsr &= ~ (GE0 | GE1);
+
+           res2 = (valn >> 16) + (valm >> 16);
+           if (res2 > 0xFFFF)
+             state->Cpsr |= (GE2 | GE3);
+           else
+             state->Cpsr &= ~ (GE2 | GE3);
+
+           state->Reg[Rd] = (res1 & 0xFFFF) | (res2 << 16);
+           return 1;
+
+         case 7:  /* USUB16.  */
+           res1 = (valn & 0xFFFF) - (valm & 0xFFFF);
+           if (res1 & 0x800000)
+             state->Cpsr |= (GE0 | GE1);
+           else
+             state->Cpsr &= ~ (GE0 | GE1);
+
+           res2 = (valn >> 16) - (valm >> 16);
+           if (res2 & 0x800000)
+             state->Cpsr |= (GE2 | GE3);
+           else
+             state->Cpsr &= ~ (GE2 | GE3);
+
+           state->Reg[Rd] = (res1 & 0xFFFF) | (res2 << 16);
+           return 1;
+
+         case 9:  /* UADD8.  */
+           res1 = (valn & 0xFF) + (valm & 0xFF);
+           if (res1 > 0xFF)
+             state->Cpsr |= GE0;
+           else
+             state->Cpsr &= ~ GE0;
+
+           res2 = ((valn >> 8) & 0xFF) + ((valm >> 8) & 0xFF);
+           if (res2 > 0xFF)
+             state->Cpsr |= GE1;
+           else
+             state->Cpsr &= ~ GE1;
+
+           res3 = ((valn >> 16) & 0xFF) + ((valm >> 16) & 0xFF);
+           if (res3 > 0xFF)
+             state->Cpsr |= GE2;
+           else
+             state->Cpsr &= ~ GE2;
+
+           res4 = (valn >> 24) + (valm >> 24);
+           if (res4 > 0xFF)
+             state->Cpsr |= GE3;
+           else
+             state->Cpsr &= ~ GE3;
+
+           state->Reg[Rd] = (res1 & 0xFF) | ((res2 << 8) & 0xFF00)
+             | ((res3 << 16) & 0xFF0000) | (res4 << 24);
+           return 1;
+
+         case 15: /* USUB8.  */
+           res1 = (valn & 0xFF) - (valm & 0xFF);
+           if (res1 & 0x800000)
+             state->Cpsr |= GE0;
+           else
+             state->Cpsr &= ~ GE0;
+
+           res2 = ((valn >> 8) & 0XFF) - ((valm >> 8) & 0xFF);
+           if (res2 & 0x800000)
+             state->Cpsr |= GE1;
+           else
+             state->Cpsr &= ~ GE1;
+
+           res3 = ((valn >> 16) & 0XFF) - ((valm >> 16) & 0xFF);
+           if (res3 & 0x800000)
+             state->Cpsr |= GE2;
+           else
+             state->Cpsr &= ~ GE2;
+
+           res4 = (valn >> 24) - (valm >> 24) ;
+           if (res4 & 0x800000)
+             state->Cpsr |= GE3;
+           else
+             state->Cpsr &= ~ GE3;
+
+           state->Reg[Rd] = (res1 & 0xFF) | ((res2 << 8) & 0xFF00)
+             | ((res3 << 16) & 0xFF0000) | (res4 << 24);
+           return 1;
+
+         default:
+           break;
+         }
+       break;
+      }
+
+    case 0x68:
+      {
+       ARMword res;
+
+       /* PKHBT<c> <Rd>,<Rn>,<Rm>{,LSL #<imm>}
+          PKHTB<c> <Rd>,<Rn>,<Rm>{,ASR #<imm>}
+          SXTAB16<c> <Rd>,<Rn>,<Rm>{,<rotation>}
+          SXTB16<c> <Rd>,<Rm>{,<rotation>}
+          SEL<c> <Rd>,<Rn>,<Rm>
+
+          instr[31,28] = cond
+          instr[27,20] = 0110 1000
+          instr[19,16] = Rn
+          instr[15,12] = Rd
+          instr[11, 7] = imm5 (PKH), 11111 (SEL), rr000 (SXTAB16 & SXTB16),
+          instr[6]     = tb (PKH), 0 (SEL), 1 (SXT)
+          instr[5]     = opcode: PKH (0), SEL/SXT (1)
+          instr[4]     = 1
+          instr[ 3, 0] = Rm.  */
+
+       if (BIT (4) != 1)
+         break;
+
+       if (BIT (5) == 0)
+         {
+           /* FIXME: Add implementation of PKH.  */
+           fprintf (stderr, "PKH: NOT YET IMPLEMENTED\n");
+           ARMul_UndefInstr (state, instr);
+           break;
+         }
+
+       if (BIT (6) == 1)
+         {
+           /* FIXME: Add implementation of SXT.  */
+           fprintf (stderr, "SXT: NOT YET IMPLEMENTED\n");
+           ARMul_UndefInstr (state, instr);
+           break;
+         }
+
+       Rn = BITS (16, 19);
+       Rd = BITS (12, 15);
+       Rm = BITS (0, 3);
+       if (Rn == 15 || Rm == 15 || Rd == 15)
+         {
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
+           break;
+         }
+
+       res  = (state->Reg[(state->Cpsr & GE0) ? Rn : Rm]) & 0xFF;
+       res |= (state->Reg[(state->Cpsr & GE1) ? Rn : Rm]) & 0xFF00;
+       res |= (state->Reg[(state->Cpsr & GE2) ? Rn : Rm]) & 0xFF0000;
+       res |= (state->Reg[(state->Cpsr & GE3) ? Rn : Rm]) & 0xFF000000;
+       state->Reg[Rd] = res;
+       return 1;
+      }
 
     case 0x6a:
       {
-       ARMword Rm;
        int ror = -1;
-         
+
        switch (BITS (4, 11))
          {
          case 0x07: ror = 0; break;
@@ -326,6 +719,7 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
          case 0xf3:
            printf ("Unhandled v6 insn: ssat\n");
            return 0;
+
          default:
            break;
          }
@@ -355,9 +749,8 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
 
     case 0x6b:
       {
-       ARMword Rm;
        int ror = -1;
-         
+
        switch (BITS (4, 11))
          {
          case 0x07: ror = 0; break;
@@ -365,9 +758,57 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
          case 0x87: ror = 16; break;
          case 0xc7: ror = 24; break;
 
+         case 0xf3:
+           {
+             /* REV<c> <Rd>,<Rm>
+                instr[31,28] = cond
+                instr[27,20] = 0110 1011
+                instr[19,16] = 1111
+                instr[15,12] = Rd
+                instr[11, 4] = 1111 0011
+                instr[ 3, 0] = Rm.  */
+             if (BITS (16, 19) != 0xF)
+               break;
+
+             Rd = BITS (12, 15);
+             Rm = BITS (0, 3);
+             if (Rd == 15 || Rm == 15)
+               {
+                 ARMul_UndefInstr (state, instr);
+                 state->Emulate = FALSE;
+                 break;
+               }
+
+             val = state->Reg[Rm] << 24;
+             val |= ((state->Reg[Rm] << 8) & 0xFF0000);
+             val |= ((state->Reg[Rm] >> 8) & 0xFF00);
+             val |= ((state->Reg[Rm] >> 24));
+             state->Reg[Rd] = val;
+             return 1;
+           }
+
          case 0xfb:
-           printf ("Unhandled v6 insn: rev\n");
-           return 0;
+           {
+             /* REV16<c> <Rd>,<Rm>.  */
+             if (BITS (16, 19) != 0xF)
+               break;
+
+             Rd = BITS (12, 15);
+             Rm = BITS (0, 3);
+             if (Rd == 15 || Rm == 15)
+               {
+                 ARMul_UndefInstr (state, instr);
+                 state->Emulate = FALSE;
+                 break;
+               }
+
+             val = 0;
+             val |= ((state->Reg[Rm] >> 8) & 0x00FF00FF);
+             val |= ((state->Reg[Rm] << 8) & 0xFF00FF00);
+             state->Reg[Rd] = val;
+             return 1;
+           }
+
          default:
            break;
          }
@@ -390,9 +831,8 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
 
     case 0x6e:
       {
-       ARMword Rm;
        int ror = -1;
-         
+
        switch (BITS (4, 11))
          {
          case 0x07: ror = 0; break;
@@ -404,6 +844,7 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
          case 0xf3:
            printf ("Unhandled v6 insn: usat\n");
            return 0;
+
          default:
            break;
          }
@@ -421,7 +862,7 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
        Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF);
 
        if (BITS (16, 19) == 0xf)
-          /* UXTB */
+         /* UXTB */
          state->Reg[BITS (12, 15)] = Rm;
        else
          /* UXTAB */
@@ -431,9 +872,9 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
 
     case 0x6f:
       {
-       ARMword Rm;
+       int i;
        int ror = -1;
-         
+
        switch (BITS (4, 11))
          {
          case 0x07: ror = 0; break;
@@ -441,9 +882,21 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
          case 0x87: ror = 16; break;
          case 0xc7: ror = 24; break;
 
+         case 0xf3: /* RBIT */
+           if (BITS (16, 19) != 0xF)
+             break;
+           Rd = BITS (12, 15);
+           state->Reg[Rd] = 0;
+           Rm = state->Reg[BITS (0, 3)];
+           for (i = 0; i < 32; i++)
+             if (Rm & (1 << i))
+               state->Reg[Rd] |= (1 << (31 - i));
+           return 1;
+
          case 0xfb:
            printf ("Unhandled v6 insn: revsh\n");
            return 0;
+
          default:
            break;
          }
@@ -457,13 +910,138 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
          /* UXT */
          state->Reg[BITS (12, 15)] = Rm;
        else
+         /* UXTAH */
+         state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm;
+      }
+      return 1;
+
+    case 0x7c:
+    case 0x7d:
+      {
+       int lsb;
+       int msb;
+       ARMword mask;
+
+       /* BFC<c> <Rd>,#<lsb>,#<width>
+          BFI<c> <Rd>,<Rn>,#<lsb>,#<width>
+
+          instr[31,28] = cond
+          instr[27,21] = 0111 110
+          instr[20,16] = msb
+          instr[15,12] = Rd
+          instr[11, 7] = lsb
+          instr[ 6, 4] = 001 1111
+          instr[ 3, 0] = Rn (BFI) / 1111 (BFC).  */
+
+       if (BITS (4, 6) != 0x1)
+         break;
+
+       Rd = BITS (12, 15);
+       if (Rd == 15)
          {
-           /* UXTAH */
-           state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm;
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
          }
-       }
-      return 1;
 
+       lsb = BITS (7, 11);
+       msb = BITS (16, 20);
+       if (lsb > msb)
+         {
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
+         }
+
+       mask = -(1 << lsb);
+       mask &= ~(-(1 << (msb + 1)));
+       state->Reg[Rd] &= ~ mask;
+
+       Rn = BITS (0, 3);
+       if (Rn != 0xF)
+         {
+           ARMword val = state->Reg[Rn] & ~(-(1 << ((msb + 1) - lsb)));
+           state->Reg[Rd] |= val << lsb;
+         }
+       return 1;
+      }
+
+    case 0x7b:
+    case 0x7a: /* SBFX<c> <Rd>,<Rn>,#<lsb>,#<width>.  */
+      {
+       int lsb;
+       int widthm1;
+       ARMsword sval;
+
+       if (BITS (4, 6) != 0x5)
+         break;
+
+       Rd = BITS (12, 15);
+       if (Rd == 15)
+         {
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
+         }
+
+       Rn = BITS (0, 3);
+       if (Rn == 15)
+         {
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
+         }
+
+       lsb = BITS (7, 11);
+       widthm1 = BITS (16, 20);
+
+       sval = state->Reg[Rn];
+       sval <<= (31 - (lsb + widthm1));
+       sval >>= (31 - widthm1);
+       state->Reg[Rd] = sval;
+       
+       return 1;
+      }
+
+    case 0x7f:
+    case 0x7e:
+      {
+       int lsb;
+       int widthm1;
+
+       /* UBFX<c> <Rd>,<Rn>,#<lsb>,#<width>
+          instr[31,28] = cond
+          instr[27,21] = 0111 111
+          instr[20,16] = widthm1
+          instr[15,12] = Rd
+          instr[11, 7] = lsb
+          instr[ 6, 4] = 101
+          instr[ 3, 0] = Rn.  */
+
+       if (BITS (4, 6) != 0x5)
+         break;
+
+       Rd = BITS (12, 15);
+       if (Rd == 15)
+         {
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
+         }
+
+       Rn = BITS (0, 3);
+       if (Rn == 15)
+         {
+           ARMul_UndefInstr (state, instr);
+           state->Emulate = FALSE;
+         }
+
+       lsb = BITS (7, 11);
+       widthm1 = BITS (16, 20);
+
+       val = state->Reg[Rn];
+       val >>= lsb;
+       val &= ~(-(1 << (widthm1 + 1)));
+
+       state->Reg[Rd] = val;
+       
+       return 1;
+      }
 #if 0
     case 0x84: printf ("Unhandled v6 insn: srs\n"); break;
 #endif
@@ -473,6 +1051,92 @@ handle_v6_insn (ARMul_State * state, ARMword instr)
   printf ("Unhandled v6 insn: UNKNOWN: %08x\n", instr);
   return 0;
 }
+#endif
+
+static void
+handle_VFP_move (ARMul_State * state, ARMword instr)
+{
+  switch (BITS (20, 27))
+    {
+    case 0xC4:
+    case 0xC5:
+      switch (BITS (4, 11))
+       {
+       case 0xA1:
+       case 0xA3:
+         {
+           /* VMOV two core <-> two VFP single precision.  */
+           int sreg = (BITS (0, 3) << 1) | BIT (5);
+
+           if (BIT (20))
+             {
+               state->Reg[BITS (12, 15)] = VFP_uword (sreg);
+               state->Reg[BITS (16, 19)] = VFP_uword (sreg + 1);
+             }
+           else
+             {
+               VFP_uword (sreg)     = state->Reg[BITS (12, 15)];
+               VFP_uword (sreg + 1) = state->Reg[BITS (16, 19)];
+             }
+         }
+         break;
+
+       case 0xB1:
+       case 0xB3:
+         {
+           /* VMOV two core <-> VFP double precision.  */
+           int dreg = BITS (0, 3) | (BIT (5) << 4);
+
+           if (BIT (20))
+             {
+               if (trace)
+                 fprintf (stderr, " VFP: VMOV: r%d r%d <= d%d\n",
+                          BITS (12, 15), BITS (16, 19), dreg);
+
+               state->Reg[BITS (12, 15)] = VFP_dword (dreg);
+               state->Reg[BITS (16, 19)] = VFP_dword (dreg) >> 32;
+             }
+           else
+             {
+               VFP_dword (dreg) = state->Reg[BITS (16, 19)];
+               VFP_dword (dreg) <<= 32;
+               VFP_dword (dreg) |= state->Reg[BITS (12, 15)];
+
+               if (trace)
+                 fprintf (stderr, " VFP: VMOV: d%d <= r%d r%d : %g\n",
+                          dreg, BITS (16, 19), BITS (12, 15),
+                          VFP_dval (dreg));
+             }
+         }
+         break;
+
+       default:
+         fprintf (stderr, "SIM: VFP: Unimplemented move insn %x\n", BITS (20, 27));
+         break;
+       }
+      break;
+
+    case 0xe0:
+    case 0xe1:
+      /* VMOV single core <-> VFP single precision.  */
+      if (BITS (0, 6) != 0x10 || BITS (8, 11) != 0xA)
+       fprintf (stderr, "SIM: VFP: Unimplemented move insn %x\n", BITS (20, 27));
+      else
+       {
+         int sreg = (BITS (16, 19) << 1) | BIT (7);
+
+         if (BIT (20))
+           state->Reg[DESTReg] = VFP_uword (sreg);
+         else
+           VFP_uword (sreg) = state->Reg[DESTReg];
+       }
+      break;
+
+    default:
+      fprintf (stderr, "SIM: VFP: Unimplemented move insn %x\n", BITS (20, 27));
+      return;
+    }
+}
 
 /* EMULATION of ARM6.  */
 
@@ -580,11 +1244,20 @@ ARMul_Emulate26 (ARMul_State * state)
 
       if (state->EventSet)
        ARMul_EnvokeEvent (state);
-#if 0 /* Enable this for a helpful bit of debugging when tracing is needed.  */
-      fprintf (stderr, "pc: %x, instr: %x\n", pc & ~1, instr);
-      if (instr == 0)
-       abort ();
-#endif
+
+      if (! TFLAG && trace)
+       {
+         fprintf (stderr, "pc: %x, ", pc & ~1);
+         if (! disas)
+           fprintf (stderr, "instr: %x\n", instr);
+       }
+
+      if (instr == 0 || pc < 0x10)
+       {
+         ARMul_Abort (state, ARMUndefinedInstrV);
+         state->Emulate = FALSE;
+       }
+
 #if 0 /* Enable this code to help track down stack alignment bugs.  */
       {
        static ARMword old_sp = -1;
@@ -628,8 +1301,8 @@ ARMul_Emulate26 (ARMul_State * state)
            }
          if (state->Debug)
            {
-             fprintf (stderr, "sim: At %08lx Instr %08lx Mode %02lx\n", pc, instr,
-                      state->Mode);
+             fprintf (stderr, "sim: At %08lx Instr %08lx Mode %02lx\n",
+                      (long) pc, (long) instr, (long) state->Mode);
              (void) fgetc (stdin);
            }
        }
@@ -667,6 +1340,14 @@ ARMul_Emulate26 (ARMul_State * state)
 
            case t_decoded:
              /* ARM instruction available.  */
+             if (disas || trace)
+               {
+                 fprintf (stderr, "  emulate as: ");
+                 if (trace)
+                   fprintf (stderr, "%08x ", new);
+                 if (! disas)
+                   fprintf (stderr, "\n");
+               }
              instr = new;
              /* So continue instruction decoding.  */
              break;
@@ -675,6 +1356,8 @@ ARMul_Emulate26 (ARMul_State * state)
            }
        }
 #endif
+      if (disas)
+       print_insn (instr);
 
       /* Check the condition codes.  */
       if ((temp = TOPBITS (28)) == AL)
@@ -693,9 +1376,9 @@ ARMul_Emulate26 (ARMul_State * state)
              if (BITS (25, 27) == 5) /* BLX(1) */
                {
                  ARMword dest;
-                 
+
                  state->Reg[14] = pc + 4;
-                 
+
                  /* Force entry into Thumb mode.  */
                  dest = pc + 8 + 1;
                  if (BIT (23))
@@ -798,10 +1481,11 @@ ARMul_Emulate26 (ARMul_State * state)
              else
                {
                  ARMword cp14r1;
-                 int do_int = 0;
+                 int do_int;
 
                  state->CP14R0_CCD = -1;
 check_PMUintr:
+                 do_int = 0;
                  cp14r0 |= ARMul_CP14_R0_FLAG2;
                  (void) state->CPWrite[14] (state, 0, cp14r0);
 
@@ -864,7 +1548,7 @@ check_PMUintr:
                      ARMword temp = GetLS7RHS (state, instr);
                      ARMword temp2 = BIT (23) ? LHS + temp : LHS - temp;
                      ARMword addr = BIT (24) ? temp2 : LHS;
-                     
+
                      if (BIT (12))
                        ARMul_UndefInstr (state, instr);
                      else if (addr & 7)
@@ -873,7 +1557,7 @@ check_PMUintr:
                      else
                        {
                          int wb = BIT (21) || (! BIT (24));
-                         
+
                          state->Reg[BITS (12, 15)] =
                            ARMul_LoadWordN (state, addr);
                          state->Reg[BITS (12, 15) + 1] =
@@ -1445,7 +2129,7 @@ check_PMUintr:
                      ARMword op1 = state->Reg[BITS (0, 3)];
                      ARMword op2 = state->Reg[BITS (8, 11)];
                      ARMword Rn = state->Reg[BITS (12, 15)];
-                     
+
                      if (BIT (5))
                        op1 >>= 16;
                      if (BIT (6))
@@ -1457,7 +2141,7 @@ check_PMUintr:
                      if (op2 & 0x8000)
                        op2 -= 65536;
                      op1 *= op2;
-                     
+
                      if (AddOverflow (op1, Rn, op1 + Rn))
                        SETS;
                      state->Reg[BITS (16, 19)] = op1 + Rn;
@@ -1527,6 +2211,11 @@ check_PMUintr:
                }
              else
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  UNDEF_Test;
                }
              break;
@@ -1600,7 +2289,7 @@ check_PMUintr:
                      if (BIT (5) == 0)
                        {
                          ARMword Rn = state->Reg[BITS (12, 15)];
-                         
+
                          if (AddOverflow (result, Rn, result + Rn))
                            SETS;
                          result += Rn;
@@ -1654,7 +2343,6 @@ check_PMUintr:
                {
                  if (BITS (4, 7) == 0x7)
                    {
-                     ARMword value;
                      extern int SWI_vector_installed;
 
                      /* Hardware is allowed to optionally override this
@@ -1694,6 +2382,11 @@ check_PMUintr:
 #endif
                  ARMul_FixCPSR (state, instr, temp);
                }
+#ifdef MODE32
+             else if (state->is_v6
+                      && handle_v6_insn (state, instr))
+               break;
+#endif
              else
                UNDEF_Test;
 
@@ -1736,7 +2429,6 @@ check_PMUintr:
                      ARMdword op1 = state->Reg[BITS (0, 3)];
                      ARMdword op2 = state->Reg[BITS (8, 11)];
                      ARMdword dest;
-                     ARMdword result;
 
                      if (BIT (5))
                        op1 >>= 16;
@@ -1825,6 +2517,11 @@ check_PMUintr:
                  UNDEF_MRSPC;
                  DEST = GETSPSR (state->Bank);
                }
+#ifdef MODE32
+             else if (state->is_v6
+                      && handle_v6_insn (state, instr))
+               break;
+#endif
              else
                UNDEF_Test;
 
@@ -1877,7 +2574,6 @@ check_PMUintr:
                      /* ElSegundo SMULxy insn.  */
                      ARMword op1 = state->Reg[BITS (0, 3)];
                      ARMword op2 = state->Reg[BITS (8, 11)];
-                     ARMword Rn = state->Reg[BITS (12, 15)];
 
                      if (BIT (5))
                        op1 >>= 16;
@@ -1962,6 +2658,11 @@ check_PMUintr:
                }
              else
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  UNDEF_Test;
                }
              break;
@@ -2316,8 +3017,15 @@ check_PMUintr:
              WRITESDEST (dest);
              break;
 
-           case 0x30:          /* TST immed */
-             UNDEF_Test;
+           case 0x30:          /* MOVW immed */
+#ifdef MODE32
+             if (state->is_v6
+                 && handle_v6_insn (state, instr))
+               break;
+#endif
+             dest = BITS (0, 11);
+             dest |= (BITS (16, 19) << 12);
+             WRITEDEST (dest);
              break;
 
            case 0x31:          /* TSTP immed */
@@ -2345,6 +3053,11 @@ check_PMUintr:
              if (DESTReg == 15)
                /* MSR immed to CPSR.  */
                ARMul_FixCPSR (state, instr, DPImmRHS);
+#ifdef MODE32
+             else if (state->is_v6
+                      && handle_v6_insn (state, instr))
+               break;
+#endif
              else
                UNDEF_Test;
              break;
@@ -2369,8 +3082,16 @@ check_PMUintr:
                }
              break;
 
-           case 0x34:          /* CMP immed */
-             UNDEF_Test;
+           case 0x34:          /* MOVT immed */
+#ifdef MODE32
+             if (state->is_v6
+                 && handle_v6_insn (state, instr))
+               break;
+#endif
+             DEST &= 0xFFFF;
+             dest  = BITS (0, 11);
+             dest |= (BITS (16, 19) << 12);
+             DEST |= (dest << 16);
              break;
 
            case 0x35:          /* CMPP immed */
@@ -2410,6 +3131,11 @@ check_PMUintr:
            case 0x36:          /* CMN immed and MSR immed to SPSR */
              if (DESTReg == 15)
                ARMul_FixSPSR (state, instr, DPImmRHS);
+#ifdef MODE32
+             else if (state->is_v6
+                      && handle_v6_insn (state, instr))
+               break;
+#endif
              else
                UNDEF_Test;
              break;
@@ -2727,6 +3453,11 @@ check_PMUintr:
            case 0x60:          /* Store Word, No WriteBack, Post Dec, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -2808,6 +3539,11 @@ check_PMUintr:
            case 0x64:          /* Store Byte, No WriteBack, Post Dec, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -2909,6 +3645,11 @@ check_PMUintr:
            case 0x69:          /* Load Word, No WriteBack, Post Inc, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -2990,6 +3731,11 @@ check_PMUintr:
            case 0x6d:          /* Load Byte, No WriteBack, Post Inc, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3066,6 +3812,11 @@ check_PMUintr:
            case 0x71:          /* Load Word, No WriteBack, Pre Dec, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3075,6 +3826,11 @@ check_PMUintr:
            case 0x72:          /* Store Word, WriteBack, Pre Dec, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3090,6 +3846,11 @@ check_PMUintr:
            case 0x73:          /* Load Word, WriteBack, Pre Dec, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3133,6 +3894,11 @@ check_PMUintr:
            case 0x76:          /* Store Byte, WriteBack, Pre Dec, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3148,6 +3914,11 @@ check_PMUintr:
            case 0x77:          /* Load Byte, WriteBack, Pre Dec, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3177,6 +3948,11 @@ check_PMUintr:
            case 0x79:          /* Load Word, No WriteBack, Pre Inc, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3206,6 +3982,11 @@ check_PMUintr:
            case 0x7b:          /* Load Word, WriteBack, Pre Inc, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3235,6 +4016,11 @@ check_PMUintr:
            case 0x7d:          /* Load Byte, No WriteBack, Pre Inc, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3244,6 +4030,11 @@ check_PMUintr:
            case 0x7e:          /* Store Byte, WriteBack, Pre Inc, Reg.  */
              if (BIT (4))
                {
+#ifdef MODE32
+                 if (state->is_v6
+                     && handle_v6_insn (state, instr))
+                   break;
+#endif
                  ARMul_UndefInstr (state, instr);
                  break;
                }
@@ -3267,6 +4058,11 @@ check_PMUintr:
                      if (!ARMul_OSHandleSWI (state, SWI_Breakpoint))
                        ARMul_Abort (state, ARMul_SWIV);
                    }
+#ifdef MODE32
+                 else if (state->is_v6
+                          && handle_v6_insn (state, instr))
+                   break;
+#endif
                  else
                    ARMul_UndefInstr (state, instr);
                  break;
@@ -3455,7 +4251,6 @@ check_PMUintr:
              FLUSHPIPE;
              break;
 
-
              /* Branch and Link forward.  */
            case 0xb0:
            case 0xb1:
@@ -3473,9 +4268,10 @@ check_PMUintr:
 #endif
              state->Reg[15] = pc + 8 + POSBRANCH;
              FLUSHPIPE;
+             if (trace_funcs)
+               fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
              break;
 
-
              /* Branch and Link backward.  */
            case 0xb8:
            case 0xb9:
@@ -3493,15 +4289,18 @@ check_PMUintr:
 #endif
              state->Reg[15] = pc + 8 + NEGBRANCH;
              FLUSHPIPE;
+             if (trace_funcs)
+               fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
              break;
 
-
              /* Co-Processor Data Transfers.  */
            case 0xc4:
              if (state->is_v5)
                {
+                 if (CPNum == 10 || CPNum == 11)
+                   handle_VFP_move (state, instr);
                  /* Reading from R15 is UNPREDICTABLE.  */
-                 if (BITS (12, 15) == 15 || BITS (16, 19) == 15)
+                 else if (BITS (12, 15) == 15 || BITS (16, 19) == 15)
                    ARMul_UndefInstr (state, instr);
                  /* Is access to coprocessor 0 allowed ?  */
                  else if (! CP_ACCESS_ALLOWED (state, CPNum))
@@ -3527,11 +4326,11 @@ check_PMUintr:
                    }
                  else
                    /* FIXME: Not sure what to do for other v5 processors.  */
-                   ARMul_UndefInstr (state, instr);                
+                   ARMul_UndefInstr (state, instr);
                  break;
                }
              /* Drop through.  */
-             
+
            case 0xc0:          /* Store , No WriteBack , Post Dec.  */
              ARMul_STC (state, instr, LHS);
              break;
@@ -3539,8 +4338,10 @@ check_PMUintr:
            case 0xc5:
              if (state->is_v5)
                {
+                 if (CPNum == 10 || CPNum == 11)
+                   handle_VFP_move (state, instr);
                  /* Writes to R15 are UNPREDICATABLE.  */
-                 if (DESTReg == 15 || LHSReg == 15)
+                 else if (DESTReg == 15 || LHSReg == 15)
                    ARMul_UndefInstr (state, instr);
                  /* Is access to the coprocessor allowed ?  */
                  else if (! CP_ACCESS_ALLOWED (state, CPNum))
@@ -3773,8 +4574,10 @@ check_PMUintr:
            case 0xee:
              if (BIT (4))
                {
+                 if (CPNum == 10 || CPNum == 11)
+                   handle_VFP_move (state, instr);
                  /* MCR.  */
-                 if (DESTReg == 15)
+                 else if (DESTReg == 15)
                    {
                      UNDEF_MCRPC;
 #ifdef MODE32
@@ -3804,17 +4607,69 @@ check_PMUintr:
            case 0xef:
              if (BIT (4))
                {
-                 /* MRC */
-                 temp = ARMul_MRC (state, instr);
-                 if (DESTReg == 15)
+                 if (CPNum == 10 || CPNum == 11)
                    {
-                     ASSIGNN ((temp & NBIT) != 0);
-                     ASSIGNZ ((temp & ZBIT) != 0);
-                     ASSIGNC ((temp & CBIT) != 0);
-                     ASSIGNV ((temp & VBIT) != 0);
+                     switch (BITS (20, 27))
+                       {
+                       case 0xEF:
+                         if (BITS (16, 19) == 0x1
+                             && BITS (0, 11) == 0xA10)
+                           {
+                             /* VMRS  */
+                             if (DESTReg == 15)
+                               {
+                                 ARMul_SetCPSR (state, (state->FPSCR & 0xF0000000)
+                                                | (ARMul_GetCPSR (state) & 0x0FFFFFFF));
+
+                                 if (trace)
+                                   fprintf (stderr, " VFP: VMRS: set flags to %c%c%c%c\n",
+                                            ARMul_GetCPSR (state) & NBIT ? 'N' : '-',
+                                            ARMul_GetCPSR (state) & ZBIT ? 'Z' : '-',
+                                            ARMul_GetCPSR (state) & CBIT ? 'C' : '-',
+                                            ARMul_GetCPSR (state) & VBIT ? 'V' : '-');
+                               }
+                             else
+                               {
+                                 state->Reg[DESTReg] = state->FPSCR;
+
+                                 if (trace)
+                                   fprintf (stderr, " VFP: VMRS: r%d = %x\n", DESTReg, state->Reg[DESTReg]);
+                               }
+                           }
+                         else
+                           fprintf (stderr, "SIM: VFP: Unimplemented: Compare op\n");
+                         break;
+
+                       case 0xE0:
+                       case 0xE1:
+                         /* VMOV reg <-> single precision.  */
+                         if (BITS (0,6) != 0x10 || BITS (8,11) != 0xA)
+                           fprintf (stderr, "SIM: VFP: Unimplemented: move op\n");
+                         else if (BIT (20))
+                           state->Reg[BITS (12, 15)] = VFP_uword (BITS (16, 19) << 1 | BIT (7));
+                         else
+                           VFP_uword (BITS (16, 19) << 1 | BIT (7)) = state->Reg[BITS (12, 15)];
+                         break;
+
+                       default:
+                         fprintf (stderr, "SIM: VFP: Unimplemented: CDP op\n");
+                         break;
+                       }
                    }
                  else
-                   DEST = temp;
+                   {
+                     /* MRC */
+                     temp = ARMul_MRC (state, instr);
+                     if (DESTReg == 15)
+                       {
+                         ASSIGNN ((temp & NBIT) != 0);
+                         ASSIGNZ ((temp & ZBIT) != 0);
+                         ASSIGNC ((temp & CBIT) != 0);
+                         ASSIGNV ((temp & VBIT) != 0);
+                       }
+                     else
+                       DEST = temp;
+                   }
                }
              else
                /* CDP Part 2.  */
@@ -3858,14 +4713,6 @@ check_PMUintr:
     donext:
 #endif
 
-#ifdef NEED_UI_LOOP_HOOK
-      if (deprecated_ui_loop_hook != NULL && ui_loop_hook_counter-- < 0)
-       {
-         ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL;
-         deprecated_ui_loop_hook (0);
-       }
-#endif /* NEED_UI_LOOP_HOOK */
-
       if (state->Emulate == ONCE)
        state->Emulate = STOP;
       /* If we have changed mode, allow the PC to advance before stopping.  */
@@ -4146,6 +4993,8 @@ WriteR15 (ARMul_State * state, ARMword src)
 #endif
 
   FLUSHPIPE;
+  if (trace_funcs)
+    fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
 }
 
 /* This routine handles writes to register 15 when the S bit is set.  */
@@ -4183,6 +5032,8 @@ WriteSR15 (ARMul_State * state, ARMword src)
   ARMul_R15Altered (state);
 #endif
   FLUSHPIPE;
+  if (trace_funcs)
+    fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
 }
 
 /* In machines capable of running in Thumb mode, BX, BLX, LDR and LDM
@@ -4204,11 +5055,24 @@ WriteR15Branch (ARMul_State * state, ARMword src)
       state->Reg[15] = src & 0xfffffffc;
     }
   FLUSHPIPE;
+  if (trace_funcs)
+    fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
 #else
   WriteR15 (state, src);
 #endif
 }
 
+/* Before ARM_v5 LDR and LDM of pc did not change mode.  */
+
+static void
+WriteR15Load (ARMul_State * state, ARMword src)
+{
+  if (state->is_v5)
+    WriteR15Branch (state, src);
+  else
+    WriteR15 (state, src);
+}
+
 /* This routine evaluates most Load and Store register RHS's.  It is
    intended to be called from the macro LSRegRHS, which filters the
    common case of an unshifted register with in line code.  */
@@ -4372,7 +5236,7 @@ Handle_Load_Double (ARMul_State * state, ARMword instr)
   ARMword addr_reg;
   ARMword write_back  = BIT (21);
   ARMword immediate   = BIT (22);
-  ARMword add_to_base = BIT (23);        
+  ARMword add_to_base = BIT (23);
   ARMword pre_indexed = BIT (24);
   ARMword offset;
   ARMword addr;
@@ -4380,7 +5244,7 @@ Handle_Load_Double (ARMul_State * state, ARMword instr)
   ARMword base;
   ARMword value1;
   ARMword value2;
-  
+
   BUSUSEDINCPCS;
 
   /* If the writeback bit is set, the pre-index bit must be clear.  */
@@ -4389,13 +5253,13 @@ Handle_Load_Double (ARMul_State * state, ARMword instr)
       ARMul_UndefInstr (state, instr);
       return;
     }
-  
+
   /* Extract the base address register.  */
   addr_reg = LHSReg;
-  
+
   /* Extract the destination register and check it.  */
   dest_reg = DESTReg;
-  
+
   /* Destination register must be even.  */
   if ((dest_reg & 1)
     /* Destination register cannot be LR.  */
@@ -4416,15 +5280,18 @@ Handle_Load_Double (ARMul_State * state, ARMword instr)
     sum = base + offset;
   else
     sum = base - offset;
-  
+
   /* If this is a pre-indexed mode use the sum.  */
   if (pre_indexed)
     addr = sum;
   else
     addr = base;
 
+  if (state->is_v6 && (addr & 0x3) == 0)
+    /* Word alignment is enough for v6.  */
+    ;
   /* The address must be aligned on a 8 byte boundary.  */
-  if (addr & 0x7)
+  else if (addr & 0x7)
     {
 #ifdef ABORTS
       ARMul_DATAABORT (addr);
@@ -4455,17 +5322,17 @@ Handle_Load_Double (ARMul_State * state, ARMword instr)
       TAKEABORT;
       return;
     }
-  
+
   ARMul_Icycles (state, 2, 0L);
 
   /* Store the values.  */
   state->Reg[dest_reg] = value1;
   state->Reg[dest_reg + 1] = value2;
-  
+
   /* Do the post addressing and writeback.  */
   if (! pre_indexed)
     addr = sum;
-  
+
   if (! pre_indexed || write_back)
     state->Reg[addr_reg] = addr;
 }
@@ -4479,7 +5346,7 @@ Handle_Store_Double (ARMul_State * state, ARMword instr)
   ARMword addr_reg;
   ARMword write_back  = BIT (21);
   ARMword immediate   = BIT (22);
-  ARMword add_to_base = BIT (23);        
+  ARMword add_to_base = BIT (23);
   ARMword pre_indexed = BIT (24);
   ARMword offset;
   ARMword addr;
@@ -4494,20 +5361,20 @@ Handle_Store_Double (ARMul_State * state, ARMword instr)
       ARMul_UndefInstr (state, instr);
       return;
     }
-  
+
   /* Extract the base address register.  */
   addr_reg = LHSReg;
-  
+
   /* Base register cannot be PC.  */
   if (addr_reg == 15)
     {
       ARMul_UndefInstr (state, instr);
       return;
     }
-  
+
   /* Extract the source register.  */
   src_reg = DESTReg;
-  
+
   /* Source register must be even.  */
   if (src_reg & 1)
     {
@@ -4526,7 +5393,7 @@ Handle_Store_Double (ARMul_State * state, ARMword instr)
     sum = base + offset;
   else
     sum = base - offset;
-  
+
   /* If this is a pre-indexed mode use the sum.  */
   if (pre_indexed)
     addr = sum;
@@ -4558,17 +5425,17 @@ Handle_Store_Double (ARMul_State * state, ARMword instr)
   /* Load the words.  */
   ARMul_StoreWordN (state, addr, state->Reg[src_reg]);
   ARMul_StoreWordN (state, addr + 4, state->Reg[src_reg + 1]);
-  
+
   if (state->Aborted)
     {
       TAKEABORT;
       return;
     }
-  
+
   /* Do the post addressing and writeback.  */
   if (! pre_indexed)
     addr = sum;
-  
+
   if (! pre_indexed || write_back)
     state->Reg[addr_reg] = addr;
 }
@@ -4721,7 +5588,7 @@ LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase)
 
   if (BIT (15) && !state->Aborted)
     /* PC is in the reg list.  */
-    WriteR15Branch (state, PC);
+    WriteR15Load (state, PC);
 
   /* To write back the final register.  */
   ARMul_Icycles (state, 1, 0L);
@@ -4965,7 +5832,7 @@ StoreSMult (ARMul_State * state,
 
   for (temp = 0; !BIT (temp); temp++)
     ;  /* N cycle first.  */
-  
+
 #ifdef MODE32
   ARMul_StoreWordN (state, address, state->Reg[temp++]);
 #else
@@ -5071,9 +5938,7 @@ Multiply64 (ARMul_State * state, ARMword instr, int msigned, int scc)
       && nRdLo != 15
       && nRs   != 15
       && nRm   != 15
-      && nRdHi != nRdLo
-      && nRdHi != nRm
-      && nRdLo != nRm)
+      && nRdHi != nRdLo)
     {
       /* Intermediate results.  */
       ARMword lo, mid1, mid2, hi;
@@ -5081,6 +5946,15 @@ Multiply64 (ARMul_State * state, ARMword instr, int msigned, int scc)
       ARMword Rs = state->Reg[nRs];
       int sign = 0;
 
+#ifdef MODE32
+      if (state->is_v6)
+       ;
+      else
+#endif
+       if (nRdHi == nRm || nRdLo == nRm)
+         fprintf (stderr, "sim: MULTIPLY64 - INVALID ARGUMENTS: %d %d %d\n",
+                  nRdHi, nRdLo, nRm);
+
       if (msigned)
        {
          /* Compute sign of result and adjust operands if necessary.  */