2013-11-01 07:50:42 +00:00
|
|
|
#include "decoder.h"
|
2013-10-31 06:22:38 +00:00
|
|
|
|
2013-11-01 07:47:12 +00:00
|
|
|
#include "arm.h"
|
2013-11-02 07:34:49 +00:00
|
|
|
#include "decoder-inlines.h"
|
2013-11-01 07:47:12 +00:00
|
|
|
#include "emitter-thumb.h"
|
|
|
|
#include "isa-inlines.h"
|
|
|
|
|
2013-11-01 08:47:04 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2013-11-01 07:47:12 +00:00
|
|
|
#define DEFINE_THUMB_DECODER(NAME, MNEMONIC, BODY) \
|
2014-07-10 10:30:59 +00:00
|
|
|
static void _ThumbDecode ## NAME (uint16_t opcode, struct ARMInstructionInfo* info) { \
|
2013-11-01 07:47:12 +00:00
|
|
|
UNUSED(opcode); \
|
2014-07-10 10:30:59 +00:00
|
|
|
info->mnemonic = ARM_MN_ ## MNEMONIC; \
|
2013-11-01 07:47:12 +00:00
|
|
|
BODY; \
|
|
|
|
}
|
|
|
|
|
2013-11-09 21:49:34 +00:00
|
|
|
#define DEFINE_IMMEDIATE_5_DECODER_DATA_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
|
2013-11-01 07:47:12 +00:00
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op3.immediate = IMMEDIATE; \
|
|
|
|
info->op1.reg = opcode & 0x0007; \
|
|
|
|
info->op2.reg = (opcode >> 3) & 0x0007; \
|
|
|
|
info->affectsCPSR = 1; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_REGISTER_2 | \
|
|
|
|
ARM_OPERAND_IMMEDIATE_3;)
|
|
|
|
|
2013-11-09 21:49:34 +00:00
|
|
|
#define DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, CYCLES, WIDTH) \
|
2013-11-01 07:47:12 +00:00
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = opcode & 0x0007; \
|
|
|
|
info->memory.baseReg = (opcode >> 3) & 0x0007; \
|
2013-11-09 21:49:34 +00:00
|
|
|
info->memory.offset.immediate = IMMEDIATE * WIDTH; \
|
2014-07-10 10:30:59 +00:00
|
|
|
info->memory.width = (enum ARMMemoryAccessType) WIDTH; \
|
2013-11-01 07:47:12 +00:00
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_MEMORY_2; \
|
|
|
|
info->memory.format = ARM_MEMORY_REGISTER_BASE | \
|
2013-11-02 09:52:53 +00:00
|
|
|
ARM_MEMORY_IMMEDIATE_OFFSET; \
|
|
|
|
CYCLES)
|
|
|
|
|
2013-11-09 21:49:34 +00:00
|
|
|
#define DEFINE_IMMEDIATE_5_DECODER_MEM_LOAD_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
|
|
|
|
DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, LOAD_CYCLES, WIDTH)
|
2013-11-02 09:52:53 +00:00
|
|
|
|
2013-11-09 21:49:34 +00:00
|
|
|
#define DEFINE_IMMEDIATE_5_DECODER_MEM_STORE_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
|
|
|
|
DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, STORE_CYCLES, WIDTH)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
2013-11-09 21:49:34 +00:00
|
|
|
#define DEFINE_IMMEDIATE_5_DECODER_THUMB(NAME, MNEMONIC, TYPE, WIDTH) \
|
|
|
|
COUNT_5(DEFINE_IMMEDIATE_5_DECODER_ ## TYPE ## _THUMB, NAME ## _, MNEMONIC, WIDTH)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
2013-11-09 21:49:34 +00:00
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(LSL1, LSL, DATA,)
|
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(LSR1, LSR, DATA,)
|
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(ASR1, ASR, DATA,)
|
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(LDR1, LDR, MEM_LOAD, 4)
|
2014-07-10 10:30:59 +00:00
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRB1, LDR, MEM_LOAD, 1)
|
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRH1, LDR, MEM_LOAD, 2)
|
2013-11-09 21:49:34 +00:00
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(STR1, STR, MEM_STORE, 4)
|
2014-07-10 10:30:59 +00:00
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(STRB1, STR, MEM_STORE, 1)
|
|
|
|
DEFINE_IMMEDIATE_5_DECODER_THUMB(STRH1, STR, MEM_STORE, 2)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
#define DEFINE_DATA_FORM_1_DECODER_EX_THUMB(NAME, RM, MNEMONIC) \
|
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = opcode & 0x0007; \
|
|
|
|
info->op2.reg = (opcode >> 3) & 0x0007; \
|
|
|
|
info->op3.reg = RM; \
|
|
|
|
info->affectsCPSR = 1; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_REGISTER_2 | \
|
|
|
|
ARM_OPERAND_REGISTER_3;)
|
|
|
|
|
|
|
|
#define DEFINE_DATA_FORM_1_DECODER_THUMB(NAME) \
|
|
|
|
COUNT_3(DEFINE_DATA_FORM_1_DECODER_EX_THUMB, NAME ## 3_R, NAME)
|
|
|
|
|
2013-11-02 09:52:53 +00:00
|
|
|
DEFINE_DATA_FORM_1_DECODER_THUMB(ADD)
|
2013-11-01 07:47:12 +00:00
|
|
|
DEFINE_DATA_FORM_1_DECODER_THUMB(SUB)
|
|
|
|
|
|
|
|
#define DEFINE_DATA_FORM_2_DECODER_EX_THUMB(NAME, IMMEDIATE, MNEMONIC) \
|
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = opcode & 0x0007; \
|
|
|
|
info->op2.reg = (opcode >> 3) & 0x0007; \
|
|
|
|
info->op3.immediate = IMMEDIATE; \
|
|
|
|
info->affectsCPSR = 1; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_REGISTER_2 | \
|
|
|
|
ARM_OPERAND_IMMEDIATE_3;)
|
|
|
|
|
|
|
|
#define DEFINE_DATA_FORM_2_DECODER_THUMB(NAME) \
|
|
|
|
COUNT_3(DEFINE_DATA_FORM_2_DECODER_EX_THUMB, NAME ## 1_, NAME)
|
|
|
|
|
|
|
|
DEFINE_DATA_FORM_2_DECODER_THUMB(ADD)
|
|
|
|
DEFINE_DATA_FORM_2_DECODER_THUMB(SUB)
|
|
|
|
|
|
|
|
#define DEFINE_DATA_FORM_3_DECODER_EX_THUMB(NAME, RD, MNEMONIC, AFFECTED) \
|
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = RD; \
|
|
|
|
info->op2.immediate = opcode & 0x00FF; \
|
|
|
|
info->affectsCPSR = 1; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
AFFECTED | \
|
|
|
|
ARM_OPERAND_IMMEDIATE_2;)
|
|
|
|
|
|
|
|
#define DEFINE_DATA_FORM_3_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
|
|
|
|
COUNT_3(DEFINE_DATA_FORM_3_DECODER_EX_THUMB, NAME ## _R, MNEMONIC, AFFECTED)
|
|
|
|
|
|
|
|
DEFINE_DATA_FORM_3_DECODER_THUMB(ADD2, ADD, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_3_DECODER_THUMB(CMP1, CMP, ARM_OPERAND_NONE)
|
|
|
|
DEFINE_DATA_FORM_3_DECODER_THUMB(MOV1, MOV, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_3_DECODER_THUMB(SUB2, SUB, ARM_OPERAND_AFFECTED_1)
|
|
|
|
|
|
|
|
#define DEFINE_DATA_FORM_5_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
|
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = opcode & 0x0007; \
|
|
|
|
info->op2.reg = (opcode >> 3) & 0x0007; \
|
|
|
|
info->affectsCPSR = 1; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
AFFECTED | \
|
|
|
|
ARM_OPERAND_REGISTER_2;)
|
|
|
|
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(AND, AND, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(EOR, EOR, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(LSL2, LSL, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(LSR2, LSR, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(ASR2, ASR, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(ADC, ADC, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(SBC, SBC, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(ROR, ROR, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(TST, TST, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(NEG, NEG, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(CMP2, CMP, ARM_OPERAND_NONE)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(CMN, CMN, ARM_OPERAND_NONE)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(ORR, ORR, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(MUL, MUL, ARM_OPERAND_AFFECTED_1)
|
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(BIC, BIC, ARM_OPERAND_AFFECTED_1)
|
2013-11-02 09:52:53 +00:00
|
|
|
DEFINE_DATA_FORM_5_DECODER_THUMB(MVN, MVN, ARM_OPERAND_AFFECTED_1)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
#define DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME, H1, H2, MNEMONIC, AFFECTED, CPSR) \
|
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = (opcode & 0x0007) | H1; \
|
|
|
|
info->op2.reg = ((opcode >> 3) & 0x0007) | H2; \
|
2013-11-03 00:07:58 +00:00
|
|
|
info->branches = info->op1.reg == ARM_PC; \
|
2013-11-01 07:47:12 +00:00
|
|
|
info->affectsCPSR = CPSR; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
AFFECTED | \
|
|
|
|
ARM_OPERAND_REGISTER_2;)
|
|
|
|
|
|
|
|
|
|
|
|
#define DEFINE_DECODER_WITH_HIGH_THUMB(NAME, MNEMONIC, AFFECTED, CPSR) \
|
|
|
|
DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 00, 0, 0, MNEMONIC, AFFECTED, CPSR) \
|
|
|
|
DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 01, 0, 8, MNEMONIC, AFFECTED, CPSR) \
|
|
|
|
DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 10, 8, 0, MNEMONIC, AFFECTED, CPSR) \
|
|
|
|
DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 11, 8, 8, MNEMONIC, AFFECTED, CPSR)
|
|
|
|
|
|
|
|
DEFINE_DECODER_WITH_HIGH_THUMB(ADD4, ADD, ARM_OPERAND_AFFECTED_1, 0)
|
|
|
|
DEFINE_DECODER_WITH_HIGH_THUMB(CMP3, CMP, ARM_OPERAND_NONE, 1)
|
|
|
|
DEFINE_DECODER_WITH_HIGH_THUMB(MOV3, MOV, ARM_OPERAND_AFFECTED_1, 0)
|
|
|
|
|
|
|
|
#define DEFINE_IMMEDIATE_WITH_REGISTER_DATA_THUMB(NAME, RD, MNEMONIC, REG) \
|
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = RD; \
|
|
|
|
info->op2.reg = REG; \
|
|
|
|
info->op3.immediate = (opcode & 0x00FF) << 2; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_REGISTER_2 | \
|
|
|
|
ARM_OPERAND_IMMEDIATE_3;)
|
|
|
|
|
2013-11-02 09:52:53 +00:00
|
|
|
#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, CYCLES) \
|
2013-11-01 07:47:12 +00:00
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = RD; \
|
|
|
|
info->memory.baseReg = REG; \
|
|
|
|
info->memory.offset.immediate = (opcode & 0x00FF) << 2; \
|
2014-07-10 10:30:59 +00:00
|
|
|
info->memory.width = ARM_ACCESS_WORD; \
|
2013-11-01 07:47:12 +00:00
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_MEMORY_2; \
|
|
|
|
info->memory.format = ARM_MEMORY_REGISTER_BASE | \
|
2013-11-02 09:52:53 +00:00
|
|
|
ARM_MEMORY_IMMEDIATE_OFFSET; \
|
|
|
|
CYCLES;)
|
|
|
|
|
|
|
|
#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_LOAD_THUMB(NAME, RD, MNEMONIC, REG) \
|
|
|
|
DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, LOAD_CYCLES)
|
|
|
|
|
|
|
|
#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_STORE_THUMB(NAME, RD, MNEMONIC, REG) \
|
|
|
|
DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, STORE_CYCLES)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
#define DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(NAME, MNEMONIC, TYPE, REG) \
|
|
|
|
COUNT_3(DEFINE_IMMEDIATE_WITH_REGISTER_ ## TYPE ## _THUMB, NAME ## _R, MNEMONIC, REG)
|
|
|
|
|
2013-11-02 09:52:53 +00:00
|
|
|
DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR3, LDR, MEM_LOAD, ARM_PC)
|
|
|
|
DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR4, LDR, MEM_LOAD, ARM_SP)
|
|
|
|
DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(STR3, STR, MEM_STORE, ARM_SP)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD5, ADD, DATA, ARM_PC)
|
|
|
|
DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD6, ADD, DATA, ARM_SP)
|
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
#define DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB(NAME, RM, MNEMONIC, CYCLES, TYPE) \
|
2013-11-01 07:47:12 +00:00
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->memory.offset.reg = RM; \
|
|
|
|
info->op1.reg = opcode & 0x0007; \
|
|
|
|
info->memory.baseReg = (opcode >> 3) & 0x0007; \
|
2014-07-10 10:30:59 +00:00
|
|
|
info->memory.width = TYPE; \
|
2013-11-01 07:47:12 +00:00
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_MEMORY_2; \
|
|
|
|
info->memory.format = ARM_MEMORY_REGISTER_BASE | \
|
2013-11-02 09:52:53 +00:00
|
|
|
ARM_MEMORY_REGISTER_OFFSET; \
|
|
|
|
CYCLES;)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
#define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, MNEMONIC, CYCLES, TYPE) \
|
|
|
|
COUNT_3(DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB, NAME ## _R, MNEMONIC, CYCLES, TYPE)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, LDR, LOAD_CYCLES, ARM_ACCESS_WORD)
|
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, LDR, LOAD_CYCLES, ARM_ACCESS_BYTE)
|
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, LDR, LOAD_CYCLES, ARM_ACCESS_HALFWORD)
|
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_BYTE)
|
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_HALFWORD)
|
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, STR, STORE_CYCLES, ARM_ACCESS_WORD)
|
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, STR, STORE_CYCLES, ARM_ACCESS_BYTE)
|
|
|
|
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STR, STORE_CYCLES, ARM_ACCESS_HALFWORD)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
#define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, MNEMONIC, DIRECTION, ADDITIONAL_REG) \
|
2013-11-01 07:47:12 +00:00
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->memory.baseReg = RN; \
|
2013-11-01 08:47:04 +00:00
|
|
|
info->op1.immediate = (opcode & 0xFF) | ADDITIONAL_REG; \
|
2013-11-03 00:07:58 +00:00
|
|
|
info->branches = info->op1.immediate & (1 << ARM_PC); \
|
2013-11-02 11:12:21 +00:00
|
|
|
info->operandFormat = ARM_OPERAND_MEMORY_1; \
|
2014-07-10 10:30:59 +00:00
|
|
|
info->memory.direction = DIRECTION; \
|
2013-11-01 07:47:12 +00:00
|
|
|
info->memory.format = ARM_MEMORY_REGISTER_BASE | \
|
|
|
|
ARM_MEMORY_POST_INCREMENT;)
|
|
|
|
|
|
|
|
#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME) \
|
2014-07-10 10:30:59 +00:00
|
|
|
COUNT_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## IA_R, NAME, ARM_INCREMENT_AFTER, 0)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDM)
|
|
|
|
DEFINE_LOAD_STORE_MULTIPLE_THUMB(STM)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
#define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
|
|
|
|
DEFINE_THUMB_DECODER(B ## COND, B, \
|
|
|
|
int8_t immediate = opcode; \
|
2013-11-02 05:29:55 +00:00
|
|
|
info->op1.immediate = immediate << 1; \
|
2013-11-01 07:47:12 +00:00
|
|
|
info->branches = 1; \
|
2013-11-02 05:29:55 +00:00
|
|
|
info->condition = ARM_CONDITION_ ## COND; \
|
2013-11-01 07:47:12 +00:00
|
|
|
info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
|
|
|
|
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(EQ)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(NE)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(CS)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(CC)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(MI)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(PL)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(VS)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(VC)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(LS)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(HI)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(GE)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(LT)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(GT)
|
|
|
|
DEFINE_CONDITIONAL_BRANCH_THUMB(LE)
|
|
|
|
|
|
|
|
#define DEFINE_SP_MODIFY_THUMB(NAME, MNEMONIC) \
|
|
|
|
DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
|
|
|
|
info->op1.reg = ARM_SP; \
|
|
|
|
info->op2.immediate = (opcode & 0x7F) << 2; \
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1 | \
|
|
|
|
ARM_OPERAND_AFFECTED_1 | \
|
|
|
|
ARM_OPERAND_IMMEDIATE_2;)
|
|
|
|
|
|
|
|
DEFINE_SP_MODIFY_THUMB(ADD7, ADD)
|
|
|
|
DEFINE_SP_MODIFY_THUMB(SUB4, SUB)
|
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POP, ARM_SP, LDM, ARM_INCREMENT_AFTER, 0)
|
|
|
|
DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR, ARM_SP, LDM, ARM_INCREMENT_AFTER, 1 << ARM_PC)
|
|
|
|
DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH, ARM_SP, STM, ARM_DECREMENT_BEFORE, 0)
|
|
|
|
DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR, ARM_SP, STM, ARM_DECREMENT_BEFORE, 1 << ARM_LR)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
DEFINE_THUMB_DECODER(ILL, ILL, info->traps = 1;)
|
|
|
|
DEFINE_THUMB_DECODER(BKPT, BKPT, info->traps = 1;)
|
|
|
|
|
|
|
|
DEFINE_THUMB_DECODER(B, B,
|
|
|
|
int16_t immediate = (opcode & 0x07FF) << 5;
|
|
|
|
info->op1.immediate = (((int32_t) immediate) >> 4);
|
|
|
|
info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
|
|
|
|
info->branches = 1;)
|
|
|
|
|
|
|
|
DEFINE_THUMB_DECODER(BL1, BLH,
|
|
|
|
int16_t immediate = (opcode & 0x07FF) << 5;
|
|
|
|
info->op1.immediate = (((int32_t) immediate) << 7);
|
2014-07-10 09:33:16 +00:00
|
|
|
info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
DEFINE_THUMB_DECODER(BL2, BL,
|
|
|
|
info->op1.immediate = (opcode & 0x07FF) << 1;
|
|
|
|
info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
|
|
|
|
info->branches = 1;)
|
|
|
|
|
|
|
|
DEFINE_THUMB_DECODER(BX, BX,
|
|
|
|
info->op1.reg = (opcode >> 3) & 0xF;
|
|
|
|
info->operandFormat = ARM_OPERAND_REGISTER_1;
|
|
|
|
info->branches = 1;)
|
|
|
|
|
|
|
|
DEFINE_THUMB_DECODER(SWI, SWI,
|
|
|
|
info->op1.immediate = opcode & 0xFF;
|
|
|
|
info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
|
|
|
|
info->traps = 1;)
|
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
typedef void (*ThumbDecoder)(uint16_t opcode, struct ARMInstructionInfo* info);
|
2013-11-01 07:47:12 +00:00
|
|
|
|
|
|
|
static const ThumbDecoder _thumbDecoderTable[0x400] = {
|
|
|
|
DECLARE_THUMB_EMITTER_BLOCK(_ThumbDecode)
|
|
|
|
};
|
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) {
|
2013-10-31 06:22:38 +00:00
|
|
|
info->opcode = opcode;
|
2013-11-01 07:47:12 +00:00
|
|
|
info->branches = 0;
|
|
|
|
info->traps = 0;
|
|
|
|
info->affectsCPSR = 0;
|
2013-11-02 05:29:55 +00:00
|
|
|
info->condition = ARM_CONDITION_AL;
|
2013-11-02 09:52:53 +00:00
|
|
|
info->sDataCycles = 0;
|
|
|
|
info->nDataCycles = 0;
|
|
|
|
info->sInstructionCycles = 1;
|
|
|
|
info->nInstructionCycles = 0;
|
|
|
|
info->iCycles = 0;
|
|
|
|
info->cCycles = 0;
|
2013-11-01 07:47:12 +00:00
|
|
|
ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6];
|
|
|
|
decoder(opcode, info);
|
2013-10-31 06:22:38 +00:00
|
|
|
}
|
2013-11-01 08:47:04 +00:00
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
const char* armMnemonicStrings[] = {
|
2013-11-01 08:47:04 +00:00
|
|
|
"ill",
|
|
|
|
"adc",
|
|
|
|
"add",
|
|
|
|
"and",
|
|
|
|
"asr",
|
|
|
|
"b",
|
|
|
|
"bic",
|
|
|
|
"bkpt",
|
|
|
|
"bl",
|
|
|
|
"blh",
|
|
|
|
"bx",
|
|
|
|
"cmn",
|
|
|
|
"cmp",
|
|
|
|
"eor",
|
2014-07-10 10:30:59 +00:00
|
|
|
"ldm",
|
2013-11-01 08:47:04 +00:00
|
|
|
"ldr",
|
|
|
|
"lsl",
|
|
|
|
"lsr",
|
|
|
|
"mov",
|
|
|
|
"mul",
|
|
|
|
"mvn",
|
|
|
|
"neg",
|
|
|
|
"orr",
|
|
|
|
"ror",
|
|
|
|
"sbc",
|
2014-07-10 10:30:59 +00:00
|
|
|
"stm",
|
2013-11-01 08:47:04 +00:00
|
|
|
"str",
|
|
|
|
"sub",
|
|
|
|
"swi",
|
|
|
|
"tst"
|
|
|
|
};
|
|
|
|
|
2014-07-10 10:30:59 +00:00
|
|
|
const char* armDirectionStrings[] = {
|
|
|
|
"da",
|
|
|
|
"ia",
|
|
|
|
"db",
|
|
|
|
"da"
|
|
|
|
};
|
|
|
|
|
|
|
|
const char* armAccessTypeStrings[] = {
|
|
|
|
"",
|
|
|
|
"b",
|
|
|
|
"h",
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"sb",
|
|
|
|
"sh",
|
|
|
|
""
|
|
|
|
""
|
|
|
|
};
|
|
|
|
|
2013-11-02 05:29:55 +00:00
|
|
|
int ARMDisassembleThumb(uint16_t opcode, uint32_t pc, char* buffer, int blen) {
|
2014-07-10 10:30:59 +00:00
|
|
|
struct ARMInstructionInfo info;
|
2013-11-02 10:42:46 +00:00
|
|
|
ARMDecodeThumb(opcode, &info);
|
2014-07-10 10:30:59 +00:00
|
|
|
const char* mnemonic = armMnemonicStrings[info.mnemonic];
|
2013-11-01 08:47:04 +00:00
|
|
|
int written;
|
|
|
|
int total = 0;
|
2013-11-02 05:29:55 +00:00
|
|
|
const char* cond = "";
|
|
|
|
if (info.condition != ARM_CONDITION_AL && info.condition < ARM_CONDITION_NV) {
|
|
|
|
cond = _armConditions[info.condition];
|
|
|
|
}
|
2014-07-10 10:30:59 +00:00
|
|
|
const char* flags = "";
|
|
|
|
switch (info.mnemonic) {
|
|
|
|
case ARM_MN_LDM:
|
|
|
|
case ARM_MN_STM:
|
|
|
|
flags = armDirectionStrings[info.memory.direction];
|
|
|
|
break;
|
|
|
|
case ARM_MN_LDR:
|
|
|
|
case ARM_MN_STR:
|
|
|
|
flags = armAccessTypeStrings[info.memory.direction];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, flags, cond);
|
2013-11-01 08:47:04 +00:00
|
|
|
ADVANCE(written);
|
|
|
|
|
|
|
|
switch (info.mnemonic) {
|
2014-07-10 10:30:59 +00:00
|
|
|
case ARM_MN_LDM:
|
|
|
|
case ARM_MN_STM:
|
2013-11-01 08:47:04 +00:00
|
|
|
written = _decodeRegister(info.memory.baseReg, buffer, blen);
|
|
|
|
ADVANCE(written);
|
2014-07-10 10:31:24 +00:00
|
|
|
strncpy(buffer, "!, ", blen - 1);
|
2013-11-01 08:47:04 +00:00
|
|
|
ADVANCE(3);
|
|
|
|
written = _decodeRegisterList(info.op1.immediate, buffer, blen);
|
|
|
|
ADVANCE(written);
|
|
|
|
break;
|
2014-07-10 10:30:59 +00:00
|
|
|
case ARM_MN_B:
|
2013-11-02 05:29:55 +00:00
|
|
|
written = _decodePCRelative(info.op1.immediate, pc, buffer, blen);
|
|
|
|
ADVANCE(written);
|
|
|
|
break;
|
2013-11-01 08:47:04 +00:00
|
|
|
default:
|
2013-11-01 08:57:48 +00:00
|
|
|
if (info.operandFormat & ARM_OPERAND_IMMEDIATE_1) {
|
2014-07-10 10:31:24 +00:00
|
|
|
written = snprintf(buffer, blen - 1, "#%i", info.op1.immediate);
|
2013-11-01 08:57:48 +00:00
|
|
|
ADVANCE(written);
|
|
|
|
} else if (info.operandFormat & ARM_OPERAND_MEMORY_1) {
|
2013-11-02 05:29:55 +00:00
|
|
|
written = _decodeMemory(info.memory, pc, buffer, blen);
|
2013-11-01 08:57:48 +00:00
|
|
|
ADVANCE(written);
|
|
|
|
} else if (info.operandFormat & ARM_OPERAND_REGISTER_1) {
|
|
|
|
written = _decodeRegister(info.op1.reg, buffer, blen);
|
|
|
|
ADVANCE(written);
|
|
|
|
}
|
|
|
|
if (info.operandFormat & ARM_OPERAND_2) {
|
|
|
|
strncpy(buffer, ", ", blen);
|
|
|
|
ADVANCE(2);
|
|
|
|
}
|
|
|
|
if (info.operandFormat & ARM_OPERAND_IMMEDIATE_2) {
|
2014-07-10 10:31:24 +00:00
|
|
|
written = snprintf(buffer, blen - 1, "#%i", info.op2.immediate);
|
2013-11-01 08:57:48 +00:00
|
|
|
ADVANCE(written);
|
|
|
|
} else if (info.operandFormat & ARM_OPERAND_MEMORY_2) {
|
2013-11-02 05:29:55 +00:00
|
|
|
written = _decodeMemory(info.memory, pc, buffer, blen);
|
2013-11-01 08:57:48 +00:00
|
|
|
ADVANCE(written);
|
|
|
|
} else if (info.operandFormat & ARM_OPERAND_REGISTER_2) {
|
|
|
|
written = _decodeRegister(info.op2.reg, buffer, blen);
|
|
|
|
ADVANCE(written);
|
|
|
|
}
|
|
|
|
if (info.operandFormat & ARM_OPERAND_3) {
|
2014-07-10 10:31:24 +00:00
|
|
|
strncpy(buffer, ", ", blen - 1);
|
2013-11-01 08:57:48 +00:00
|
|
|
ADVANCE(2);
|
|
|
|
}
|
|
|
|
if (info.operandFormat & ARM_OPERAND_IMMEDIATE_3) {
|
2014-07-10 10:31:24 +00:00
|
|
|
written = snprintf(buffer, blen - 1, "#%i", info.op3.immediate);
|
2013-11-01 08:57:48 +00:00
|
|
|
ADVANCE(written);
|
|
|
|
} else if (info.operandFormat & ARM_OPERAND_MEMORY_3) {
|
2013-11-02 05:29:55 +00:00
|
|
|
written = _decodeMemory(info.memory, pc, buffer, blen);
|
2013-11-01 08:57:48 +00:00
|
|
|
ADVANCE(written);
|
|
|
|
} else if (info.operandFormat & ARM_OPERAND_REGISTER_3) {
|
|
|
|
written = _decodeRegister(info.op1.reg, buffer, blen);
|
|
|
|
ADVANCE(written);
|
|
|
|
}
|
2013-11-01 08:47:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-07-10 10:31:24 +00:00
|
|
|
buffer[blen - 1] = '\0';
|
2013-11-01 08:47:04 +00:00
|
|
|
return total;
|
|
|
|
}
|