aboutsummaryrefslogtreecommitdiff
path: root/sim/arm/thumbemu.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2015-06-28 19:14:36 +0100
committerNick Clifton <nickc@redhat.com>2015-06-28 19:14:36 +0100
commit73cb0348b296656e971c4d428aa63781e656a1c4 (patch)
treeddb71aae6c4ea1858ed6307f71451a72ff1c6919 /sim/arm/thumbemu.c
parentee0c0c503deffb7baf900ac8e092b18bf8c1528a (diff)
downloadgdb-73cb0348b296656e971c4d428aa63781e656a1c4.zip
gdb-73cb0348b296656e971c4d428aa63781e656a1c4.tar.gz
gdb-73cb0348b296656e971c4d428aa63781e656a1c4.tar.bz2
Add support for ARM v6 instructions.
* Makefile.in (SIM_EXTRA_CFLAGS): Add -lm. * armdefs.h (ARMdval, ARMfval): New types. (ARM_VFP_reg): New union. (struct ARMul_State): Add VFP_Reg and FPSCR fields. (VFP_fval, VFP_uword, VFP_sword, VFP_dval, VFP_dword): Accessor macros for the new VFP_Reg field. * armemu.c (handle_v6_insn): Add code to handle MOVW, MOVT, QADD16, QASX, QSAX, QSUB16, QADD8, QSUB8, UADD16, USUB16, UADD8, USUB8, SEL, REV, REV16, RBIT, BFC, BFI, SBFX and UBFX instructions. (handle_VFP_move): New function. (ARMul_Emulate16): Add checks for newly supported v6 instructions. Add support for VMRS, VMOV and MRC instructions. (Multiply64): Allow nRdHi == nRm and/or nRdLo == nRm when operating in v6 mode. * armemu.h (t_resolved): Define. * armsupp.c: Include math.h. (handle_VFP_xfer): New function. Handles VMOV, VSTM, VSTR, VPUSH, VSTM, VLDM and VPOP instructions. (ARMul_LDC): Test for co-processor 10 or 11 and pass call to the new handle_VFP_xfer function. (ARMul_STC): Likewise. (handle_VFP_op): New function. Handles VMLA, VMLS, VNMLA, VNMLS, VNMUL, VMUL, VADD, VSUB, VDIV, VMOV, VABS, VNEG, VSQRT, VCMP, VCMPE and VCVT instructions. (ARMul_CDP): Test for co-processor 10 or 11 and pass call to the new handle_VFP_op function. * thumbemu.c (tBIT, tBITS, ntBIT, ntBITS): New macros. (test_cond): New function. Tests a condition and returns non-zero if the condition has been met. (handle_IT_block): New function. (in_IT_block): New function. (IT_block_allow): New function. (ThumbExpandImm): New function. (handle_T2_insn): New function. Handles T2 thumb instructions. (handle_v6_thumb_insn): Add next_instr and pc parameters. (ARMul_ThumbDecode): Add support for IT blocks. Add support for v6 instructions. * wrapper.c (sim_create_inferior): Detect a thumb address and call SETT appropriately.
Diffstat (limited to 'sim/arm/thumbemu.c')
-rw-r--r--sim/arm/thumbemu.c2028
1 files changed, 1994 insertions, 34 deletions
diff --git a/sim/arm/thumbemu.c b/sim/arm/thumbemu.c
index e4c91f6..40c365e 100644
--- a/sim/arm/thumbemu.c
+++ b/sim/arm/thumbemu.c
@@ -30,12 +30,1788 @@ existing ARM simulator. */
#include "armemu.h"
#include "armos.h"
+#define tBIT(n) ( (ARMword)(tinstr >> (n)) & 1)
+#define tBITS(m,n) ( (ARMword)(tinstr << (31 - (n))) >> ((31 - (n)) + (m)) )
+
+#define ntBIT(n) ( (ARMword)(next_instr >> (n)) & 1)
+#define ntBITS(m,n) ( (ARMword)(next_instr << (31 - (n))) >> ((31 - (n)) + (m)) )
+
+static int
+test_cond (int cond, ARMul_State * state)
+{
+ switch (cond)
+ {
+ case EQ: return ZFLAG;
+ case NE: return !ZFLAG;
+ case VS: return VFLAG;
+ case VC: return !VFLAG;
+ case MI: return NFLAG;
+ case PL: return !NFLAG;
+ case CS: return CFLAG;
+ case CC: return !CFLAG;
+ case HI: return (CFLAG && !ZFLAG);
+ case LS: return (!CFLAG || ZFLAG);
+ case GE: return ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
+ case LT: return ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
+ case GT: return ((!NFLAG && !VFLAG && !ZFLAG)
+ || (NFLAG && VFLAG && !ZFLAG));
+ case LE: return ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
+ case AL: return TRUE;
+ case NV:
+ default: return FALSE;
+ }
+}
+
+static ARMword skipping_32bit_thumb = 0;
+
+static int IT_block_cond = AL;
+static ARMword IT_block_mask = 0;
+static int IT_block_first = FALSE;
+
+static void
+handle_IT_block (ARMul_State * state,
+ ARMword tinstr,
+ tdstate * pvalid)
+{
+ * pvalid = t_branch;
+ IT_block_mask = tBITS (0, 3);
+
+ if (IT_block_mask == 0)
+ // NOP or a HINT.
+ return;
+
+ IT_block_cond = tBITS (4, 7);
+ IT_block_first = TRUE;
+}
+
+static int
+in_IT_block (void)
+{
+ return IT_block_mask != 0;
+}
+
+static int
+IT_block_allow (ARMul_State * state)
+{
+ int cond;
+
+ if (IT_block_mask == 0)
+ return TRUE;
+
+ cond = IT_block_cond;
+
+ if (IT_block_first)
+ IT_block_first = FALSE;
+ else
+ {
+ if ((IT_block_mask & 8) == 0)
+ cond &= 0xe;
+ else
+ cond |= 1;
+ IT_block_mask <<= 1;
+ IT_block_mask &= 0xF;
+ }
+
+ if (IT_block_mask == 0x8)
+ IT_block_mask = 0;
+
+ return test_cond (cond, state);
+}
+
+static ARMword
+ThumbExpandImm (ARMword tinstr)
+{
+ ARMword val;
+
+ if (tBITS (10, 11) == 0)
+ {
+ switch (tBITS (8, 9))
+ {
+ case 0: val = tBITS (0, 7); break;
+ case 1: val = tBITS (0, 7) << 8; break;
+ case 2: val = (tBITS (0, 7) << 8) | (tBITS (0, 7) << 24); break;
+ case 3: val = tBITS (0, 7) * 0x01010101; break;
+ default: val = 0;
+ }
+ }
+ else
+ {
+ int ror = tBITS (7, 11);
+
+ val = (1 << 7) | tBITS (0, 6);
+ val = (val >> ror) | (val << (32 - ror));
+ }
+
+ return val;
+}
+
+#define tASSERT(truth) \
+ do \
+ { \
+ if (! (truth)) \
+ { \
+ fprintf (stderr, "unhandled T2 insn %04x|%04x detected at thumbemu.c:%d\n", \
+ tinstr, next_instr, __LINE__); \
+ return ; \
+ } \
+ } \
+ while (0)
+
+
+/* Attempt to emulate a 32-bit ARMv7 Thumb instruction.
+ Stores t_branch into PVALUE upon success or t_undefined otherwise. */
+
+static void
+handle_T2_insn (ARMul_State * state,
+ ARMword tinstr,
+ ARMword next_instr,
+ ARMword pc,
+ ARMword * ainstr,
+ tdstate * pvalid)
+{
+ * pvalid = t_undefined;
+
+ if (! state->is_v6)
+ return;
+
+ if (trace)
+ fprintf (stderr, "|%04x ", next_instr);
+
+ if (tBITS (11, 15) == 0x1E && ntBIT (15) == 1)
+ {
+ ARMsword simm32 = 0;
+ int S = tBIT (10);
+
+ * pvalid = t_branch;
+ switch ((ntBIT (14) << 1) | ntBIT (12))
+ {
+ case 0: /* B<c>.W */
+ {
+ ARMword cond = tBITS (6, 9);
+ ARMword imm6;
+ ARMword imm11;
+ ARMword J1;
+ ARMword J2;
+
+ tASSERT (cond != AL && cond != NV);
+ if (! test_cond (cond, state))
+ return;
+
+ imm6 = tBITS (0, 5);
+ imm11 = ntBITS (0, 10);
+ J1 = ntBIT (13);
+ J2 = ntBIT (11);
+
+ simm32 = (J1 << 19) | (J2 << 18) | (imm6 << 12) | (imm11 << 1);
+ if (S)
+ simm32 |= (-1 << 20);
+ break;
+ }
+
+ case 1: /* B.W */
+ {
+ ARMword imm10 = tBITS (0, 9);
+ ARMword imm11 = ntBITS (0, 10);
+ ARMword I1 = (ntBIT (13) ^ S) ? 0 : 1;
+ ARMword I2 = (ntBIT (11) ^ S) ? 0 : 1;
+
+ simm32 = (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
+ if (S)
+ simm32 |= (-1 << 24);
+ break;
+ }
+
+ case 2: /* BLX <label> */
+ {
+ ARMword imm10h = tBITS (0, 9);
+ ARMword imm10l = ntBITS (1, 10);
+ ARMword I1 = (ntBIT (13) ^ S) ? 0 : 1;
+ ARMword I2 = (ntBIT (11) ^ S) ? 0 : 1;
+
+ simm32 = (I1 << 23) | (I2 << 22) | (imm10h << 12) | (imm10l << 2);
+ if (S)
+ simm32 |= (-1 << 24);
+
+ CLEART;
+ state->Reg[14] = (pc + 4) | 1;
+ break;
+ }
+
+ case 3: /* BL <label> */
+ {
+ ARMword imm10 = tBITS (0, 9);
+ ARMword imm11 = ntBITS (0, 10);
+ ARMword I1 = (ntBIT (13) ^ S) ? 0 : 1;
+ ARMword I2 = (ntBIT (11) ^ S) ? 0 : 1;
+
+ simm32 = (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
+ if (S)
+ simm32 |= (-1 << 24);
+ state->Reg[14] = (pc + 4) | 1;
+ break;
+ }
+ }
+
+ state->Reg[15] = (pc + 4 + simm32);
+ FLUSHPIPE;
+ if (trace_funcs)
+ fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
+ return;
+ }
+
+ switch (tBITS (5,12))
+ {
+ case 0x29: // TST<c>.W <Rn>,<Rm>{,<shift>}
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rm = ntBITS (0, 3);
+ ARMword type = ntBITS (4, 5);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+
+ tASSERT (ntBITS (8, 11) == 0xF);
+
+ * ainstr = 0xE1100000;
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rm);
+ * ainstr |= (type << 5);
+ * ainstr |= (imm5 << 7);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x46:
+ if (tBIT (4) && ntBITS (5, 15) == 0x780)
+ {
+ // Table Branch
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rm = ntBITS (0, 3);
+ ARMword address, dest;
+
+ if (ntBIT (4))
+ {
+ // TBH
+ address = state->Reg[Rn] + state->Reg[Rm] * 2;
+ dest = ARMul_LoadHalfWord (state, address);
+ }
+ else
+ {
+ // TBB
+ address = state->Reg[Rn] + state->Reg[Rm];
+ dest = ARMul_LoadByte (state, address);
+ }
+
+ state->Reg[15] = (pc + 4 + dest * 2);
+ FLUSHPIPE;
+ * pvalid = t_branch;
+ break;
+ }
+ /* Fall through. */
+ case 0x42:
+ case 0x43:
+ case 0x47:
+ case 0x4A:
+ case 0x4B:
+ case 0x4E: // STRD
+ case 0x4F: // LDRD
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rt = ntBITS (12, 15);
+ ARMword Rt2 = ntBITS (8, 11);
+ ARMword imm8 = ntBITS (0, 7);
+ ARMword P = tBIT (8);
+ ARMword U = tBIT (7);
+ ARMword W = tBIT (5);
+
+ tASSERT (Rt2 == Rt + 1);
+ imm8 <<= 2;
+ tASSERT (imm8 <= 255);
+ tASSERT (P != 0 || W != 0);
+
+ // Convert into an ARM A1 encoding.
+ if (Rn == 15)
+ {
+ tASSERT (tBIT (4) == 1);
+ // LDRD (literal)
+ // Ignore W even if 1.
+ * ainstr = 0xE14F00D0;
+ }
+ else
+ {
+ if (tBIT (4) == 1)
+ // LDRD (immediate)
+ * ainstr = 0xE04000D0;
+ else
+ {
+ // STRD<c> <Rt>,<Rt2>,[<Rn>{,#+/-<imm8>}]
+ // STRD<c> <Rt>,<Rt2>,[<Rn>],#+/-<imm8>
+ // STRD<c> <Rt>,<Rt2>,[<Rn>,#+/-<imm8>]!
+ * ainstr = 0xE04000F0;
+ }
+ * ainstr |= (Rn << 16);
+ * ainstr |= (P << 24);
+ * ainstr |= (W << 21);
+ }
+
+ * ainstr |= (U << 23);
+ * ainstr |= (Rt << 12);
+ * ainstr |= ((imm8 << 4) & 0xF00);
+ * ainstr |= (imm8 & 0xF);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x44:
+ case 0x45: // LDMIA
+ {
+ ARMword Rn = tBITS (0, 3);
+ int W = tBIT (5);
+ ARMword list = (ntBIT (15) << 15) | (ntBIT (14) << 14) | ntBITS (0, 12);
+
+ if (Rn == 13)
+ * ainstr = 0xE8BD0000;
+ else
+ {
+ * ainstr = 0xE8900000;
+ * ainstr |= (W << 21);
+ * ainstr |= (Rn << 16);
+ }
+ * ainstr |= list;
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x48:
+ case 0x49: // STMDB
+ {
+ ARMword Rn = tBITS (0, 3);
+ int W = tBIT (5);
+ ARMword list = (ntBIT (14) << 14) | ntBITS (0, 12);
+
+ if (Rn == 13 && W)
+ * ainstr = 0xE92D0000;
+ else
+ {
+ * ainstr = 0xE9000000;
+ * ainstr |= (W << 21);
+ * ainstr |= (Rn << 16);
+ }
+ * ainstr |= list;
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x50:
+ {
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rm = ntBITS (0, 3);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword type = ntBITS (4, 5);
+
+ tASSERT (ntBIT (15) == 0);
+
+ if (Rd == 15)
+ {
+ tASSERT (tBIT (4) == 1);
+
+ // TST<c>.W <Rn>,<Rm>{,<shift>}
+ * ainstr = 0xE1100000;
+ }
+ else
+ {
+ // AND{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ int S = tBIT (4);
+
+ * ainstr = 0xE0000000;
+
+ if (in_IT_block ())
+ S = 0;
+ * ainstr |= (S << 20);
+ }
+
+ * ainstr |= (Rn << 16);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (type << 5);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x51: // BIC{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword S = tBIT(4);
+ ARMword Rm = ntBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword type = ntBITS (4, 5);
+
+ tASSERT (ntBIT (15) == 0);
+
+ * ainstr = 0xE1C00000;
+ * ainstr |= (S << 20);
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rd << 12);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (type << 5);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x52:
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+ int S = tBIT (4);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword type = ntBITS (4, 5);
+
+ tASSERT (Rd != 15);
+
+ if (in_IT_block ())
+ S = 0;
+
+ if (Rn == 15)
+ {
+ tASSERT (ntBIT (15) == 0);
+
+ switch (ntBITS (4, 5))
+ {
+ case 0:
+ // LSL{S}<c>.W <Rd>,<Rm>,#<imm5>
+ * ainstr = 0xE1A00000;
+ break;
+ case 1:
+ // LSR{S}<c>.W <Rd>,<Rm>,#<imm>
+ * ainstr = 0xE1A00020;
+ break;
+ case 2:
+ // ASR{S}<c>.W <Rd>,<Rm>,#<imm>
+ * ainstr = 0xE1A00040;
+ break;
+ case 3:
+ // ROR{S}<c> <Rd>,<Rm>,#<imm>
+ * ainstr = 0xE1A00060;
+ break;
+ default:
+ tASSERT (0);
+ * ainstr = 0;
+ }
+ }
+ else
+ {
+ // ORR{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ * ainstr = 0xE1800000;
+ * ainstr |= (Rn << 16);
+ * ainstr |= (type << 5);
+ }
+
+ * ainstr |= (Rd << 12);
+ * ainstr |= (S << 20);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x53: // MVN{S}<c>.W <Rd>,<Rm>{,<shift>}
+ {
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+ int S = tBIT (4);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword type = ntBITS (4, 5);
+
+ tASSERT (ntBIT (15) == 0);
+
+ if (in_IT_block ())
+ S = 0;
+
+ * ainstr = 0xE1E00000;
+ * ainstr |= (S << 20);
+ * ainstr |= (Rd << 12);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (type << 5);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x54:
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+ int S = tBIT (4);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword type = ntBITS (4, 5);
+
+ if (Rd == 15 && S)
+ {
+ // TEQ<c> <Rn>,<Rm>{,<shift>}
+ tASSERT (ntBIT (15) == 0);
+
+ * ainstr = 0xE1300000;
+ }
+ else
+ {
+ // EOR{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ if (in_IT_block ())
+ S = 0;
+
+ * ainstr = 0xE0200000;
+ * ainstr |= (S << 20);
+ * ainstr |= (Rd << 8);
+ }
+
+ * ainstr |= (Rn << 16);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (type << 5);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x58: // ADD{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+ int S = tBIT (4);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword type = ntBITS (4, 5);
+
+ tASSERT (! (Rd == 15 && S));
+
+ if (in_IT_block ())
+ S = 0;
+
+ * ainstr = 0xE0800000;
+ * ainstr |= (S << 20);
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rd << 12);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (type << 5);
+ * ainstr |= Rm;
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x5A: // ADC{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ tASSERT (ntBIT (15) == 0);
+ * ainstr = 0xE0A00000;
+ if (! in_IT_block ())
+ * ainstr |= (tBIT (4) << 20); // S
+ * ainstr |= (tBITS (0, 3) << 16); // Rn
+ * ainstr |= (ntBITS (8, 11) << 12); // Rd
+ * ainstr |= ((ntBITS (12, 14) << 2) | ntBITS (6, 7)) << 7; // imm5
+ * ainstr |= (ntBITS (4, 5) << 5); // type
+ * ainstr |= ntBITS (0, 3); // Rm
+ * pvalid = t_decoded;
+ break;
+
+ case 0x5B: // SBC{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+ int S = tBIT (4);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword type = ntBITS (4, 5);
+
+ tASSERT (ntBIT (15) == 0);
+
+ if (in_IT_block ())
+ S = 0;
+
+ * ainstr = 0xE0C00000;
+ * ainstr |= (S << 20);
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rd << 12);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (type << 5);
+ * ainstr |= Rm;
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x5E: // RSB{S}<c> <Rd>,<Rn>,<Rm>{,<shift>}
+ case 0x5D: // SUB{S}<c>.W <Rd>,<Rn>,<Rm>{,<shift>}
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+ ARMword S = tBIT (4);
+ ARMword type = ntBITS (4, 5);
+ ARMword imm5 = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+
+ tASSERT (ntBIT(15) == 0);
+
+ if (Rd == 15)
+ {
+ // CMP<c>.W <Rn>, <Rm> {,<shift>}
+ * ainstr = 0xE1500000;
+ Rd = 0;
+ }
+ else if (tBIT (5))
+ * ainstr = 0xE0400000;
+ else
+ * ainstr = 0xE0600000;
+
+ * ainstr |= (S << 20);
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rd << 12);
+ * ainstr |= (imm5 << 7);
+ * ainstr |= (type << 5);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0x9D: // NOP.W
+ tASSERT (tBITS (0, 15) == 0xF3AF);
+ tASSERT (ntBITS (0, 15) == 0x8000);
+ * pvalid = t_branch;
+ break;
+
+ case 0x80: // AND
+ case 0xA0: // TST
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword imm12 = (tBIT(10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword val;
+ int S = tBIT (4);
+
+ imm12 = ThumbExpandImm (imm12);
+ val = state->Reg[Rn] & imm12;
+
+ if (Rd == 15)
+ {
+ // TST<c> <Rn>,#<const>
+ tASSERT (S == 1);
+ }
+ else
+ {
+ // AND{S}<c> <Rd>,<Rn>,#<const>
+ if (in_IT_block ())
+ S = 0;
+
+ state->Reg[Rd] = val;
+ }
+
+ if (S)
+ ARMul_NegZero (state, val);
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xA1:
+ case 0x81: // BIC.W
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword S = tBIT (4);
+ ARMword imm8 = (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+
+ tASSERT (ntBIT (15) == 0);
+
+ imm8 = ThumbExpandImm (imm8);
+ state->Reg[Rd] = state->Reg[Rn] & ~ imm8;
+
+ if (S && ! in_IT_block ())
+ ARMul_NegZero (state, state->Reg[Rd]);
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xA2:
+ case 0x82: // MOV{S}<c>.W <Rd>,#<const>
+ {
+ ARMword val = (tBIT(10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ ARMword Rd = ntBITS (8, 11);
+
+ val = ThumbExpandImm (val);
+ state->Reg[Rd] = val;
+
+ if (tBIT (4) && ! in_IT_block ())
+ ARMul_NegZero (state, val);
+ /* Indicate that the instruction has been processed. */
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xA3:
+ case 0x83: // MVN{S}<c> <Rd>,#<const>
+ {
+ ARMword val = (tBIT(10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ ARMword Rd = ntBITS (8, 11);
+
+ val = ThumbExpandImm (val);
+ val = ~ val;
+ state->Reg[Rd] = val;
+
+ if (tBIT (4) && ! in_IT_block ())
+ ARMul_NegZero (state, val);
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xA4: // EOR
+ case 0x84: // TEQ
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword S = tBIT (4);
+ ARMword imm12 = ((tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7));
+ ARMword result;
+
+ imm12 = ThumbExpandImm (imm12);
+
+ result = state->Reg[Rn] ^ imm12;
+
+ if (Rd == 15 && S)
+ // TEQ<c> <Rn>,#<const>
+ ;
+ else
+ {
+ // EOR{S}<c> <Rd>,<Rn>,#<const>
+ state->Reg[Rd] = result;
+
+ if (in_IT_block ())
+ S = 0;
+ }
+
+ if (S)
+ ARMul_NegZero (state, result);
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xA8: // CMN
+ case 0x88: // ADD
+ {
+ ARMword Rd = ntBITS (8, 11);
+ int S = tBIT (4);
+ ARMword Rn = tBITS (0, 3);
+ ARMword lhs = state->Reg[Rn];
+ ARMword imm12 = (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ ARMword rhs = ThumbExpandImm (imm12);
+ ARMword res = lhs + rhs;
+
+ if (Rd == 15 && S)
+ {
+ // CMN<c> <Rn>,#<const>
+ res = lhs - rhs;
+ }
+ else
+ {
+ // ADD{S}<c>.W <Rd>,<Rn>,#<const>
+ res = lhs + rhs;
+
+ if (in_IT_block ())
+ S = 0;
+
+ state->Reg[Rd] = res;
+ }
+
+ if (S)
+ {
+ ARMul_NegZero (state, res);
+
+ if ((lhs | rhs) >> 30)
+ {
+ /* Possible C,V,N to set. */
+ ARMul_AddCarry (state, lhs, rhs, res);
+ ARMul_AddOverflow (state, lhs, rhs, res);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ }
+
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xAA:
+ case 0x8A: // ADC{S}<c> <Rd>,<Rn>,#<const>
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ int S = tBIT (4);
+ ARMword imm12 = (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ ARMword lhs = state->Reg[Rn];
+ ARMword rhs = ThumbExpandImm (imm12);
+ ARMword res;
+
+ tASSERT (ntBIT (15) == 0);
+
+ if (CFLAG)
+ rhs += 1;
+
+ res = lhs + rhs;
+ state->Reg[Rd] = res;
+
+ if (in_IT_block ())
+ S = 0;
+
+ if (S)
+ {
+ ARMul_NegZero (state, res);
+
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_AddCarry (state, lhs, rhs, res);
+ ARMul_AddOverflow (state, lhs, rhs, res);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ }
+
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xAB:
+ case 0x8B: // SBC{S}<c> <Rd>,<Rn>,#<const>
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ int S = tBIT (4);
+ ARMword imm12 = (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ ARMword lhs = state->Reg[Rn];
+ ARMword rhs = ThumbExpandImm (imm12);
+ ARMword res;
+
+ tASSERT (ntBIT (15) == 0);
+
+ if (! CFLAG)
+ rhs += 1;
+
+ res = lhs - rhs;
+ state->Reg[Rd] = res;
+
+ if (in_IT_block ())
+ S = 0;
+
+ if (S)
+ {
+ ARMul_NegZero (state, res);
+
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, res);
+ ARMul_SubOverflow (state, lhs, rhs, res);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ }
+
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xAD:
+ case 0x8D: // SUB
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ int S = tBIT (4);
+ ARMword imm12 = (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ ARMword lhs = state->Reg[Rn];
+ ARMword rhs = ThumbExpandImm (imm12);
+ ARMword res = lhs - rhs;
+
+ if (Rd == 15 && S)
+ {
+ // CMP<c>.W <Rn>,#<const>
+ tASSERT (S);
+ }
+ else
+ {
+ // SUB{S}<c>.W <Rd>,<Rn>,#<const>
+ if (in_IT_block ())
+ S = 0;
+
+ state->Reg[Rd] = res;
+ }
+
+ if (S)
+ {
+ ARMul_NegZero (state, res);
+
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, res);
+ ARMul_SubOverflow (state, lhs, rhs, res);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ }
+
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xAE:
+ case 0x8E: // RSB{S}<c>.W <Rd>,<Rn>,#<const>
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword imm12 = (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+ int S = tBIT (4);
+ ARMword lhs = imm12;
+ ARMword rhs = state->Reg[Rn];
+ ARMword res = lhs - rhs;
+
+ tASSERT (ntBIT (15) == 0);
+
+ state->Reg[Rd] = res;
+
+ if (S)
+ {
+ ARMul_NegZero (state, res);
+
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, res);
+ ARMul_SubOverflow (state, lhs, rhs, res);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ }
+
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xB0:
+ case 0x90: // ADDW<c> <Rd>,<Rn>,#<imm12>
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword imm12 = (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBIT (15) == 0);
+
+ state->Reg[Rd] = state->Reg[Rn] + imm12;
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xB2:
+ case 0x92: // MOVW<c> <Rd>,#<imm16>
+ {
+ ARMword Rd = ntBITS (8, 11);
+ ARMword imm = (tBITS (0, 3) << 12) | (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+
+ state->Reg[Rd] = imm;
+ /* Indicate that the instruction has been processed. */
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xb5:
+ case 0x95:// SUBW<c> <Rd>,<Rn>,#<imm12>
+ {
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rn = tBITS (0, 3);
+ ARMword imm12 = (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBIT (15) == 0);
+
+ /* Note the ARM ARM indicates special cases for Rn == 15 (ADR)
+ and Rn == 13 (SUB SP minus immediate), but these are implemented
+ in exactly the same way as the normal SUBW insn. */
+ state->Reg[Rd] = state->Reg[Rn] - imm12;
+
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xB6:
+ case 0x96: // MOVT<c> <Rd>,#<imm16>
+ {
+ ARMword Rd = ntBITS (8, 11);
+ ARMword imm = (tBITS (0, 3) << 12) | (tBIT (10) << 11) | (ntBITS (12, 14) << 8) | ntBITS (0, 7);
+
+ state->Reg[Rd] &= 0xFFFF;
+ state->Reg[Rd] |= (imm << 16);
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0x9A: // SBFXc> <Rd>,<Rn>,#<lsb>,#<width>
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBIT (15) == 0);
+ tASSERT (ntBIT (5) == 0);
+ * ainstr = 0xE7A00050;
+ * ainstr |= (ntBITS (0, 4) << 16); // widthm1
+ * ainstr |= (ntBITS (8, 11) << 12); // Rd
+ * ainstr |= (((ntBITS (12, 14) << 2) | ntBITS (6, 7)) << 7); // lsb
+ * ainstr |= tBITS (0, 3); // Rn
+ * pvalid = t_decoded;
+ break;
+
+ case 0x9B:
+ {
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rn = tBITS (0, 3);
+ ARMword msbit = ntBITS (0, 5);
+ ARMword lsbit = (ntBITS (12, 14) << 2) | ntBITS (6, 7);
+ ARMword mask = -1 << lsbit;
+
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBIT (15) == 0);
+ tASSERT (ntBIT (5) == 0);
+
+ mask &= ((1 << (msbit + 1)) - 1);
+
+ if (lsbit > msbit)
+ ; // UNPREDICTABLE
+ else if (Rn == 15)
+ {
+ // BFC<c> <Rd>,#<lsb>,#<width>
+ state->Reg[Rd] &= ~ mask;
+ }
+ else
+ {
+ // BFI<c> <Rd>,<Rn>,#<lsb>,#<width>
+ ARMword val = state->Reg[Rn] & (mask >> lsbit);
+
+ val <<= lsbit;
+ state->Reg[Rd] &= ~ mask;
+ state->Reg[Rd] |= val;
+ }
+
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0x9E: // UBFXc> <Rd>,<Rn>,#<lsb>,#<width>
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBIT (15) == 0);
+ tASSERT (ntBIT (5) == 0);
+ * ainstr = 0xE7E00050;
+ * ainstr |= (ntBITS (0, 4) << 16); // widthm1
+ * ainstr |= (ntBITS (8, 11) << 12); // Rd
+ * ainstr |= (((ntBITS (12, 14) << 2) | ntBITS (6, 7)) << 7); // lsb
+ * ainstr |= tBITS (0, 3); // Rn
+ * pvalid = t_decoded;
+ break;
+
+ case 0xC0: // STRB
+ case 0xC4: // LDRB
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rt = ntBITS (12, 15);
+
+ if (tBIT (4))
+ {
+ if (Rn == 15)
+ {
+ tASSERT (Rt != 15);
+
+ /* LDRB<c> <Rt>,<label> => 1111 1000 U001 1111 */
+ * ainstr = 0xE55F0000;
+ * ainstr |= (tBIT (7) << 23);
+ * ainstr |= ntBITS (0, 11);
+ }
+ else if (tBIT (7))
+ {
+ /* LDRB<c>.W <Rt>,[<Rn>{,#<imm12>}] => 1111 1000 1001 rrrr */
+ * ainstr = 0xE5D00000;
+ * ainstr |= ntBITS (0, 11);
+ }
+ else if (ntBIT (11) == 0)
+ {
+ /* LDRB<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}] => 1111 1000 0001 rrrr */
+ * ainstr = 0xE7D00000;
+ * ainstr |= (ntBITS (4, 5) << 7);
+ * ainstr |= ntBITS (0, 3);
+ }
+ else
+ {
+ int P = ntBIT (10);
+ int U = ntBIT (9);
+ int W = ntBIT (8);
+
+ tASSERT (! (Rt == 15 && P && !U && !W));
+ tASSERT (! (P && U && !W));
+
+ /* LDRB<c> <Rt>,[<Rn>,#-<imm8>] => 1111 1000 0001 rrrr
+ LDRB<c> <Rt>,[<Rn>],#+/-<imm8> => 1111 1000 0001 rrrr
+ LDRB<c> <Rt>,[<Rn>,#+/-<imm8>]! => 1111 1000 0001 rrrr */
+ * ainstr = 0xE4500000;
+ * ainstr |= (P << 24);
+ * ainstr |= (U << 23);
+ * ainstr |= (W << 21);
+ * ainstr |= ntBITS (0, 7);
+ }
+ }
+ else
+ {
+ if (tBIT (7) == 1)
+ {
+ // STRB<c>.W <Rt>,[<Rn>,#<imm12>]
+ ARMword imm12 = ntBITS (0, 11);
+
+ ARMul_StoreByte (state, state->Reg[Rn] + imm12, state->Reg [Rt]);
+ * pvalid = t_branch;
+ break;
+ }
+ else if (ntBIT (11))
+ {
+ // STRB<c> <Rt>,[<Rn>,#-<imm8>]
+ // STRB<c> <Rt>,[<Rn>],#+/-<imm8>
+ // STRB<c> <Rt>,[<Rn>,#+/-<imm8>]!
+ int P = ntBIT (10);
+ int U = ntBIT (9);
+ int W = ntBIT (8);
+ ARMword imm8 = ntBITS (0, 7);
+
+ tASSERT (! (P && U && !W));
+ tASSERT (! (Rn == 13 && P && !U && W && imm8 == 4));
+
+ * ainstr = 0xE4000000;
+ * ainstr |= (P << 24);
+ * ainstr |= (U << 23);
+ * ainstr |= (W << 21);
+ * ainstr |= imm8;
+ }
+ else
+ {
+ // STRB<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
+ tASSERT (ntBITS (6, 11) == 0);
+
+ * ainstr = 0xE7C00000;
+ * ainstr |= (ntBITS (4, 5) << 7);
+ * ainstr |= ntBITS (0, 3);
+ }
+ }
+
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rt << 12);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0xC2: // LDR, STR
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rt = ntBITS (12, 15);
+ ARMword imm8 = ntBITS (0, 7);
+ ARMword P = ntBIT (10);
+ ARMword U = ntBIT (9);
+ ARMword W = ntBIT (8);
+
+ tASSERT (Rn != 15);
+
+ if (tBIT (4))
+ {
+ if (Rn == 15)
+ {
+ // LDR<c>.W <Rt>,<label>
+ * ainstr = 0xE51F0000;
+ * ainstr |= ntBITS (0, 11);
+ }
+ else if (ntBIT (11))
+ {
+ tASSERT (! (P && U && ! W));
+ tASSERT (! (!P && U && W && Rn == 13 && imm8 == 4 && ntBIT (11) == 0));
+ tASSERT (! (P && !U && W && Rn == 13 && imm8 == 4 && ntBIT (11)));
+
+ // LDR<c> <Rt>,[<Rn>,#-<imm8>]
+ // LDR<c> <Rt>,[<Rn>],#+/-<imm8>
+ // LDR<c> <Rt>,[<Rn>,#+/-<imm8>]!
+ if (!P && W)
+ W = 0;
+ * ainstr = 0xE4100000;
+ * ainstr |= (P << 24);
+ * ainstr |= (U << 23);
+ * ainstr |= (W << 21);
+ * ainstr |= imm8;
+ }
+ else
+ {
+ // LDR<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
+
+ tASSERT (ntBITS (6, 11) == 0);
+
+ * ainstr = 0xE7900000;
+ * ainstr |= ntBITS (4, 5) << 7;
+ * ainstr |= ntBITS (0, 3);
+ }
+ }
+ else
+ {
+ if (ntBIT (11))
+ {
+ tASSERT (! (P && U && ! W));
+ if (Rn == 13 && P && !U && W && imm8 == 4)
+ {
+ // PUSH<c>.W <register>
+ tASSERT (ntBITS (0, 11) == 0xD04);
+ tASSERT (tBITS (0, 4) == 0x0D);
+
+ * ainstr = 0xE92D0000;
+ * ainstr |= (1 << Rt);
+
+ Rt = Rn = 0;
+ }
+ else
+ {
+ tASSERT (! (P && U && !W));
+ if (!P && W)
+ W = 0;
+ // STR<c> <Rt>,[<Rn>,#-<imm8>]
+ // STR<c> <Rt>,[<Rn>],#+/-<imm8>
+ // STR<c> <Rt>,[<Rn>,#+/-<imm8>]!
+ * ainstr = 0xE4000000;
+ * ainstr |= (P << 24);
+ * ainstr |= (U << 23);
+ * ainstr |= (W << 21);
+ * ainstr |= imm8;
+ }
+ }
+ else
+ {
+ // STR<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
+ tASSERT (ntBITS (6, 11) == 0);
+
+ * ainstr = 0xE7800000;
+ * ainstr |= ntBITS (4, 5) << 7;
+ * ainstr |= ntBITS (0, 3);
+ }
+ }
+
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rt << 12);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0xC1: // STRH
+ case 0xC5: // LDRH
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rt = ntBITS (12, 15);
+ ARMword address;
+
+ tASSERT (Rn != 15);
+
+ if (tBIT (4) == 1)
+ {
+ if (tBIT (7))
+ {
+ // LDRH<c>.W <Rt>,[<Rn>{,#<imm12>}]
+ ARMword imm12 = ntBITS (0, 11);
+ address = state->Reg[Rn] + imm12;
+ }
+ else if (ntBIT (11))
+ {
+ // LDRH<c> <Rt>,[<Rn>,#-<imm8>]
+ // LDRH<c> <Rt>,[<Rn>],#+/-<imm8>
+ // LDRH<c> <Rt>,[<Rn>,#+/-<imm8>]!
+ ARMword P = ntBIT (10);
+ ARMword U = ntBIT (9);
+ ARMword W = ntBIT (8);
+ ARMword imm8 = ntBITS (0, 7);
+
+ tASSERT (Rn != 15);
+ tASSERT (! (P && U && !W));
+
+ * ainstr = 0xE05000B0;
+ * ainstr |= (P << 24);
+ * ainstr |= (U << 23);
+ * ainstr |= (W << 21);
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rt << 12);
+ * ainstr |= ((imm8 & 0xF0) << 4);
+ * ainstr |= (imm8 & 0xF);
+ * pvalid = t_decoded;
+ break;
+ }
+ else
+ {
+ // LDRH<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
+ ARMword Rm = ntBITS (0, 3);
+ ARMword imm2 = ntBITS (4, 5);
+
+ tASSERT (ntBITS (6, 10) == 0);
+
+ address = state->Reg[Rn] + (state->Reg[Rm] << imm2);
+ }
+
+ state->Reg[Rt] = ARMul_LoadHalfWord (state, address);
+ }
+ else
+ {
+ if (tBIT (7))
+ {
+ // STRH<c>.W <Rt>,[<Rn>{,#<imm12>}]
+ ARMword imm12 = ntBITS (0, 11);
+
+ address = state->Reg[Rn] + imm12;
+ }
+ else if (ntBIT (11))
+ {
+ // STRH<c> <Rt>,[<Rn>,#-<imm8>]
+ // STRH<c> <Rt>,[<Rn>],#+/-<imm8>
+ // STRH<c> <Rt>,[<Rn>,#+/-<imm8>]!
+ ARMword P = ntBIT (10);
+ ARMword U = ntBIT (9);
+ ARMword W = ntBIT (8);
+ ARMword imm8 = ntBITS (0, 7);
+
+ tASSERT (! (P && U && !W));
+
+ * ainstr = 0xE04000B0;
+ * ainstr |= (P << 24);
+ * ainstr |= (U << 23);
+ * ainstr |= (W << 21);
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rt << 12);
+ * ainstr |= ((imm8 & 0xF0) << 4);
+ * ainstr |= (imm8 & 0xF);
+ * pvalid = t_decoded;
+ break;
+ }
+ else
+ {
+ // STRH<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
+ ARMword Rm = ntBITS (0, 3);
+ ARMword imm2 = ntBITS (4, 5);
+
+ tASSERT (ntBITS (6, 10) == 0);
+
+ address = state->Reg[Rn] + (state->Reg[Rm] << imm2);
+ }
+
+ ARMul_StoreHalfWord (state, address, state->Reg [Rt]);
+ }
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0xC6: // LDR.W/STR.W
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rt = ntBITS (12, 15);
+ ARMword imm12 = ntBITS (0, 11);
+ ARMword address = state->Reg[Rn];
+
+ if (Rn == 15)
+ {
+ // LDR<c>.W <Rt>,<label>
+ tASSERT (tBIT (4) == 1);
+ // tASSERT (tBIT (7) == 1)
+ }
+
+ address += imm12;
+ if (tBIT (4) == 1)
+ state->Reg[Rt] = ARMul_LoadWordN (state, address);
+ else
+ ARMul_StoreWordN (state, address, state->Reg [Rt]);
+
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xC8:
+ case 0xCC: // LDRSB
+ {
+ ARMword Rt = ntBITS (12, 15);
+ ARMword Rn = tBITS (0, 3);
+ ARMword U = tBIT (7);
+ ARMword address = state->Reg[Rn];
+
+ tASSERT (tBIT (4) == 1);
+ tASSERT (Rt != 15); // PLI
+
+ if (Rn == 15)
+ {
+ // LDRSB<c> <Rt>,<label>
+ ARMword imm12 = ntBITS (0, 11);
+ address += (U ? imm12 : - imm12);
+ }
+ else if (U)
+ {
+ // LDRSB<c> <Rt>,[<Rn>,#<imm12>]
+ ARMword imm12 = ntBITS (0, 11);
+ address += imm12;
+ }
+ else if (ntBIT (11))
+ {
+ // LDRSB<c> <Rt>,[<Rn>,#-<imm8>]
+ // LDRSB<c> <Rt>,[<Rn>],#+/-<imm8>
+ // LDRSB<c> <Rt>,[<Rn>,#+/-<imm8>]!
+ * ainstr = 0xE05000D0;
+ * ainstr |= ntBIT (10) << 24; // P
+ * ainstr |= ntBIT (9) << 23; // U
+ * ainstr |= ntBIT (8) << 21; // W
+ * ainstr |= Rn << 16;
+ * ainstr |= Rt << 12;
+ * ainstr |= ntBITS (4, 7) << 8;
+ * ainstr |= ntBITS (0, 3);
+ * pvalid = t_decoded;
+ break;
+ }
+ else
+ {
+ // LDRSB<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
+ ARMword Rm = ntBITS (0, 3);
+ ARMword imm2 = ntBITS (4,5);
+
+ tASSERT (ntBITS (6, 11) == 0);
+
+ address += (state->Reg[Rm] << imm2);
+ }
+
+ state->Reg[Rt] = ARMul_LoadByte (state, address);
+ if (state->Reg[Rt] & 0x80)
+ state->Reg[Rt] |= -1 << 8;
+
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xC9:
+ case 0xCD:// LDRSH
+ {
+ ARMword Rt = ntBITS (12, 15);
+ ARMword Rn = tBITS (0, 3);
+ ARMword U = tBIT (7);
+ ARMword address = state->Reg[Rn];
+
+ tASSERT (tBIT (4) == 1);
+
+ if (Rn == 15 || U == 1)
+ {
+ // Rn==15 => LDRSH<c> <Rt>,<label>
+ // Rn!=15 => LDRSH<c> <Rt>,[<Rn>,#<imm12>]
+ ARMword imm12 = ntBITS (0, 11);
+
+ address += (U ? imm12 : - imm12);
+ }
+ else if (ntBIT (11))
+ {
+ // LDRSH<c> <Rt>,[<Rn>,#-<imm8>]
+ // LDRSH<c> <Rt>,[<Rn>],#+/-<imm8>
+ // LDRSH<c> <Rt>,[<Rn>,#+/-<imm8>]!
+ * ainstr = 0xE05000F0;
+ * ainstr |= ntBIT (10) << 24; // P
+ * ainstr |= ntBIT (9) << 23; // U
+ * ainstr |= ntBIT (8) << 21; // W
+ * ainstr |= Rn << 16;
+ * ainstr |= Rt << 12;
+ * ainstr |= ntBITS (4, 7) << 8;
+ * ainstr |= ntBITS (0, 3);
+ * pvalid = t_decoded;
+ break;
+ }
+ else /* U == 0 */
+ {
+ // LDRSH<c>.W <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]
+ ARMword Rm = ntBITS (0, 3);
+ ARMword imm2 = ntBITS (4,5);
+
+ tASSERT (ntBITS (6, 11) == 0);
+
+ address += (state->Reg[Rm] << imm2);
+ }
+
+ state->Reg[Rt] = ARMul_LoadHalfWord (state, address);
+ if (state->Reg[Rt] & 0x8000)
+ state->Reg[Rt] |= -1 << 16;
+
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0x0D0:
+ {
+ ARMword Rm = ntBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+
+ tASSERT (ntBITS (12, 15) == 15);
+
+ if (ntBIT (7) == 1)
+ {
+ // SXTH<c>.W <Rd>,<Rm>{,<rotation>}
+ ARMword ror = ntBITS (4, 5) << 3;
+ ARMword val;
+
+ val = state->Reg[Rm];
+ val = (val >> ror) | (val << (32 - ror));
+ if (val & 0x8000)
+ val |= -1 << 16;
+ state->Reg[Rd] = val;
+ }
+ else
+ {
+ // LSL{S}<c>.W <Rd>,<Rn>,<Rm>
+ ARMword Rn = tBITS (0, 3);
+
+ tASSERT (ntBITS (4, 6) == 0);
+
+ state->Reg[Rd] = state->Reg[Rn] << (state->Reg[Rm] & 0xFF);
+ if (tBIT (4))
+ ARMul_NegZero (state, state->Reg[Rd]);
+ }
+ * pvalid = t_branch;
+ break;
+ }
+
+ case 0x0D1: // LSR{S}<c>.W <Rd>,<Rn>,<Rm>
+ {
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rm = ntBITS (0, 3);
+
+ tASSERT (ntBITS (12, 15) == 15);
+ tASSERT (ntBITS (4, 7) == 0);
+
+ state->Reg[Rd] = state->Reg[Rn] >> (state->Reg[Rm] & 0xFF);
+ if (tBIT (4))
+ ARMul_NegZero (state, state->Reg[Rd]);
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xD2:
+ tASSERT (ntBITS (12, 15) == 15);
+ if (ntBIT (7))
+ {
+ tASSERT (ntBIT (6) == 0);
+ // UXTB<c>.W <Rd>,<Rm>{,<rotation>}
+ * ainstr = 0xE6EF0070;
+ * ainstr |= (ntBITS (4, 5) << 10); // rotate
+ * ainstr |= ntBITS (0, 3); // Rm
+ }
+ else
+ {
+ // ASR{S}<c>.W <Rd>,<Rn>,<Rm>
+ tASSERT (ntBITS (4, 7) == 0);
+ * ainstr = 0xE1A00050;
+ if (! in_IT_block ())
+ * ainstr |= (tBIT (4) << 20);
+ * ainstr |= (ntBITS (0, 3) << 8); // Rm
+ * ainstr |= tBITS (0, 3); // Rn
+ }
+
+ * ainstr |= (ntBITS (8, 11) << 12); // Rd
+ * pvalid = t_decoded;
+ break;
+
+ case 0xD3: // ROR{S}<c>.W <Rd>,<Rn>,<Rm>
+ tASSERT (ntBITS (12, 15) == 15);
+ tASSERT (ntBITS (4, 7) == 0);
+ * ainstr = 0xE1A00070;
+ if (! in_IT_block ())
+ * ainstr |= (tBIT (4) << 20);
+ * ainstr |= (ntBITS (8, 11) << 12); // Rd
+ * ainstr |= (ntBITS (0, 3) << 8); // Rm
+ * ainstr |= (tBITS (0, 3) << 0); // Rn
+ * pvalid = t_decoded;
+ break;
+
+ case 0xD4:
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+
+ tASSERT (ntBITS (12, 15) == 15);
+
+ if (ntBITS (4, 7) == 8)
+ {
+ // REV<c>.W <Rd>,<Rm>
+ ARMword val = state->Reg[Rm];
+
+ tASSERT (Rm == Rn);
+
+ state->Reg [Rd] =
+ (val >> 24)
+ | ((val >> 8) & 0xFF00)
+ | ((val << 8) & 0xFF0000)
+ | (val << 24);
+ * pvalid = t_resolved;
+ }
+ else
+ {
+ tASSERT (ntBITS (4, 7) == 4);
+
+ if (tBIT (4) == 1)
+ // UADD8<c> <Rd>,<Rn>,<Rm>
+ * ainstr = 0xE6500F10;
+ else
+ // UADD16<c> <Rd>,<Rn>,<Rm>
+ * ainstr = 0xE6500F90;
+
+ * ainstr |= (Rn << 16);
+ * ainstr |= (Rd << 12);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ }
+ break;
+ }
+
+ case 0xD5:
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Rm = ntBITS (0, 3);
+
+ tASSERT (ntBITS (12, 15) == 15);
+ tASSERT (ntBITS (4, 7) == 8);
+
+ if (tBIT (4))
+ {
+ // CLZ<c> <Rd>,<Rm>
+ tASSERT (Rm == Rn);
+ * ainstr = 0xE16F0F10;
+ }
+ else
+ {
+ // SEL<c> <Rd>,<Rn>,<Rm>
+ * ainstr = 0xE6800FB0;
+ * ainstr |= (Rn << 16);
+ }
+
+ * ainstr |= (Rd << 12);
+ * ainstr |= (Rm << 0);
+ * pvalid = t_decoded;
+ break;
+ }
+
+ case 0xD8: // MUL
+ {
+ ARMword Rn = tBITS (0, 3);
+ ARMword Rm = ntBITS (0, 3);
+ ARMword Rd = ntBITS (8, 11);
+ ARMword Ra = ntBITS (12, 15);
+
+ if (tBIT (4))
+ {
+ // SMLA<x><y><c> <Rd>,<Rn>,<Rm>,<Ra>
+ ARMword nval = state->Reg[Rn];
+ ARMword mval = state->Reg[Rm];
+ ARMword res;
+
+ tASSERT (ntBITS (6, 7) == 0);
+ tASSERT (Ra != 15);
+
+ if (ntBIT (5))
+ nval >>= 16;
+ else
+ nval &= 0xFFFF;
+
+ if (ntBIT (4))
+ mval >>= 16;
+ else
+ mval &= 0xFFFF;
+
+ res = nval * mval;
+ res += state->Reg[Ra];
+ // FIXME: Test and clear/set the Q bit.
+ state->Reg[Rd] = res;
+ }
+ else
+ {
+ if (ntBITS (4, 7) == 1)
+ {
+ // MLS<c> <Rd>,<Rn>,<Rm>,<Ra>
+ state->Reg[Rd] = state->Reg[Ra] - (state->Reg[Rn] * state->Reg[Rm]);
+ }
+ else
+ {
+ tASSERT (ntBITS (4, 7) == 0);
+
+ if (Ra == 15)
+ // MUL<c> <Rd>,<Rn>,<Rm>
+ state->Reg[Rd] = state->Reg[Rn] * state->Reg[Rm];
+ else
+ // MLA<c> <Rd>,<Rn>,<Rm>,<Ra>
+ state->Reg[Rd] = state->Reg[Rn] * state->Reg[Rm] + state->Reg[Ra];
+ }
+ }
+ * pvalid = t_resolved;
+ break;
+ }
+
+ case 0xDC: // SMULL
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBITS (4, 7) == 0);
+ * ainstr = 0xE0C00090;
+ * ainstr |= (ntBITS (8, 11) << 16); // RdHi
+ * ainstr |= (ntBITS (12, 15) << 12); // RdLo
+ * ainstr |= (ntBITS (0, 3) << 8); // Rm
+ * ainstr |= tBITS (0, 3); // Rn
+ * pvalid = t_decoded;
+ break;
+
+ case 0xDD: // UMULL
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBITS (4, 7) == 0);
+ * ainstr = 0xE0800090;
+ * ainstr |= (ntBITS (8, 11) << 16); // RdHi
+ * ainstr |= (ntBITS (12, 15) << 12); // RdLo
+ * ainstr |= (ntBITS (0, 3) << 8); // Rm
+ * ainstr |= tBITS (0, 3); // Rn
+ * pvalid = t_decoded;
+ break;
+
+ case 0xDF: // UMLAL
+ tASSERT (tBIT (4) == 0);
+ tASSERT (ntBITS (4, 7) == 0);
+ * ainstr = 0xE0A00090;
+ * ainstr |= (ntBITS (8, 11) << 16); // RdHi
+ * ainstr |= (ntBITS (12, 15) << 12); // RdLo
+ * ainstr |= (ntBITS (0, 3) << 8); // Rm
+ * ainstr |= tBITS (0, 3); // Rn
+ * pvalid = t_decoded;
+ break;
+
+ default:
+ fprintf (stderr, "(op = %x) ", tBITS (5,12));
+ tASSERT (0);
+ return;
+ }
+
+ /* Tell the Thumb decoder to skip the next 16-bit insn - it was
+ part of this insn - unless this insn has changed the PC. */
+ skipping_32bit_thumb = pc + 2;
+}
+
/* 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,
+ ARMword next_instr,
+ ARMword pc,
+ ARMword * ainstr,
tdstate * pvalid)
{
if (! state->is_v6)
@@ -44,13 +1820,105 @@ handle_v6_thumb_insn (ARMul_State * state,
return;
}
+ if (tBITS (12, 15) == 0xB
+ && tBIT (10) == 0
+ && tBIT (8) == 1)
+ {
+ // Conditional branch forwards.
+ ARMword Rn = tBITS (0, 2);
+ ARMword imm5 = tBIT (9) << 5 | tBITS (3, 7);
+
+ if (tBIT (11))
+ {
+ if (state->Reg[Rn] != 0)
+ {
+ state->Reg[15] = (pc + 4 + imm5 * 2);
+ FLUSHPIPE;
+ }
+ }
+ else
+ {
+ if (state->Reg[Rn] == 0)
+ {
+ state->Reg[15] = (pc + 4 + imm5 * 2);
+ FLUSHPIPE;
+ }
+ }
+ * pvalid = t_branch;
+ return;
+ }
+
switch (tinstr & 0xFFC0)
{
- case 0xb660: /* cpsie */
- case 0xb670: /* cpsid */
- case 0x4600: /* cpy */
+ case 0x4400:
+ case 0x4480:
+ case 0x4440:
+ case 0x44C0: // ADD
+ {
+ ARMword Rd = (tBIT (7) << 3) | tBITS (0, 2);
+ ARMword Rm = tBITS (3, 6);
+ state->Reg[Rd] += state->Reg[Rm];
+ break;
+ }
+
+ case 0x4600: // MOV<c> <Rd>,<Rm>
+ {
+ // instr [15, 8] = 0100 0110
+ // instr [7] = Rd<high>
+ // instr [6,3] = Rm
+ // instr [2,0] = Rd<low>
+ ARMword Rd = (tBIT(7) << 3) | tBITS (0, 2);
+ // FIXME: Check for Rd == 15 and ITblock.
+ state->Reg[Rd] = state->Reg[tBITS (3, 6)];
+ break;
+ }
+
+ case 0xBF00:
+ case 0xBF40:
+ case 0xBF80:
+ case 0xBFC0:
+ handle_IT_block (state, tinstr, pvalid);
+ return;
+
+ case 0xE840:
+ case 0xE880: // LDMIA
+ case 0xE8C0:
+ case 0xE900: // STM
+ case 0xE940:
+ case 0xE980:
+ case 0xE9C0: // LDRD
+ case 0xEA00: // BIC
+ case 0xEA40: // ORR
+ case 0xEA80: // EOR
+ case 0xEAC0:
+ case 0xEB00: // ADD
+ case 0xEB40: // SBC
+ case 0xEB80: // SUB
+ case 0xEBC0: // RSB
+ case 0xFA80: // UADD, SEL
+ handle_T2_insn (state, tinstr, next_instr, pc, ainstr, pvalid);
+ return;
+
case 0xba00: /* rev */
+ {
+ ARMword val = state->Reg[tBITS (3, 5)];
+ state->Reg [tBITS (0, 2)] =
+ (val >> 24)
+ | ((val >> 8) & 0xFF00)
+ | ((val << 8) & 0xFF0000)
+ | (val << 24);
+ break;
+ }
+
case 0xba40: /* rev16 */
+ {
+ ARMword val = state->Reg[tBITS (3, 5)];
+ state->Reg [tBITS (0, 2)] = (val >> 16) | (val << 16);
+ break;
+ }
+
+ case 0xb660: /* cpsie */
+ case 0xb670: /* cpsid */
case 0xbac0: /* revsh */
case 0xb650: /* setend */
default:
@@ -113,6 +1981,14 @@ ARMul_ThumbDecode (ARMul_State * state,
{
tdstate valid = t_decoded; /* default assumes a valid instruction */
ARMword next_instr;
+ ARMword old_tinstr = tinstr;
+
+ if (skipping_32bit_thumb == pc)
+ {
+ skipping_32bit_thumb = 0;
+ return t_branch;
+ }
+ skipping_32bit_thumb = 0;
if (state->bigendSig)
{
@@ -125,6 +2001,24 @@ ARMul_ThumbDecode (ARMul_State * state,
tinstr &= 0xFFFF;
}
+ if (! IT_block_allow (state))
+ {
+ if ( tBITS (11, 15) == 0x1F
+ || tBITS (11, 15) == 0x1E
+ || tBITS (11, 15) == 0x1D)
+ {
+ if (trace)
+ fprintf (stderr, "pc: %x, SKIP instr: %04x|%04x\n",
+ pc & ~1, tinstr, next_instr);
+ skipping_32bit_thumb = pc + 2;
+ }
+ else if (trace)
+ fprintf (stderr, "pc: %x, SKIP instr: %04x\n", pc & ~1, tinstr);
+
+ return t_branch;
+ }
+
+ old_tinstr = tinstr;
if (trace)
fprintf (stderr, "pc: %x, Thumb instr: %x", pc & ~1, tinstr);
@@ -147,38 +2041,50 @@ ARMul_ThumbDecode (ARMul_State * state,
case 3: /* ADD/SUB */
/* Format 2 */
{
- ARMword subset[4] = {
- 0xE0900000, /* ADDS Rd,Rs,Rn */
- 0xE0500000, /* SUBS Rd,Rs,Rn */
- 0xE2900000, /* ADDS Rd,Rs,#imm3 */
- 0xE2500000 /* SUBS Rd,Rs,#imm3 */
- };
+ ARMword subset[4] =
+ {
+ 0xE0900000, /* ADDS Rd,Rs,Rn */
+ 0xE0500000, /* SUBS Rd,Rs,Rn */
+ 0xE2900000, /* ADDS Rd,Rs,#imm3 */
+ 0xE2500000 /* SUBS Rd,Rs,#imm3 */
+ };
/* It is quicker indexing into a table, than performing switch
or conditionals: */
*ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */
| ((tinstr & 0x01C0) >> 6) /* Rn or imm3 */
| ((tinstr & 0x0038) << (16 - 3)) /* Rs */
| ((tinstr & 0x0007) << (12 - 0)); /* Rd */
+
+ if (in_IT_block ())
+ *ainstr &= ~ (1 << 20);
}
break;
- case 4: /* MOV */
- case 5: /* CMP */
- case 6: /* ADD */
- case 7: /* SUB */
- /* Format 3 */
- {
- ARMword subset[4] = {
- 0xE3B00000, /* MOVS Rd,#imm8 */
- 0xE3500000, /* CMP Rd,#imm8 */
- 0xE2900000, /* ADDS Rd,Rd,#imm8 */
- 0xE2500000, /* SUBS Rd,Rd,#imm8 */
- };
- *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */
- | ((tinstr & 0x00FF) >> 0) /* imm8 */
- | ((tinstr & 0x0700) << (16 - 8)) /* Rn */
- | ((tinstr & 0x0700) << (12 - 8)); /* Rd */
- }
+ case 4:
+ * ainstr = 0xE3A00000; /* MOV Rd,#imm8 */
+ if (! in_IT_block ())
+ * ainstr |= (1 << 20);
+ * ainstr |= tBITS (8, 10) << 12;
+ * ainstr |= tBITS (0, 7);
+ break;
+
+ case 5:
+ * ainstr = 0xE3500000; /* CMP Rd,#imm8 */
+ * ainstr |= tBITS (8, 10) << 16;
+ * ainstr |= tBITS (0, 7);
break;
+
+ case 6:
+ case 7:
+ * ainstr = tBIT (11)
+ ? 0xE2400000 /* SUB Rd,Rd,#imm8 */
+ : 0xE2800000; /* ADD Rd,Rd,#imm8 */
+ if (! in_IT_block ())
+ * ainstr |= (1 << 20);
+ * ainstr |= tBITS (8, 10) << 12;
+ * ainstr |= tBITS (8, 10) << 16;
+ * ainstr |= tBITS (0, 7);
+ break;
+
case 8: /* Arithmetic and high register transfers */
/* TODO: Since the subsets for both Format 4 and Format 5
instructions are made up of different ARM encodings, we could
@@ -214,6 +2120,38 @@ ARMul_ThumbDecode (ARMul_State * state,
{ 0xE1F00000, t_norm} /* MVNS Rd,Rs */
};
*ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
+
+ if (in_IT_block ())
+ {
+ struct
+ {
+ ARMword opcode;
+ enum
+ { t_norm, t_shift, t_neg, t_mul }
+ otype;
+ }
+ subset[16] =
+ {
+ { 0xE0000000, t_norm}, /* AND Rd,Rd,Rs */
+ { 0xE0200000, t_norm}, /* EOR Rd,Rd,Rs */
+ { 0xE1A00010, t_shift}, /* MOV Rd,Rd,LSL Rs */
+ { 0xE1A00030, t_shift}, /* MOV Rd,Rd,LSR Rs */
+ { 0xE1A00050, t_shift}, /* MOV Rd,Rd,ASR Rs */
+ { 0xE0A00000, t_norm}, /* ADC Rd,Rd,Rs */
+ { 0xE0C00000, t_norm}, /* SBC Rd,Rd,Rs */
+ { 0xE1A00070, t_shift}, /* MOV Rd,Rd,ROR Rs */
+ { 0xE1100000, t_norm}, /* TST Rd,Rs */
+ { 0xE2600000, t_neg}, /* RSB Rd,Rs,#0 */
+ { 0xE1500000, t_norm}, /* CMP Rd,Rs */
+ { 0xE1700000, t_norm}, /* CMN Rd,Rs */
+ { 0xE1800000, t_norm}, /* ORR Rd,Rd,Rs */
+ { 0xE0000090, t_mul} , /* MUL Rd,Rd,Rs */
+ { 0xE1C00000, t_norm}, /* BIC Rd,Rd,Rs */
+ { 0xE1E00000, t_norm} /* MVN Rd,Rs */
+ };
+ *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
+ }
+
switch (subset[(tinstr & 0x03C0) >> 6].otype)
{
case t_norm:
@@ -268,7 +2206,6 @@ ARMul_ThumbDecode (ARMul_State * state,
case 0xA: /* MOV Hd,Rs */
case 0xB: /* MOV Hd,Hs */
*ainstr = 0xE1A00000 /* base */
- | (Rd << 16) /* Rn */
| (Rd << 12) /* Rd */
| (Rs << 0); /* Rm */
break;
@@ -287,10 +2224,11 @@ ARMul_ThumbDecode (ARMul_State * state,
break;
}
/* Drop through. */
+ default:
case 0x0: /* UNDEFINED */
case 0x4: /* UNDEFINED */
case 0x8: /* UNDEFINED */
- handle_v6_thumb_insn (state, tinstr, & valid);
+ handle_v6_thumb_insn (state, tinstr, next_instr, pc, ainstr, & valid);
break;
}
}
@@ -432,13 +2370,17 @@ ARMul_ThumbDecode (ARMul_State * state,
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);
+ if (state->is_v6)
+ // Map to the SVC instruction instead of the BKPT instruction.
+ * ainstr = 0xEF000000 | tBITS (0, 7);
+ else
+ * ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
break;
}
/* Drop through. */
default:
/* Everything else is an undefined instruction. */
- handle_v6_thumb_insn (state, tinstr, & valid);
+ handle_v6_thumb_insn (state, tinstr, next_instr, pc, ainstr, & valid);
break;
}
break;
@@ -530,7 +2472,7 @@ ARMul_ThumbDecode (ARMul_State * state,
}
else
/* UNDEFINED : cc=1110(AL) uses different format. */
- handle_v6_thumb_insn (state, tinstr, & valid);
+ handle_v6_thumb_insn (state, tinstr, next_instr, pc, ainstr, & valid);
break;
case 28: /* B */
/* Format 18 */
@@ -541,15 +2483,21 @@ ARMul_ThumbDecode (ARMul_State * state,
valid = t_branch;
break;
case 29: /* UNDEFINED */
+ if (state->is_v6)
+ {
+ handle_v6_thumb_insn (state, tinstr, next_instr, pc, ainstr, & valid);
+ break;
+ }
+
if (state->is_v5)
{
if (tinstr & 1)
{
- handle_v6_thumb_insn (state, tinstr, & valid);
+ handle_v6_thumb_insn (state, tinstr, next_instr, pc, ainstr, & 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
@@ -571,10 +2519,16 @@ ARMul_ThumbDecode (ARMul_State * state,
}
}
- handle_v6_thumb_insn (state, tinstr, & valid);
+ handle_v6_thumb_insn (state, tinstr, next_instr, pc, ainstr, & valid);
break;
case 30: /* BL instruction 1 */
+ if (state->is_v6)
+ {
+ handle_T2_insn (state, tinstr, next_instr, pc, ainstr, & valid);
+ break;
+ }
+
/* Format 19 */
/* There is no single ARM instruction equivalent for this Thumb
instruction. To keep the simulation simple (from the user
@@ -610,6 +2564,12 @@ ARMul_ThumbDecode (ARMul_State * state,
/* 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 */
+ if (state->is_v6)
+ {
+ handle_T2_insn (state, old_tinstr, next_instr, pc, ainstr, & valid);
+ break;
+ }
+
/* Format 19 */
/* There is no single ARM instruction equivalent for this
instruction. Also, it should only ever be matched with the