David Brownell <david-b@pacbell.net>:
authorzwelch <zwelch@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 15 Jul 2009 23:48:11 +0000 (23:48 +0000)
committerzwelch <zwelch@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 15 Jul 2009 23:48:11 +0000 (23:48 +0000)
Make the Thumb2 disassembler handle a bunch of 32-bit instructions:

  A5.3.4 Branches and miscellaneous control

Note that this shifts some responsabililty out of helper functions,
making the code and layout simpler for 32-bit decoders:  they only
need to know how to format the instruction and its parameters.

Also, technical note:  with this patch, Thumb1 decoders could now
call the Thumb2 decoder if they wanted to get nicer treatment of
the exiting 32-bit B/BLX instructions.

git-svn-id: svn://svn.berlios.de/openocd/trunk@2532 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/target/arm_disassembler.c

index 4d1342137ee2b3c8e97617e4438c04bb117b4cd0..69d5de87df678d6a1cb6f4bf7975256c750c7db7 100644 (file)
@@ -2292,6 +2292,247 @@ int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, arm_instruction_t *
        return -1;
 }
 
+static int t2ev_b_bl(uint32_t opcode, uint32_t address,
+               arm_instruction_t *instruction, char *cp)
+{
+       unsigned offset;
+       unsigned b21 = 1 << 21;
+       unsigned b22 = 1 << 22;
+
+       /* instead of combining two smaller 16-bit branch instructions,
+        * Thumb2 uses only one larger 32-bit instruction.
+        */
+       offset = opcode & 0x7ff;
+       offset |= (opcode & 0x03ff0000) >> 5;
+       if (opcode & (1 << 26)) {
+               offset |= 0xff << 23;
+               if ((opcode & (1 << 11)) == 0)
+                       b21 = 0;
+               if ((opcode & (1 << 13)) == 0)
+                       b22 = 0;
+       } else {
+               if (opcode & (1 << 11))
+                       b21 = 0;
+               if (opcode & (1 << 13))
+                       b22 = 0;
+       }
+       offset |= b21;
+       offset |= b22;
+
+
+       address += 4;
+       address += offset << 1;
+
+       instruction->type = (opcode & (1 << 14)) ? ARM_BL : ARM_B;
+       instruction->info.b_bl_bx_blx.reg_operand = -1;
+       instruction->info.b_bl_bx_blx.target_address = address;
+       sprintf(cp, "%s\t%#8.8" PRIx32,
+                       (opcode & (1 << 14)) ? "BL" : "B.W",
+                       address);
+
+       return ERROR_OK;
+}
+
+static int t2ev_cond_b(uint32_t opcode, uint32_t address,
+               arm_instruction_t *instruction, char *cp)
+{
+       unsigned offset;
+       unsigned b17 = 1 << 17;
+       unsigned b18 = 1 << 18;
+       unsigned cond = (opcode >> 22) & 0x0f;
+
+       offset = opcode & 0x7ff;
+       offset |= (opcode & 0x003f0000) >> 5;
+       if (opcode & (1 << 26)) {
+               offset |= 0xffff << 19;
+               if ((opcode & (1 << 11)) == 0)
+                       b17 = 0;
+               if ((opcode & (1 << 13)) == 0)
+                       b18 = 0;
+       } else {
+               if (opcode & (1 << 11))
+                       b17 = 0;
+               if (opcode & (1 << 13))
+                       b18 = 0;
+       }
+       offset |= b17;
+       offset |= b18;
+
+       address += 4;
+       address += offset << 1;
+
+       instruction->type = ARM_B;
+       instruction->info.b_bl_bx_blx.reg_operand = -1;
+       instruction->info.b_bl_bx_blx.target_address = address;
+       sprintf(cp, "B%s.W\t%#8.8" PRIx32,
+                       arm_condition_strings[cond],
+                       address);
+
+       return ERROR_OK;
+}
+
+static const char *special_name(int number)
+{
+       char *special = "(RESERVED)";
+
+       switch (number) {
+       case 0:
+               special = "apsr";
+               break;
+       case 1:
+               special = "iapsr";
+               break;
+       case 2:
+               special = "eapsr";
+               break;
+       case 3:
+               special = "xpsr";
+               break;
+       case 5:
+               special = "ipsr";
+               break;
+       case 6:
+               special = "epsr";
+               break;
+       case 7:
+               special = "iepsr";
+               break;
+       case 8:
+               special = "msp";
+               break;
+       case 9:
+               special = "psp";
+               break;
+       case 16:
+               special = "primask";
+               break;
+       case 17:
+               special = "basepri";
+               break;
+       case 18:
+               special = "basepri_max";
+               break;
+       case 19:
+               special = "faultmask";
+               break;
+       case 20:
+               special = "control";
+               break;
+       }
+       return special;
+}
+
+static int t2ev_hint(uint32_t opcode, uint32_t address,
+               arm_instruction_t *instruction, char *cp)
+{
+       const char *mnemonic;
+
+       if (opcode & 0x0700) {
+               instruction->type = ARM_UNDEFINED_INSTRUCTION;
+               strcpy(cp, "UNDEFINED");
+               return ERROR_OK;
+       }
+
+       if (opcode & 0x00f0) {
+               sprintf(cp, "DBG\t#%d", opcode & 0xf);
+               return ERROR_OK;
+       }
+
+       switch (opcode & 0x0f) {
+       case 0:
+               mnemonic = "NOP.W";
+               break;
+       case 1:
+               mnemonic = "YIELD.W";
+               break;
+       case 2:
+               mnemonic = "WFE.W";
+               break;
+       case 3:
+               mnemonic = "WFI.W";
+               break;
+       case 4:
+               mnemonic = "SEV.W";
+               break;
+       default:
+               mnemonic = "HINT.W (UNRECOGNIZED)";
+               break;
+       }
+       strcpy(cp, mnemonic);
+       return ERROR_OK;
+}
+
+static int t2ev_misc(uint32_t opcode, uint32_t address,
+               arm_instruction_t *instruction, char *cp)
+{
+       const char *mnemonic;
+
+       switch ((opcode >> 4) & 0x0f) {
+       case 2:
+               mnemonic = "CLREX";
+               break;
+       case 4:
+               mnemonic = "DSB";
+               break;
+       case 5:
+               mnemonic = "DMB";
+               break;
+       case 6:
+               mnemonic = "ISB";
+               break;
+       default:
+               return ERROR_INVALID_ARGUMENTS;
+       }
+       strcpy(cp, mnemonic);
+       return ERROR_OK;
+}
+
+static int t2ev_b_misc(uint32_t opcode, uint32_t address,
+               arm_instruction_t *instruction, char *cp)
+{
+       /* permanently undefined */
+       if ((opcode & 0x07f07000) == 0x07f02000) {
+               instruction->type = ARM_UNDEFINED_INSTRUCTION;
+               strcpy(cp, "UNDEFINED");
+               return ERROR_OK;
+       }
+
+       switch ((opcode >> 12) & 0x5) {
+       case 0x1:
+       case 0x5:
+               return t2ev_b_bl(opcode, address, instruction, cp);
+       case 0x4:
+               goto undef;
+       case 0:
+               if (((opcode >> 23) & 0x07) == 0x07)
+                       return t2ev_cond_b(opcode, address, instruction, cp);
+               if (opcode & (1 << 26))
+                       goto undef;
+               break;
+       }
+
+       switch ((opcode >> 20) & 0x7f) {
+       case 0x38:
+       case 0x39:
+               sprintf(cp, "MSR\t%s, r%d", special_name(opcode & 0xff),
+                               (opcode >> 16) & 0x0f);
+               return ERROR_OK;
+       case 0x3a:
+               return t2ev_hint(opcode, address, instruction, cp);
+       case 0x3b:
+               return t2ev_misc(opcode, address, instruction, cp);
+       case 0x3e:
+       case 0x3f:
+               sprintf(cp, "MRS\tr%d, %s", (opcode >> 16) & 0x0f,
+                               special_name(opcode & 0xff));
+               return ERROR_OK;
+       }
+
+undef:
+       return ERROR_INVALID_ARGUMENTS;
+}
+
+
 /*
  * REVISIT for Thumb2 instructions, instruction->type and friends aren't
  * always set.  That means eventual arm_simulate_step() support for Thumb2
@@ -2302,6 +2543,7 @@ int thumb2_opcode(target_t *target, uint32_t address, arm_instruction_t *instruc
        int retval;
        uint16_t op;
        uint32_t opcode;
+       char *cp;
 
        /* clear low bit ... it's set on function pointers */
        address &= ~1;
@@ -2332,13 +2574,30 @@ int thumb2_opcode(target_t *target, uint32_t address, arm_instruction_t *instruc
                return thumb_evaluate_opcode(op, address, instruction);
        }
 
-       /* FIXME decode the 32-bit instructions */
+       snprintf(instruction->text, 128,
+                       "0x%8.8" PRIx32 "  0x%8.8" PRIx32 "\t",
+                       address, opcode);
+       cp = strchr(instruction->text, 0);
+       retval = ERROR_FAIL;
+
+       /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
+       if ((opcode & 0x18008000) == 0x10008000)
+               retval = t2ev_b_misc(opcode, address, instruction, cp);
+
+       /* FIXME decode more 32-bit instructions */
+
+       if (retval == ERROR_OK)
+               return retval;
+
+       if (retval == ERROR_INVALID_ARGUMENTS) {
+               instruction->type = ARM_UNDEFINED_INSTRUCTION;
+               strcpy(cp, "UNDEFINED OPCODE");
+               return ERROR_OK;
+       }
 
        LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08x)", opcode);
 
-       snprintf(instruction->text, 128,
-                       "0x%8.8" PRIx32 "  0x%8.8x\t... 32-bit Thumb2 ...",
-                       address, opcode);
+       strcpy(cp, "(32-bit Thumb2 ...)");
        return ERROR_OK;
 }
 

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)