}
else
{
+ /* REVISIT: if reg_imm == 0, display as "MOVS" */
instruction->type = ARM_ADD;
mnemonic = "ADDS";
}
sprintf(cp, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
size, rt, rn, (int) opcode & 0x0f,
(int) (opcode >> 4) & 0x03);
+ return ERROR_OK;
imm12:
immed = opcode & 0x0fff;
return ERROR_OK;
}
+/* load/store dual or exclusive, table branch */
+static int t2ev_ldrex_strex(uint32_t opcode, uint32_t address,
+ arm_instruction_t *instruction, char *cp)
+{
+ unsigned op1op2 = (opcode >> 20) & 0x3;
+ unsigned op3 = (opcode >> 4) & 0xf;
+ char *mnemonic;
+ unsigned rn = (opcode >> 16) & 0xf;
+ unsigned rt = (opcode >> 12) & 0xf;
+ unsigned rd = (opcode >> 8) & 0xf;
+ unsigned imm = opcode & 0xff;
+ char *p1 = "";
+ char *p2 = "]";
+
+ op1op2 |= (opcode >> 21) & 0xc;
+ switch (op1op2) {
+ case 0:
+ mnemonic = "STREX";
+ goto strex;
+ case 1:
+ mnemonic = "LDREX";
+ goto ldrex;
+ case 2:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ mnemonic = "STRD";
+ goto immediate;
+ case 3:
+ case 7:
+ case 9:
+ case 11:
+ case 13:
+ case 15:
+ mnemonic = "LDRD";
+ if (rn == 15)
+ goto literal;
+ else
+ goto immediate;
+ case 4:
+ switch (op3) {
+ case 4:
+ mnemonic = "STREXB";
+ break;
+ case 5:
+ mnemonic = "STREXH";
+ break;
+ default:
+ return ERROR_INVALID_ARGUMENTS;
+ }
+ rd = opcode & 0xf;
+ imm = 0;
+ goto strex;
+ case 5:
+ switch (op3) {
+ case 0:
+ sprintf(cp, "TBB\t[r%u, r%u]", rn, imm & 0xf);
+ return ERROR_OK;
+ case 1:
+ sprintf(cp, "TBH\t[r%u, r%u, LSL #1]", rn, imm & 0xf);
+ return ERROR_OK;
+ case 4:
+ mnemonic = "LDREXB";
+ break;
+ case 5:
+ mnemonic = "LDREXH";
+ break;
+ default:
+ return ERROR_INVALID_ARGUMENTS;
+ }
+ imm = 0;
+ goto ldrex;
+ }
+ return ERROR_INVALID_ARGUMENTS;
+
+strex:
+ imm <<= 2;
+ if (imm)
+ sprintf(cp, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
+ mnemonic, rd, rt, rn, imm, imm);
+ else
+ sprintf(cp, "%s\tr%u, r%u, [r%u]",
+ mnemonic, rd, rt, rn);
+ return ERROR_OK;
+
+ldrex:
+ imm <<= 2;
+ if (imm)
+ sprintf(cp, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
+ mnemonic, rt, rn, imm, imm);
+ else
+ sprintf(cp, "%s\tr%u, [r%u]",
+ mnemonic, rt, rn);
+ return ERROR_OK;
+
+immediate:
+ /* two indexed modes will write back rn */
+ if (opcode & (1 << 21)) {
+ if (opcode & (1 << 24)) /* pre-indexed */
+ p2 = "]!";
+ else { /* post-indexed */
+ p1 = "]";
+ p2 = "";
+ }
+ }
+
+ imm <<= 2;
+ sprintf(cp, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
+ mnemonic, rt, rd, rn, p1,
+ (opcode & (1 << 23)) ? "" : "-",
+ imm, p2, imm);
+ return ERROR_OK;
+
+literal:
+ address = thumb_alignpc4(address);
+ imm <<= 2;
+ if (opcode & (1 << 23))
+ address += imm;
+ else
+ address -= imm;
+ sprintf(cp, "%s\tr%u, r%u, %#8.8" PRIx32,
+ mnemonic, rt, rd, address);
+ return ERROR_OK;
+}
+
static int t2ev_data_shift(uint32_t opcode, uint32_t address,
arm_instruction_t *instruction, char *cp)
{
char *mnemonic;
char *suffix = "";
- immed |= (opcode >> 10) & 0x7;
- if (opcode & (1 << 21))
+ immed |= (opcode >> 10) & 0x1c;
+ if (opcode & (1 << 20))
suffix = "S";
switch (op) {
case 0:
if (rd == 0xf) {
- if (!(opcode & (1 << 21)))
+ if (!(opcode & (1 << 20)))
return ERROR_INVALID_ARGUMENTS;
instruction->type = ARM_TST;
mnemonic = "TST";
+ suffix = "";
goto two;
}
instruction->type = ARM_AND;
break;
default:
if (immed == 0) {
- sprintf(cp, "RRX%s.W\tr%d, r%d",
+ sprintf(cp, "RRX%s\tr%d, r%d",
suffix, rd,
(int) (opcode & 0xf));
return ERROR_OK;
break;
case 4:
if (rd == 0xf) {
- if (!(opcode & (1 << 21)))
+ if (!(opcode & (1 << 20)))
return ERROR_INVALID_ARGUMENTS;
instruction->type = ARM_TEQ;
mnemonic = "TEQ";
+ suffix = "";
goto two;
}
instruction->type = ARM_EOR;
break;
case 8:
if (rd == 0xf) {
- if (!(opcode & (1 << 21)))
+ if (!(opcode & (1 << 20)))
return ERROR_INVALID_ARGUMENTS;
instruction->type = ARM_CMN;
mnemonic = "CMN";
+ suffix = "";
goto two;
}
instruction->type = ARM_ADD;
return ERROR_INVALID_ARGUMENTS;
instruction->type = ARM_CMP;
mnemonic = "CMP";
+ suffix = "";
goto two;
}
instruction->type = ARM_SUB;
break;
case 1:
suffix = "LSR";
+ if (immed == 32)
+ immed = 0;
break;
case 2:
suffix = "ASR";
+ if (immed == 32)
+ immed = 0;
break;
case 3:
if (immed == 0) {
- strcpy(cp, "RRX");
+ strcpy(cp, ", RRX");
return ERROR_OK;
}
suffix = "ROR";
int rt = (opcode >> 12) & 0xf;
int op2 = (opcode >> 6) & 0x3f;
unsigned immed;
- char *p1 = "]", *p2 = "";
+ char *p1 = "", *p2 = "]";
char *mnemonic;
switch ((opcode >> 23) & 0x3) {
case 0:
if ((rn & rt) == 0xf) {
-preload_immediate_t2:
+pld_literal:
immed = opcode & 0xfff;
-preload_immediate_t1:
- p1 = (opcode & (1 << 21)) ? "W" : "";
- sprintf(cp, "PLD%s\t[r%d, #%d]\t; %#6.6x",
- p1, rn, immed, immed);
+ address = thumb_alignpc4(address);
+ if (opcode & (1 << 23))
+ address += immed;
+ else
+ address -= immed;
+ sprintf(cp, "PLD\tr%d, %#8.8" PRIx32,
+ rt, address);
return ERROR_OK;
}
if (rn == 0x0f && rt != 0x0f) {
if ((op2 & 0x3c) == 0x30) {
if (rt == 0x0f) {
immed = opcode & 0xff;
- goto preload_immediate_t1;
+ immed = -immed;
+preload_immediate:
+ p1 = (opcode & (1 << 21)) ? "W" : "";
+ sprintf(cp, "PLD%s\t[r%d, #%d]\t; %#6.6x",
+ p1, rn, immed, immed);
+ return ERROR_OK;
}
mnemonic = "LDRB";
ldrxb_immediate_t3:
immed = opcode & 0xff;
- if (opcode & 0x200)
+ if (!(opcode & 0x200))
immed = -immed;
/* two indexed modes will write back rn */
}
break;
case 1:
- if (rt == 0xf)
- goto preload_immediate_t2;
+ if ((rn & rt) == 0xf)
+ goto pld_literal;
+ if (rt == 0xf) {
+ immed = opcode & 0xfff;
+ goto preload_immediate;
+ }
if (rn == 0x0f)
goto ldrb_literal;
mnemonic = "LDRB.W";
goto ldrxb_immediate_t2;
case 2:
if ((rn & rt) == 0xf) {
-pli_immediate:
immed = opcode & 0xfff;
address = thumb_alignpc4(address);
if (opcode & (1 << 23))
break;
if ((op2 & 0x3c) == 0x38) {
immed = opcode & 0xff;
- sprintf(cp, "LDRSBT\tr%d, [r%d, #%d]\t; %2.2x",
+ sprintf(cp, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
rt, rn, immed, immed);
return ERROR_OK;
}
if (rt == 0xf) {
immed = opcode & 0xff;
immed = -immed; // pli
- sprintf(cp, "PLI\t[r%d, #-%d]\t; %2.2x",
- rn, immed, immed);
+ sprintf(cp, "PLI\t[r%d, #%d]\t; -%#2.2x",
+ rn, immed, -immed);
return ERROR_OK;
}
mnemonic = "LDRSB";
}
break;
case 3:
- if (rt == 0xf)
- goto pli_immediate;
+ if (rt == 0xf) {
+ immed = opcode & 0xfff;
+ sprintf(cp, "PLI\t[r%d, #%d]\t; %#3.3x",
+ rn, immed, immed);
+ return ERROR_OK;
+ }
if (rn == 0xf)
goto ldrsb_literal;
immed = opcode & 0xfff;
else if ((opcode & 0x1e400000) == 0x08000000)
retval = t2ev_ldm_stm(opcode, address, instruction, cp);
+ /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
+ else if ((opcode & 0x1e400000) == 0x08400000)
+ retval = t2ev_ldrex_strex(opcode, address, instruction, cp);
+
/* ARMv7-M: A5.3.7 Load word */
else if ((opcode & 0x1f700000) == 0x18500000)
retval = t2ev_load_word(opcode, address, instruction, cp);
else if ((opcode & 0x1f800000) == 0x1b800000)
retval = t2ev_mul64_div(opcode, address, instruction, cp);
- /* FIXME decode more 32-bit instructions */
-
if (retval == ERROR_OK)
return retval;
+ /*
+ * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
+ * instructions; not yet handled here.
+ */
+
if (retval == ERROR_INVALID_ARGUMENTS) {
instruction->type = ARM_UNDEFINED_INSTRUCTION;
strcpy(cp, "UNDEFINED OPCODE");