sim: add helper macros for branch profiling
[deliverable/binutils-gdb.git] / sim / arm / thumbemu.c
index dc90dd7cf486ddf974b02634f40c651b52f2e62c..8707ca71a64b09a498750b5717d3ba551d7d9dc1 100644 (file)
@@ -13,7 +13,7 @@
  
     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. */
+    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
 
 /* We can provide simple Thumb simulation by decoding the Thumb
 instruction into its corresponding ARM instruction, and using the
@@ -31,20 +31,74 @@ existing ARM simulator.  */
 #include "armemu.h"
 #include "armos.h"
 
+/* Attempt to emulate an ARMv6 instruction.
+   Stores t_branch into PVALUE upon success or t_undefined otherwise.  */
+
+static void
+handle_v6_thumb_insn (ARMul_State * state,
+                     ARMword       tinstr,
+                     tdstate *     pvalid)
+{
+  ARMword Rd;
+  ARMword Rm;
+
+  if (! state->is_v6)
+    {
+      * pvalid = t_undefined;
+      return;
+    }
+
+  switch (tinstr & 0xFFC0)
+    {
+    case 0xb660: /* cpsie */
+    case 0xb670: /* cpsid */
+    case 0x4600: /* cpy */
+    case 0xba00: /* rev */
+    case 0xba40: /* rev16 */
+    case 0xbac0: /* revsh */
+    case 0xb650: /* setend */
+    default:  
+      printf ("Unhandled v6 thumb insn: %04x\n", tinstr);
+      * pvalid = t_undefined;
+      return;
+
+    case 0xb200: /* sxth */
+      Rm = state->Reg [(tinstr & 0x38) >> 3];
+      if (Rm & 0x8000)
+       state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000;
+      else
+       state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
+      break;
+    case 0xb240: /* sxtb */
+      Rm = state->Reg [(tinstr & 0x38) >> 3];
+      if (Rm & 0x80)
+       state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00;
+      else
+       state->Reg [(tinstr & 0x7)] = Rm & 0xff;
+      break;
+    case 0xb280: /* uxth */
+      Rm = state->Reg [(tinstr & 0x38) >> 3];
+      state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
+      break;
+    case 0xb2c0: /* uxtb */
+      Rm = state->Reg [(tinstr & 0x38) >> 3];
+      state->Reg [(tinstr & 0x7)] = Rm & 0xff;
+      break;
+    }
+  /* Indicate that the instruction has been processed.  */
+  * pvalid = t_branch;
+}
+
 /* Decode a 16bit Thumb instruction.  The instruction is in the low
    16-bits of the tinstr field, with the following Thumb instruction
    held in the high 16-bits.  Passing in two Thumb instructions allows
    easier simulation of the special dual BL instruction.  */
 
-tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
-     ARMul_State *
-       state;
-     ARMword
-       pc;
-     ARMword
-       tinstr;
-     ARMword *
-       ainstr;
+tdstate
+ARMul_ThumbDecode (ARMul_State * state,
+                  ARMword       pc,
+                  ARMword       tinstr,
+                  ARMword *     ainstr)
 {
   tdstate valid = t_decoded;   /* default assumes a valid instruction */
   ARMword next_instr;
@@ -209,12 +263,20 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
              *ainstr = 0xE12FFF10      /* base */
                | ((tinstr & 0x0078) >> 3);     /* Rd */
              break;
+           case 0xE:           /* UNDEFINED */
+           case 0xF:           /* UNDEFINED */
+             if (state->is_v5)
+               {
+                 /* BLX Rs; BLX Hs */
+                 *ainstr = 0xE12FFF30  /* base */
+                   | ((tinstr & 0x0078) >> 3); /* Rd */
+                 break;
+               }
+             /* Drop through.  */
            case 0x0:           /* UNDEFINED */
            case 0x4:           /* UNDEFINED */
            case 0x8:           /* UNDEFINED */
-           case 0xE:           /* UNDEFINED */
-           case 0xF:           /* UNDEFINED */
-             valid = t_undefined;
+             handle_v6_thumb_insn (state, tinstr, & valid);
              break;
            }
        }
@@ -322,30 +384,48 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
       break;
     case 22:
     case 23:
-      if ((tinstr & 0x0F00) == 0x0000)
+      switch (tinstr & 0x0F00)
        {
+       case 0x0000:
          /* Format 13 */
          /* NOTE: The instruction contains a shift left of 2
-            equivalent (implemented as ROR #30): */
+            equivalent (implemented as ROR #30):  */
          *ainstr = ((tinstr & (1 << 7))        /* base */
                     ? 0xE24DDF00       /* SUB */
                     : 0xE28DDF00)      /* ADD */
            | (tinstr & 0x007F);        /* off7 */
-       }
-      else if ((tinstr & 0x0F00) == 0x0e00)
-       *ainstr = 0xEF000000 | SWI_Breakpoint;
-      else
-       {
-         /* Format 14 */
-         ARMword subset[4] = {
-           0xE92D0000,         /* STMDB sp!,{rlist}    */
-           0xE92D4000,         /* STMDB sp!,{rlist,lr} */
-           0xE8BD0000,         /* LDMIA sp!,{rlist}    */
-           0xE8BD8000          /* LDMIA sp!,{rlist,pc} */
-         };
-         *ainstr = subset[((tinstr & (1 << 11)) >> 10)
-                          | ((tinstr & (1 << 8)) >> 8)]        /* base */
-           | (tinstr & 0x00FF);        /* mask8 */
+         break;
+       case 0x0400:
+         /* Format 14 - Push */
+         * ainstr = 0xE92D0000 | (tinstr & 0x00FF);
+         break;
+       case 0x0500:
+         /* Format 14 - Push + LR */
+         * ainstr = 0xE92D4000 | (tinstr & 0x00FF);
+         break;
+       case 0x0c00:
+         /* Format 14 - Pop */
+         * ainstr = 0xE8BD0000 | (tinstr & 0x00FF);
+         break;
+       case 0x0d00:
+         /* Format 14 - Pop + PC */
+         * ainstr = 0xE8BD8000 | (tinstr & 0x00FF);
+         break;
+       case 0x0e00:
+         if (state->is_v5)
+           {
+             /* This is normally an undefined instruction.  The v5t architecture 
+                defines this particular pattern as a BKPT instruction, for
+                hardware assisted debugging.  We map onto the arm BKPT
+                instruction.  */
+             * ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
+             break;
+           }
+         /* Drop through.  */
+       default:
+         /* Everything else is an undefined instruction.  */
+         handle_v6_thumb_insn (state, tinstr, & valid);
+         break;
        }
       break;
     case 24:                   /* STMIA */
@@ -434,8 +514,9 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
            }
          valid = t_branch;
        }
-      else                     /* UNDEFINED : cc=1110(AL) uses different format */
-       valid = t_undefined;
+      else
+       /* UNDEFINED : cc=1110(AL) uses different format.  */
+       handle_v6_thumb_insn (state, tinstr, & valid);
       break;
     case 28:                   /* B */
       /* Format 18 */
@@ -446,8 +527,37 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
       valid = t_branch;
       break;
     case 29:                   /* UNDEFINED */
-      valid = t_undefined;
+      if (state->is_v5)
+       {
+         if (tinstr & 1)
+           {
+             handle_v6_thumb_insn (state, tinstr, & valid);
+             break;
+           }
+         /* Drop through.  */
+         
+         /* Format 19 */
+         /* There is no single ARM instruction equivalent for this
+            instruction. Also, it should only ever be matched with the
+            fmt19 "BL/BLX instruction 1" instruction.  However, we do
+            allow the simulation of it on its own, with undefined results
+            if r14 is not suitably initialised.  */
+         {
+           ARMword tmp = (pc + 2);
+
+           state->Reg[15] = ((state->Reg[14] + ((tinstr & 0x07FF) << 1))
+                             & 0xFFFFFFFC);
+           CLEART;
+           state->Reg[14] = (tmp | 1);
+           valid = t_branch;
+           FLUSHPIPE;
+           break;
+         }
+       }
+
+      handle_v6_thumb_insn (state, tinstr, & valid);
       break;
+
     case 30:                   /* BL instruction 1 */
       /* Format 19 */
       /* There is no single ARM instruction equivalent for this Thumb
@@ -456,12 +566,31 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
          second half of this BL, and if it is we simulate it
          immediately.  */
       state->Reg[14] = state->Reg[15] \
-       +(((tinstr & 0x07FF) << 12) \
-         |((tinstr & (1 << 10)) ? 0xFF800000 : 0));
+       + (((tinstr & 0x07FF) << 12) \
+          | ((tinstr & (1 << 10)) ? 0xFF800000 : 0));
+
       valid = t_branch;                /* in-case we don't have the 2nd half */
       tinstr = next_instr;     /* move the instruction down */
+      pc += 2;                 /* point the pc at the 2nd half */
       if (((tinstr & 0xF800) >> 11) != 31)
-       break;                  /* exit, since not correct instruction */
+       {
+         if (((tinstr & 0xF800) >> 11) == 29)
+           {
+             ARMword tmp = (pc + 2);
+
+             state->Reg[15] = ((state->Reg[14]
+                                + ((tinstr & 0x07FE) << 1))
+                               & 0xFFFFFFFC);
+             CLEART;
+             state->Reg[14] = (tmp | 1);
+             valid = t_branch;
+             FLUSHPIPE;
+           }
+         else
+           /* Exit, since not correct instruction. */
+           pc -= 2;
+         break;
+       }
       /* else we fall through to process the second half of the BL */
       pc += 2;                 /* point the pc at the 2nd half */
     case 31:                   /* BL instruction 2 */
@@ -472,7 +601,8 @@ tdstate ARMul_ThumbDecode (state, pc, tinstr, ainstr)
          the simulation of it on its own, with undefined results if
          r14 is not suitably initialised.  */
       {
-       ARMword tmp = (pc + 2);
+       ARMword tmp = pc;
+
        state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
        state->Reg[14] = (tmp | 1);
        valid = t_branch;
This page took 0.026292 seconds and 4 git commands to generate.