David Brownell <david-b@pacbell.net>:
[openocd.git] / src / target / arm_disassembler.c
index 69d5de87df678d6a1cb6f4bf7975256c750c7db7..1ea882d0437314986abcffdf8451ba54129e812c 100644 (file)
@@ -1678,6 +1678,12 @@ int evaluate_data_proc_thumb(uint16_t opcode, uint32_t address, arm_instruction_
        return ERROR_OK;
 }
 
+/* PC-relative data addressing is word-aligned even with Thumb */
+static inline uint32_t thumb_alignpc4(uint32_t addr)
+{
+       return (addr + 4) & ~3;
+}
+
 int evaluate_load_literal_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
 {
        uint32_t immediate;
@@ -1685,16 +1691,19 @@ int evaluate_load_literal_thumb(uint16_t opcode, uint32_t address, arm_instructi
 
        instruction->type = ARM_LDR;
        immediate = opcode & 0x000000ff;
-
-       snprintf(instruction->text, 128,
-               "0x%8.8" PRIx32 "  0x%4.4x    \tLDR\tr%i, [pc, #%#" PRIx32 "]",
-               address, opcode, Rd, immediate*4);
+       immediate *= 4;
 
        instruction->info.load_store.Rd = Rd;
        instruction->info.load_store.Rn = 15 /*PC*/;
        instruction->info.load_store.index_mode = 0; /*offset*/
        instruction->info.load_store.offset_mode = 0; /*immediate*/
-       instruction->info.load_store.offset.offset = immediate*4;
+       instruction->info.load_store.offset.offset = immediate;
+
+       snprintf(instruction->text, 128,
+               "0x%8.8" PRIx32 "  0x%4.4x    \t"
+               "LDR\tr%i, [pc, #%#" PRIx32 "]\t; %#8.8x",
+               address, opcode, Rd, immediate,
+               thumb_alignpc4(address) + immediate);
 
        return ERROR_OK;
 }
@@ -2532,6 +2541,238 @@ undef:
        return ERROR_INVALID_ARGUMENTS;
 }
 
+static int t2ev_data_mod_immed(uint32_t opcode, uint32_t address,
+               arm_instruction_t *instruction, char *cp)
+{
+       char *mnemonic = NULL;
+       int rn = (opcode >> 16) & 0xf;
+       int rd = (opcode >> 8) & 0xf;
+       unsigned immed = opcode & 0xff;
+       unsigned func;
+       bool one = false;
+       char *suffix = "";
+
+       /* ARMv7-M: A5.3.2 Modified immediate constants */
+       func = (opcode >> 11) & 0x0e;
+       if (immed & 0x80)
+               func |= 1;
+       if (opcode & (1 << 26))
+               func |= 0x10;
+
+       /* "Modified" immediates */
+       switch (func >> 1) {
+       case 0:
+               break;
+       case 2:
+               immed <<= 8;
+               /* FALLTHROUGH */
+       case 1:
+               immed += immed << 16;
+               break;
+       case 3:
+               immed += immed << 8;
+               immed += immed << 16;
+               break;
+       default:
+               immed |= 0x80;
+               immed = ror(immed, func);
+       }
+
+       if (opcode & (1 << 20))
+               suffix = "S";
+
+       switch ((opcode >> 21) & 0xf) {
+       case 0:
+               if (rd == 0xf) {
+                       instruction->type = ARM_TST;
+                       mnemonic = "TST";
+                       one = true;
+                       suffix = "";
+                       rd = rn;
+               } else {
+                       instruction->type = ARM_AND;
+                       mnemonic = "AND";
+               }
+               break;
+       case 1:
+               instruction->type = ARM_BIC;
+               mnemonic = "BIC";
+               break;
+       case 2:
+               if (rn == 0xf) {
+                       instruction->type = ARM_MOV;
+                       mnemonic = "MOV";
+                       one = true;
+               } else {
+                       instruction->type = ARM_ORR;
+                       mnemonic = "ORR";
+               }
+               break;
+       case 3:
+               if (rn == 0xf) {
+                       instruction->type = ARM_MVN;
+                       mnemonic = "MVN";
+                       one = true;
+               } else {
+                       // instruction->type = ARM_ORN;
+                       mnemonic = "ORN";
+               }
+               break;
+       case 4:
+               if (rd == 0xf) {
+                       instruction->type = ARM_TEQ;
+                       mnemonic = "TEQ";
+                       one = true;
+                       suffix = "";
+                       rd = rn;
+               } else {
+                       instruction->type = ARM_EOR;
+                       mnemonic = "EOR";
+               }
+               break;
+       case 8:
+               if (rd == 0xf) {
+                       instruction->type = ARM_CMN;
+                       mnemonic = "CMN";
+                       one = true;
+                       suffix = "";
+                       rd = rn;
+               } else {
+                       instruction->type = ARM_ADD;
+                       mnemonic = "ADD";
+               }
+               break;
+       case 10:
+               instruction->type = ARM_ADC;
+               mnemonic = "ADC";
+               break;
+       case 11:
+               instruction->type = ARM_SBC;
+               mnemonic = "SBC";
+               break;
+       case 13:
+               if (rd == 0xf) {
+                       instruction->type = ARM_CMP;
+                       mnemonic = "CMP";
+                       one = true;
+                       suffix = "";
+                       rd = rn;
+               } else {
+                       instruction->type = ARM_SUB;
+                       mnemonic = "SUB";
+               }
+               break;
+       case 14:
+               instruction->type = ARM_RSB;
+               mnemonic = "RSB";
+               break;
+       default:
+               return ERROR_INVALID_ARGUMENTS;
+       }
+
+       if (one)
+               sprintf(cp, "%s\tr%d, #%d\t; %#8.8x",
+                               mnemonic, rd, immed, immed);
+       else
+               sprintf(cp, "%s%s\tr%d, r%d, #%d\t; %#8.8x",
+                               mnemonic, suffix, rd, rn, immed, immed);
+
+       return ERROR_OK;
+}
+
+static int t2ev_data_immed(uint32_t opcode, uint32_t address,
+               arm_instruction_t *instruction, char *cp)
+{
+       char *mnemonic = NULL;
+       int rn = (opcode >> 16) & 0xf;
+       int rd = (opcode >> 8) & 0xf;
+       unsigned immed;
+       bool add = false;
+       bool is_signed = false;
+
+       immed = (opcode & 0x0ff) | ((opcode & 0x7000) >> 12);
+       if (opcode & (1 << 27))
+               immed |= (1 << 11);
+
+       switch ((opcode >> 20) & 0x1f) {
+       case 0:
+               if (rn == 0xf) {
+                       add = true;
+                       goto do_adr;
+               }
+               mnemonic = "ADD.W";
+               break;
+       case 4:
+               mnemonic = "MOV.W";
+               break;
+       case 0x0a:
+               if (rn == 0xf)
+                       goto do_adr;
+               mnemonic = "SUB.W";
+               break;
+       case 0x0c:
+               /* move constant to top 16 bits of register */
+               immed |= (opcode >> 4) & 0xf000;
+               sprintf(cp, "MOVT\tr%d, #%d\t; %#4.4x", rn, immed, immed);
+               return ERROR_OK;
+       case 0x10:
+       case 0x12:
+               is_signed = true;
+       case 0x18:
+       case 0x1a:
+               /* signed/unsigned saturated add */
+               immed = (opcode >> 6) & 0x03;
+               immed |= (opcode >> 10) & 0x1c;
+               sprintf(cp, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
+                               is_signed ? "S" : "U",
+                               rd, (opcode & 0x1f) + 1, rn,
+                               (opcode & (1 << 21)) ? "ASR" : "LSL",
+                               immed ? immed : 32);
+               return ERROR_OK;
+       case 0x14:
+               is_signed = true;
+               /* FALLTHROUGH */
+       case 0x1c:
+               /* signed/unsigned bitfield extract */
+               immed = (opcode >> 6) & 0x03;
+               immed |= (opcode >> 10) & 0x1c;
+               sprintf(cp, "%sBFX\tr%d, r%d, #%d, #%d\t",
+                               is_signed ? "S" : "U",
+                               rd, rn, immed,
+                               (opcode & 0x1f) + 1);
+               return ERROR_OK;
+       case 0x16:
+               immed = (opcode >> 6) & 0x03;
+               immed |= (opcode >> 10) & 0x1c;
+               if (rn == 0xf)          /* bitfield clear */
+                       sprintf(cp, "BFC\tr%d, #%d, #%d\t",
+                                       rd, immed,
+                                       (opcode & 0x1f) + 1 - immed);
+               else                    /* bitfield insert */
+                       sprintf(cp, "BFI\tr%d, r%d, #%d, #%d\t",
+                                       rd, rn, immed,
+                                       (opcode & 0x1f) + 1 - immed);
+               return ERROR_OK;
+       default:
+               return ERROR_INVALID_ARGUMENTS;
+       }
+
+       sprintf(cp, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic,
+                       rd, rn, immed, immed);
+       return ERROR_OK;
+
+do_adr:
+       address = thumb_alignpc4(address);
+       if (add)
+               address += immed;
+       else
+               address -= immed;
+       /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
+        * not hiding the pc-relative stuff will sometimes be useful.
+        */
+       sprintf(cp, "ADR.W\tr%d, %#8.8" PRIx32, rd, address);
+       return ERROR_OK;
+}
 
 /*
  * REVISIT for Thumb2 instructions, instruction->type and friends aren't
@@ -2580,8 +2821,16 @@ int thumb2_opcode(target_t *target, uint32_t address, arm_instruction_t *instruc
        cp = strchr(instruction->text, 0);
        retval = ERROR_FAIL;
 
+       /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
+       if ((opcode & 0x1a008000) == 0x10000000)
+               retval = t2ev_data_mod_immed(opcode, address, instruction, cp);
+
+       /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
+       else if ((opcode & 0x1a008000) == 0x12000000)
+               retval = t2ev_data_immed(opcode, address, instruction, cp);
+
        /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
-       if ((opcode & 0x18008000) == 0x10008000)
+       else if ((opcode & 0x18008000) == 0x10008000)
                retval = t2ev_b_misc(opcode, address, instruction, cp);
 
        /* FIXME decode more 32-bit instructions */

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)