X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Farm_disassembler.c;h=34d679c113b7a33355842294e914653501383725;hb=42cb62cf3b47b982d6444948b483f9c6ce32de05;hp=29ca23cae1273c4b28f7af6eece027700db58c0a;hpb=c79cca04bed78839a18e73f3996805eb8001a812;p=openocd.git diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 29ca23cae1..34d679c113 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -50,6 +50,7 @@ * except as coprocessor 10/11 operations * * Most ARM instructions through ARMv6 are decoded, but some * of the post-ARMv4 opcodes may not be handled yet + * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ... * * NEON instructions are not understood (ARMv7-A) * * - Thumb/Thumb2 decoding @@ -106,6 +107,16 @@ static uint32_t ror(uint32_t value, int places) return (value >> places) | (value << (32 - places)); } +static int evaluate_unknown(uint32_t opcode, + uint32_t address, struct arm_instruction *instruction) +{ + instruction->type = ARM_UNDEFINED_INSTRUCTION; + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 + "\tUNDEFINED INSTRUCTION", address, opcode); + return ERROR_OK; +} + static int evaluate_pld(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { @@ -118,14 +129,51 @@ static int evaluate_pld(uint32_t opcode, return ERROR_OK; } - else - { - instruction->type = ARM_UNDEFINED_INSTRUCTION; - return ERROR_OK; + return evaluate_unknown(opcode, address, instruction); +} + +static int evaluate_srs(uint32_t opcode, + uint32_t address, struct arm_instruction *instruction) +{ + const char *wback = (opcode & (1 << 21)) ? "!" : ""; + const char *mode = ""; + + switch ((opcode >> 23) & 0x3) { + case 0: + mode = "DA"; + break; + case 1: + /* "IA" is default */ + break; + case 2: + mode = "DB"; + break; + case 3: + mode = "IB"; + break; } - LOG_ERROR("should never reach this point"); - return -1; + switch (opcode & 0x0e500000) { + case 0x08400000: + snprintf(instruction->text, 128, "0x%8.8" PRIx32 + "\t0x%8.8" PRIx32 + "\tSRS%s\tSP%s, #%d", + address, opcode, + mode, wback, + (unsigned)(opcode & 0x1f)); + break; + case 0x08100000: + snprintf(instruction->text, 128, "0x%8.8" PRIx32 + "\t0x%8.8" PRIx32 + "\tRFE%s\tr%d%s", + address, opcode, + mode, + (unsigned)((opcode >> 16) & 0xf), wback); + break; + default: + return evaluate_unknown(opcode, address, instruction); + } + return ERROR_OK; } static int evaluate_swi(uint32_t opcode, @@ -232,28 +280,33 @@ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, { instruction->type = ARM_MCRR; mnemonic = "MCRR"; - } - - /* MRRC */ - if ((opcode & 0x0ff00000) == 0x0c500000) - { + } else if ((opcode & 0x0ff00000) == 0x0c500000) { + /* MRRC */ instruction->type = ARM_MRRC; mnemonic = "MRRC"; + } else { + LOG_ERROR("Unknown instruction"); + return ERROR_FAIL; } - snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, %x, r%i, r%i, c%i", - address, opcode, mnemonic, COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm); + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 + "\t%s%s%s p%i, %x, r%i, r%i, c%i", + address, opcode, mnemonic, + ((opcode & 0xf0000000) == 0xf0000000) + ? "2" : COND(opcode), + COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm); } else /* LDC or STC */ { uint8_t CRd, Rn, offset; - uint8_t U, N; + uint8_t U; char *mnemonic; char addressing_mode[32]; CRd = (opcode & 0xf000) >> 12; Rn = (opcode & 0xf0000) >> 16; - offset = (opcode & 0xff); + offset = (opcode & 0xff) << 2; /* load/store */ if (opcode & 0x00100000) @@ -268,22 +321,29 @@ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, } U = (opcode & 0x00800000) >> 23; - N = (opcode & 0x00400000) >> 22; /* addressing modes */ - if ((opcode & 0x01200000) == 0x01000000) /* immediate offset */ - snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]", Rn, (U) ? "" : "-", offset); - else if ((opcode & 0x01200000) == 0x01200000) /* immediate pre-indexed */ - snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]!", Rn, (U) ? "" : "-", offset); - else if ((opcode & 0x01200000) == 0x00200000) /* immediate post-indexed */ - snprintf(addressing_mode, 32, "[r%i], #%s0x%2.2x*4", Rn, (U) ? "" : "-", offset); + if ((opcode & 0x01200000) == 0x01000000) /* offset */ + snprintf(addressing_mode, 32, "[r%i, #%s%d]", + Rn, U ? "" : "-", offset); + else if ((opcode & 0x01200000) == 0x01200000) /* pre-indexed */ + snprintf(addressing_mode, 32, "[r%i, #%s%d]!", + Rn, U ? "" : "-", offset); + else if ((opcode & 0x01200000) == 0x00200000) /* post-indexed */ + snprintf(addressing_mode, 32, "[r%i], #%s%d", + Rn, U ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */ - snprintf(addressing_mode, 32, "[r%i], #0x%2.2x", Rn, offset); + snprintf(addressing_mode, 32, "[r%i], {%d}", + Rn, offset >> 2); - snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s p%i, c%i, %s", - address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? COND(opcode) : "2", - (N) ? "L" : "", - cp_num, CRd, addressing_mode); + snprintf(instruction->text, 128, "0x%8.8" PRIx32 + "\t0x%8.8" PRIx32 + "\t%s%s%s p%i, c%i, %s", + address, opcode, mnemonic, + ((opcode & 0xf0000000) == 0xf0000000) + ? "2" : COND(opcode), + (opcode & (1 << 22)) ? "L" : "", + cp_num, CRd, addressing_mode); } return ERROR_OK; @@ -1037,8 +1097,11 @@ static int evaluate_ldm_stm(uint32_t opcode, } } - snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i%s, {%s}%s", - address, opcode, mnemonic, COND(opcode), addressing_mode, + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 + "\t%s%s%s r%i%s, {%s}%s", + address, opcode, + mnemonic, addressing_mode, COND(opcode), Rn, (W) ? "!" : "", reg_list, (S) ? "^" : ""); return ERROR_OK; @@ -1591,7 +1654,8 @@ static int evaluate_data_proc(uint32_t opcode, return ERROR_OK; } -int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) +int arm_evaluate_opcode(uint32_t opcode, uint32_t address, + struct arm_instruction *instruction) { /* clear fields, to avoid confusion */ memset(instruction, 0, sizeof(struct arm_instruction)); @@ -1605,13 +1669,9 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instructio if ((opcode & 0x08000000) == 0x00000000) return evaluate_pld(opcode, address, instruction); - /* Undefined instruction */ + /* Undefined instruction (or ARMv6+ SRS/RFE) */ if ((opcode & 0x0e000000) == 0x08000000) - { - instruction->type = ARM_UNDEFINED_INSTRUCTION; - snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode); - return ERROR_OK; - } + return evaluate_srs(opcode, address, instruction); /* Branch and branch with link and change to Thumb */ if ((opcode & 0x0e000000) == 0x0a000000) @@ -1717,7 +1777,7 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instructio } /* catch opcodes with [27:25] = b110 */ - if ((opcode & 0x0e000000) == 0x0a000000) + if ((opcode & 0x0e000000) == 0x0c000000) { /* Coprocessor load/store and double register transfers */ return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction); @@ -1739,7 +1799,8 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instructio return evaluate_cdp_mcr_mrc(opcode, address, instruction); } - LOG_ERROR("should never reach this point"); + LOG_ERROR("ARM: should never reach this point (opcode=%08x)", + (unsigned) opcode); return -1; } @@ -2292,7 +2353,7 @@ static int evaluate_add_sp_pc_thumb(uint16_t opcode, uint8_t Rd = (opcode >> 8) & 0x7; uint8_t Rn; uint32_t SP = opcode & (1 << 11); - char *reg_name; + const char *reg_name; instruction->type = ARM_ADD; @@ -2753,7 +2814,7 @@ int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruct } } - LOG_ERROR("should never reach this point (opcode=%04x)",opcode); + LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode); return -1; } @@ -2952,7 +3013,7 @@ static int t2ev_misc(uint32_t opcode, uint32_t address, mnemonic = "ISB"; break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } strcpy(cp, mnemonic); return ERROR_OK; @@ -3003,7 +3064,7 @@ static int t2ev_b_misc(uint32_t opcode, uint32_t address, } undef: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } static int t2ev_data_mod_immed(uint32_t opcode, uint32_t address, @@ -3138,7 +3199,7 @@ static int t2ev_data_mod_immed(uint32_t opcode, uint32_t address, suffix2 = ".W"; break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } if (one) @@ -3186,7 +3247,7 @@ static int t2ev_data_immed(uint32_t opcode, uint32_t address, 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); + sprintf(cp, "MOVT\tr%d, #%d\t; %#4.4x", rd, immed, immed); return ERROR_OK; case 0x10: case 0x12: @@ -3227,7 +3288,7 @@ static int t2ev_data_immed(uint32_t opcode, uint32_t address, (int) (opcode & 0x1f) + 1 - immed); return ERROR_OK; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic, @@ -3260,7 +3321,7 @@ static int t2ev_store_single(uint32_t opcode, uint32_t address, unsigned rt = (opcode >> 12) & 0x0f; if (rn == 0xf) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; if (opcode & 0x0800) op |= 1; @@ -3297,7 +3358,7 @@ static int t2ev_store_single(uint32_t opcode, uint32_t address, break; /* error */ default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]", @@ -3320,7 +3381,7 @@ imm8: break; case 0x000: case 0x200: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } /* two indexed modes will write back rn */ @@ -3365,7 +3426,7 @@ static int t2ev_mul32(uint32_t opcode, uint32_t address, (int) (opcode >> 0) & 0xf, ra); break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } @@ -3401,7 +3462,7 @@ static int t2ev_mul64_div(uint32_t opcode, uint32_t address, (int) (opcode >> 0) & 0xf); break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; @@ -3414,11 +3475,28 @@ static int t2ev_ldm_stm(uint32_t opcode, uint32_t address, int op = (opcode >> 22) & 0x6; int t = (opcode >> 21) & 1; unsigned registers = opcode & 0xffff; + char *mode = ""; if (opcode & (1 << 20)) op |= 1; switch (op) { + case 0: + mode = "DB"; + /* FALL THROUGH */ + case 6: + sprintf(cp, "SRS%s\tsp%s, #%d", mode, + t ? "!" : "", + (unsigned) (opcode & 0x1f)); + return ERROR_OK; + case 1: + mode = "DB"; + /* FALL THROUGH */ + case 7: + sprintf(cp, "RFE%s\tr%d%s", mode, + (unsigned) ((opcode >> 16) & 0xf), + t ? "!" : ""); + return ERROR_OK; case 2: sprintf(cp, "STM.W\tr%d%s, ", rn, t ? "!" : ""); break; @@ -3438,7 +3516,7 @@ static int t2ev_ldm_stm(uint32_t opcode, uint32_t address, sprintf(cp, "LDMDB.W\tr%d%s, ", rn, t ? "!" : ""); break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } cp = strchr(cp, 0); @@ -3506,7 +3584,7 @@ static int t2ev_ldrex_strex(uint32_t opcode, uint32_t address, mnemonic = "STREXH"; break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } rd = opcode & 0xf; imm = 0; @@ -3526,12 +3604,12 @@ static int t2ev_ldrex_strex(uint32_t opcode, uint32_t address, mnemonic = "LDREXH"; break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } imm = 0; goto ldrex; } - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; strex: imm <<= 2; @@ -3602,7 +3680,7 @@ static int t2ev_data_shift(uint32_t opcode, uint32_t address, case 0: if (rd == 0xf) { if (!(opcode & (1 << 20))) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_TST; mnemonic = "TST"; suffix = ""; @@ -3664,7 +3742,7 @@ static int t2ev_data_shift(uint32_t opcode, uint32_t address, case 4: if (rd == 0xf) { if (!(opcode & (1 << 20))) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_TEQ; mnemonic = "TEQ"; suffix = ""; @@ -3676,7 +3754,7 @@ static int t2ev_data_shift(uint32_t opcode, uint32_t address, case 8: if (rd == 0xf) { if (!(opcode & (1 << 20))) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_CMN; mnemonic = "CMN"; suffix = ""; @@ -3696,7 +3774,7 @@ static int t2ev_data_shift(uint32_t opcode, uint32_t address, case 0xd: if (rd == 0xf) { if (!(opcode & (1 << 21))) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_CMP; mnemonic = "CMP"; suffix = ""; @@ -3710,7 +3788,7 @@ static int t2ev_data_shift(uint32_t opcode, uint32_t address, mnemonic = "RSB"; break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "%s%s.W\tr%d, r%d, r%d", @@ -3779,7 +3857,7 @@ static int t2ev_data_reg(uint32_t opcode, uint32_t address, mnemonic = "ROR"; break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } instruction->type = ARM_MOV; @@ -3820,11 +3898,11 @@ static int t2ev_data_reg(uint32_t opcode, uint32_t address, case 0xa: case 0xb: if (opcode & (1 << 6)) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; if (((opcode >> 12) & 0xf) != 0xf) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; if (!(opcode & (1 << 20))) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; switch (((opcode >> 19) & 0x04) | ((opcode >> 4) & 0x3)) { @@ -3844,7 +3922,7 @@ static int t2ev_data_reg(uint32_t opcode, uint32_t address, mnemonic = "CLZ"; break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "%s\tr%d, r%d", mnemonic, @@ -3852,7 +3930,7 @@ static int t2ev_data_reg(uint32_t opcode, uint32_t address, (int) (opcode >> 0) & 0xf); break; default: - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -3908,7 +3986,7 @@ static int t2ev_load_word(uint32_t opcode, uint32_t address, char *p1 = "]", *p2 = ""; if (!(opcode & 0x0500)) - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; immed = opcode & 0x00ff; @@ -3930,7 +4008,7 @@ static int t2ev_load_word(uint32_t opcode, uint32_t address, return ERROR_OK; } - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } static int t2ev_load_byte_hints(uint32_t opcode, uint32_t address, @@ -4109,7 +4187,7 @@ ldrsb_literal: goto ldrxb_immediate_t2; } - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } static int t2ev_load_halfword(uint32_t opcode, uint32_t address, @@ -4187,7 +4265,7 @@ ldrh_literal: return ERROR_OK; } - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } /* @@ -4299,7 +4377,7 @@ int thumb2_opcode(struct target *target, uint32_t address, struct arm_instructio * instructions; not yet handled here. */ - if (retval == ERROR_INVALID_ARGUMENTS) { + if (retval == ERROR_COMMAND_SYNTAX_ERROR) { instruction->type = ARM_UNDEFINED_INSTRUCTION; strcpy(cp, "UNDEFINED OPCODE"); return ERROR_OK;