+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+/* We can provide simple Thumb simulation by decoding the Thumb
+instruction into its corresponding ARM instruction, and using the
+existing ARM simulator. */
+
+#ifndef MODET /* required for the Thumb instruction support */
+#if 1
+#error "MODET needs to be defined for the Thumb world to work"
+#else
+#define MODET (1)
+#endif
+#endif
+
+#include "armdefs.h"
+#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);