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
#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;
*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;
}
}
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 */
}
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 */
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
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 */
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;