return ERROR_OK;
}
+static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp)
+{
+ unsigned rm = (opcode >> 0) & 0xf;
+ unsigned rd = (opcode >> 12) & 0xf;
+ unsigned rn = (opcode >> 16) & 0xf;
+ char *type, *rot;
+
+ /* GCC 'uninitialized warning removal' */
+ type = rot = NULL;
+
+ switch ((opcode >> 24) & 0x3) {
+ case 0:
+ type = "B16";
+ break;
+ case 1:
+ sprintf(cp, "UNDEFINED");
+ return ARM_UNDEFINED_INSTRUCTION;
+ case 2:
+ type = "B";
+ break;
+ case 3:
+ type = "H";
+ break;
+ }
+
+ switch ((opcode >> 10) & 0x3) {
+ case 0:
+ rot = "";
+ break;
+ case 1:
+ rot = ", ROR #8";
+ break;
+ case 2:
+ rot = ", ROR #16";
+ break;
+ case 3:
+ rot = ", ROR #24";
+ break;
+ }
+
+ if (rn == 0xf) {
+ sprintf(cp, "%cXT%s%s\tr%d, r%d%s",
+ (opcode & (1 << 22)) ? 'U' : 'S',
+ type, COND(opcode),
+ rd, rm, rot);
+ return ARM_MOV;
+ } else {
+ sprintf(cp, "%cXTA%s%s\tr%d, r%d, r%d%s",
+ (opcode & (1 << 22)) ? 'U' : 'S',
+ type, COND(opcode),
+ rd, rn, rm, rot);
+ return ARM_ADD;
+ }
+}
+
+static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp)
+{
+ char *prefix;
+ char *op;
+ int type;
+
+ switch ((opcode >> 20) & 0x7) {
+ case 1:
+ prefix = "S";
+ break;
+ case 2:
+ prefix = "Q";
+ break;
+ case 3:
+ prefix = "SH";
+ break;
+ case 5:
+ prefix = "U";
+ break;
+ case 6:
+ prefix = "UQ";
+ break;
+ case 7:
+ prefix = "UH";
+ break;
+ default:
+ goto undef;
+ }
+
+ switch ((opcode >> 5) & 0x7) {
+ case 0:
+ op = "ADD16";
+ type = ARM_ADD;
+ break;
+ case 1:
+ op = "ADDSUBX";
+ type = ARM_ADD;
+ break;
+ case 2:
+ op = "SUBADDX";
+ type = ARM_SUB;
+ break;
+ case 3:
+ op = "SUB16";
+ type = ARM_SUB;
+ break;
+ case 4:
+ op = "ADD8";
+ type = ARM_ADD;
+ break;
+ case 7:
+ op = "SUB8";
+ type = ARM_SUB;
+ break;
+ default:
+ goto undef;
+ }
+
+ sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode),
+ (int) (opcode >> 12) & 0xf,
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf);
+ return type;
+
+undef:
+ /* these opcodes might be used someday */
+ sprintf(cp, "UNDEFINED");
+ return ARM_UNDEFINED_INSTRUCTION;
+}
+
+/* ARMv6 and later support "media" instructions (includes SIMD) */
+static int evaluate_media(uint32_t opcode, uint32_t address,
+ arm_instruction_t *instruction)
+{
+ char *cp = instruction->text;
+ char *mnemonic = NULL;
+
+ sprintf(cp,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t",
+ address, opcode);
+ cp = strchr(cp, 0);
+
+ /* parallel add/subtract */
+ if ((opcode & 0x01800000) == 0x00000000) {
+ instruction->type = evaluate_p_add_sub(opcode, address, cp);
+ return ERROR_OK;
+ }
+
+ /* halfword pack */
+ if ((opcode & 0x01f00020) == 0x00800000) {
+ char *type, *shift;
+ unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
+
+ if (opcode & (1 << 6)) {
+ type = "TB";
+ shift = "ASR";
+ if (imm == 0)
+ imm = 32;
+ } else {
+ type = "BT";
+ shift = "LSL";
+ }
+ sprintf(cp, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
+ type, COND(opcode),
+ (int) (opcode >> 12) & 0xf,
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ shift, imm);
+ return ERROR_OK;
+ }
+
+ /* word saturate */
+ if ((opcode & 0x01a00020) == 0x00a00000) {
+ char *shift;
+ unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
+
+ if (opcode & (1 << 6)) {
+ shift = "ASR";
+ if (imm == 0)
+ imm = 32;
+ } else {
+ shift = "LSL";
+ }
+
+ sprintf(cp, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
+ (opcode & (1 << 22)) ? 'U' : 'S',
+ COND(opcode),
+ (int) (opcode >> 12) & 0xf,
+ (int) (opcode >> 16) & 0x1f,
+ (int) (opcode >> 0) & 0xf,
+ shift, imm);
+ return ERROR_OK;
+ }
+
+ /* sign extension */
+ if ((opcode & 0x018000f0) == 0x00800070) {
+ instruction->type = evaluate_extend(opcode, address, cp);
+ return ERROR_OK;
+ }
+
+ /* multiplies */
+ if ((opcode & 0x01f00080) == 0x01000000) {
+ unsigned rn = (opcode >> 12) & 0xf;
+
+ if (rn != 0xf)
+ sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
+ (opcode & (1 << 6)) ? 'S' : 'A',
+ (opcode & (1 << 5)) ? "X" : "",
+ COND(opcode),
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ (int) (opcode >> 8) & 0xf,
+ rn);
+ else
+ sprintf(cp, "SMU%cD%s%s\tr%d, r%d, r%d",
+ (opcode & (1 << 6)) ? 'S' : 'A',
+ (opcode & (1 << 5)) ? "X" : "",
+ COND(opcode),
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ (int) (opcode >> 8) & 0xf);
+ return ERROR_OK;
+ }
+ if ((opcode & 0x01f00000) == 0x01400000) {
+ sprintf(cp, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
+ (opcode & (1 << 6)) ? 'S' : 'A',
+ (opcode & (1 << 5)) ? "X" : "",
+ COND(opcode),
+ (int) (opcode >> 12) & 0xf,
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ (int) (opcode >> 8) & 0xf);
+ return ERROR_OK;
+ }
+ if ((opcode & 0x01f00000) == 0x01500000) {
+ unsigned rn = (opcode >> 12) & 0xf;
+
+ switch (opcode & 0xc0) {
+ case 3:
+ if (rn == 0xf)
+ goto undef;
+ /* FALL THROUGH */
+ case 0:
+ break;
+ default:
+ goto undef;
+ }
+
+ if (rn != 0xf)
+ sprintf(cp, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
+ (opcode & (1 << 6)) ? 'S' : 'A',
+ (opcode & (1 << 5)) ? "R" : "",
+ COND(opcode),
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ (int) (opcode >> 8) & 0xf,
+ rn);
+ else
+ sprintf(cp, "SMMUL%s%s\tr%d, r%d, r%d",
+ (opcode & (1 << 5)) ? "R" : "",
+ COND(opcode),
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ (int) (opcode >> 8) & 0xf);
+ return ERROR_OK;
+ }
+
+
+ /* simple matches against the remaining decode bits */
+ switch (opcode & 0x01f000f0) {
+ case 0x00a00030:
+ case 0x00e00030:
+ /* parallel halfword saturate */
+ sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d",
+ (opcode & (1 << 22)) ? 'U' : 'S',
+ COND(opcode),
+ (int) (opcode >> 12) & 0xf,
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf);
+ return ERROR_OK;
+ case 0x00b00030:
+ mnemonic = "REV";
+ break;
+ case 0x00b000b0:
+ mnemonic = "REV16";
+ break;
+ case 0x00f000b0:
+ mnemonic = "REVSH";
+ break;
+ case 0x008000b0:
+ /* select bytes */
+ sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode),
+ (int) (opcode >> 12) & 0xf,
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf);
+ return ERROR_OK;
+ case 0x01800010:
+ /* unsigned sum of absolute differences */
+ if (((opcode >> 12) & 0xf) == 0xf)
+ sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode),
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ (int) (opcode >> 8) & 0xf);
+ else
+ sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode),
+ (int) (opcode >> 16) & 0xf,
+ (int) (opcode >> 0) & 0xf,
+ (int) (opcode >> 8) & 0xf,
+ (int) (opcode >> 12) & 0xf);
+ return ERROR_OK;
+ }
+ if (mnemonic) {
+ unsigned rm = (opcode >> 0) & 0xf;
+ unsigned rd = (opcode >> 12) & 0xf;
+
+ sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd);
+ return ERROR_OK;
+ }
+
+undef:
+ /* these opcodes might be used someday */
+ sprintf(cp, "UNDEFINED");
+ return ERROR_OK;
+}
+
/* Miscellaneous load/store instructions */
int evaluate_misc_load_store(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
{
instruction->info.b_bl_bx_blx.target_address = -1;
}
+ /* BXJ - "Jazelle" support (ARMv5-J) */
+ if ((opcode & 0x006000f0) == 0x00200020)
+ {
+ uint8_t Rm;
+ instruction->type = ARM_BX;
+ Rm = opcode & 0xf;
+
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBXJ%s r%i",
+ address, opcode, COND(opcode), Rm);
+
+ instruction->info.b_bl_bx_blx.reg_operand = Rm;
+ instruction->info.b_bl_bx_blx.target_address = -1;
+ }
+
/* CLZ */
if ((opcode & 0x006000f0) == 0x00600010)
{
/* catch opcodes with [27:25] = b011 */
if ((opcode & 0x0e000000) == 0x06000000)
{
- /* Undefined instruction */
- if ((opcode & 0x00000010) == 0x00000010)
+ /* Load/store register offset */
+ if ((opcode & 0x00000010) == 0x00000000)
+ return evaluate_load_store(opcode, address, instruction);
+
+ /* Architecturally Undefined instruction
+ * ... don't expect these to ever be used
+ */
+ if ((opcode & 0x07f000f0) == 0x07f000f0)
{
instruction->type = ARM_UNDEFINED_INSTRUCTION;
- snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode);
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEF",
+ address, opcode);
return ERROR_OK;
}
- /* Load/store register offset */
- return evaluate_load_store(opcode, address, instruction);
-
+ /* "media" instructions */
+ return evaluate_media(opcode, address, instruction);
}
/* catch opcodes with [27:25] = b100 */
}
else
{
+ /* REVISIT: if reg_imm == 0, display as "MOVS" */
instruction->type = ARM_ADD;
mnemonic = "ADDS";
}
break;
case 0x9:
instruction->type = ARM_RSB;
- mnemonic = "NEGS";
+ mnemonic = "RSBS";
instruction->info.data_proc.variant = 0 /*immediate*/;
instruction->info.data_proc.shifter_operand.immediate.immediate = 0;
instruction->info.data_proc.Rn = Rm;
if ((opcode & 0xf000) == 0xc000)
{ /* generic load/store multiple */
+ char *wback = "!";
+
if (L)
{
instruction->type = ARM_LDM;
mnemonic = "LDM";
+ if (opcode & (1 << Rn))
+ wback = "";
}
else
{
instruction->type = ARM_STM;
mnemonic = "STM";
}
- snprintf(ptr_name,7,"r%i!, ",Rn);
+ snprintf(ptr_name, sizeof ptr_name, "r%i%s, ", Rn, wback);
}
else
{ /* push/pop */
mnemonic = "TST";
one = true;
suffix = "";
- suffix2 = ".W";
rd = rn;
} else {
instruction->type = ARM_AND;
case 10:
instruction->type = ARM_ADC;
mnemonic = "ADC";
+ suffix2 = ".W";
break;
case 11:
instruction->type = ARM_SBC;
bool add = false;
bool is_signed = false;
- immed = (opcode & 0x0ff) | ((opcode & 0x7000) >> 12);
- if (opcode & (1 << 27))
+ immed = (opcode & 0x0ff) | ((opcode & 0x7000) >> 4);
+ if (opcode & (1 << 26))
immed |= (1 << 11);
switch ((opcode >> 20) & 0x1f) {
add = true;
goto do_adr;
}
- mnemonic = "ADD.W";
+ mnemonic = "ADDW";
break;
case 4:
- mnemonic = "MOV.W";
- break;
+ immed |= (opcode >> 4) & 0xf000;
+ sprintf(cp, "MOVW\tr%d, #%d\t; %#3.3x", rd, immed, immed);
+ return ERROR_OK;
case 0x0a:
if (rn == 0xf)
goto do_adr;
- mnemonic = "SUB.W";
+ mnemonic = "SUBW";
break;
case 0x0c:
/* move constant to top 16 bits of register */
immed |= (opcode >> 10) & 0x1c;
sprintf(cp, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
is_signed ? "S" : "U",
- rd, (int) (opcode & 0x1f) + 1, rn,
+ rd, (int) (opcode & 0x1f) + is_signed, rn,
(opcode & (1 << 21)) ? "ASR" : "LSL",
immed ? immed : 32);
return ERROR_OK;
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;
switch (op) {
case 2:
- sprintf(cp, "STMB\tr%d%s, ", rn, t ? "!" : "");
+ sprintf(cp, "STM.W\tr%d%s, ", rn, t ? "!" : "");
break;
case 3:
if (rn == 13 && t)
- sprintf(cp, "POP\t");
+ sprintf(cp, "POP.W\t");
else
sprintf(cp, "LDM.W\tr%d%s, ", rn, t ? "!" : "");
break;
case 4:
if (rn == 13 && t)
- sprintf(cp, "PUSH\t");
+ sprintf(cp, "PUSH.W\t");
else
- sprintf(cp, "STM.W\tr%d%s, ", rn, t ? "!" : "");
+ sprintf(cp, "STMDB\tr%d%s, ", rn, t ? "!" : "");
break;
case 5:
- sprintf(cp, "LDMB\tr%d%s, ", rn, t ? "!" : "");
+ sprintf(cp, "LDMDB.W\tr%d%s, ", rn, t ? "!" : "");
break;
default:
return ERROR_INVALID_ARGUMENTS;
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";
if (rn == 0xf) {
immed = opcode & 0x0fff;
- if (opcode & (1 << 23))
+ if ((opcode & (1 << 23)) == 0)
immed = -immed;
sprintf(cp, "LDR\tr%d, %#8.8" PRIx32,
(int) (opcode >> 12) & 0xf,
if (((opcode >> 8) & 0xf) == 0xc || (opcode & 0x0900) == 0x0900) {
char *p1 = "]", *p2 = "";
- if (!(opcode & 0x0600))
+ if (!(opcode & 0x0500))
return ERROR_INVALID_ARGUMENTS;
immed = opcode & 0x00ff;
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;
int rn = (opcode >> 16) & 0xf;
int rt = (opcode >> 12) & 0xf;
int op2 = (opcode >> 6) & 0x3f;
- char *sign = (opcode & (1 < 24)) ? "S" : "";
+ char *sign = "";
unsigned immed;
if (rt == 0xf) {
return ERROR_OK;
}
+ if (opcode & (1 << 24))
+ sign = "S";
+
if ((opcode & (1 << 23)) == 0) {
if (rn == 0xf) {
ldrh_literal:
return ERROR_OK;
}
if ((op2 & 0x3c) == 0x38) {
- immed = (opcode >> 4) & 0x3;
+ immed = opcode & 0xff;
sprintf(cp, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
sign, rt, rn, immed, immed);
return ERROR_OK;
}
if ((op2 & 0x3c) == 0x30 || (op2 & 0x24) == 0x24) {
- char *p1 = "]", *p2 = "";
+ char *p1 = "", *p2 = "]";
immed = opcode & 0xff;
- if (opcode & 0x200)
+ if (!(opcode & 0x200))
immed = -immed;
/* two indexed modes will write back rn */
goto ldrh_literal;
immed = opcode & 0xfff;
- sprintf(cp, "LDR%sH.W\tr%d, [r%d, #%d]\t; %#6.6x",
- sign, rt, rn, immed, immed);
+ sprintf(cp, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
+ sign, *sign ? "" : ".W",
+ rt, rn, immed, immed);
return ERROR_OK;
}
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);
/* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
- else if ((opcode & 0x1e700000) == 0x18e00000)
+ else if ((opcode & 0x1e700000) == 0x18300000)
retval = t2ev_load_halfword(opcode, address, instruction, cp);
/* ARMv7-M: A5.3.9 Load byte, memory hints */
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");