diff --git a/src/arm/decoder-thumb.c b/src/arm/decoder-thumb.c index b33c03728..2f4343043 100644 --- a/src/arm/decoder-thumb.c +++ b/src/arm/decoder-thumb.c @@ -221,8 +221,9 @@ DEFINE_LOAD_STORE_MULTIPLE_THUMB(STMIA) #define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \ DEFINE_THUMB_DECODER(B ## COND, B, \ int8_t immediate = opcode; \ - info->op1.immediate += immediate << 1; \ + info->op1.immediate = immediate << 1; \ info->branches = 1; \ + info->condition = ARM_CONDITION_ ## COND; \ info->operandFormat = ARM_OPERAND_IMMEDIATE_1;) DEFINE_CONDITIONAL_BRANCH_THUMB(EQ) @@ -300,6 +301,7 @@ void ARMDecodeThumb(uint16_t opcode, struct ThumbInstructionInfo* info) { info->traps = 0; info->accessesSpecialRegisters = 0; info->affectsCPSR = 0; + info->condition = ARM_CONDITION_AL; ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6]; decoder(opcode, info); } @@ -380,7 +382,11 @@ static int _decodeRegisterList(int list, char* buffer, int blen) { return total; } -static int _decodeMemory(struct ARMMemoryAccess memory, char* buffer, int blen) { +static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) { + return snprintf(buffer, blen, "$%08X", address + pc); +} + +static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) { if (blen <= 0) { return 0; } @@ -389,18 +395,23 @@ static int _decodeMemory(struct ARMMemoryAccess memory, char* buffer, int blen) ADVANCE(1); int written; if (memory.format & ARM_MEMORY_REGISTER_BASE) { - written = _decodeRegister(memory.baseReg, buffer, blen); - ADVANCE(written); - if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) { - strncpy(buffer, ", ", blen); - ADVANCE(2); + if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { + written = _decodePCRelative(memory.offset.immediate, pc, buffer, blen); + ADVANCE(written); + } else { + written = _decodeRegister(memory.baseReg, buffer, blen); + ADVANCE(written); + if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) { + strncpy(buffer, ", ", blen); + ADVANCE(2); + } } } if (memory.format & ARM_MEMORY_POST_INCREMENT) { strncpy(buffer, "], ", blen); ADVANCE(3); } - if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { + if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) { if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { written = snprintf(buffer, blen, "#-%i", memory.offset.immediate); ADVANCE(written); @@ -429,6 +440,25 @@ static int _decodeMemory(struct ARMMemoryAccess memory, char* buffer, int blen) return total; } +static const char* _armConditions[] = { + "eq", + "ne", + "cs", + "cc", + "mi", + "pl", + "vs", + "vc", + "hi", + "ls", + "ge", + "lt", + "gt", + "le", + "al", + "nv" +}; + static const char* _thumbMnemonicStrings[] = { "ill", "adc", @@ -470,13 +500,17 @@ static const char* _thumbMnemonicStrings[] = { "tst" }; -int ARMDisassembleThumb(uint16_t opcode, char* buffer, int blen) { +int ARMDisassembleThumb(uint16_t opcode, uint32_t pc, char* buffer, int blen) { struct ThumbInstructionInfo info; ARMDecodeThumb(opcode, &info); const char* mnemonic = _thumbMnemonicStrings[info.mnemonic]; int written; int total = 0; - written = snprintf(buffer, blen, "%s ", mnemonic); + const char* cond = ""; + if (info.condition != ARM_CONDITION_AL && info.condition < ARM_CONDITION_NV) { + cond = _armConditions[info.condition]; + } + written = snprintf(buffer, blen, "%s%s ", mnemonic, cond); ADVANCE(written); switch (info.mnemonic) { @@ -492,12 +526,16 @@ int ARMDisassembleThumb(uint16_t opcode, char* buffer, int blen) { written = _decodeRegisterList(info.op1.immediate, buffer, blen); ADVANCE(written); break; + case THUMB_MN_B: + written = _decodePCRelative(info.op1.immediate, pc, buffer, blen); + ADVANCE(written); + break; default: if (info.operandFormat & ARM_OPERAND_IMMEDIATE_1) { written = snprintf(buffer, blen, "#%i", info.op1.immediate); ADVANCE(written); } else if (info.operandFormat & ARM_OPERAND_MEMORY_1) { - written = _decodeMemory(info.memory, buffer, blen); + written = _decodeMemory(info.memory, pc, buffer, blen); ADVANCE(written); } else if (info.operandFormat & ARM_OPERAND_REGISTER_1) { written = _decodeRegister(info.op1.reg, buffer, blen); @@ -511,7 +549,7 @@ int ARMDisassembleThumb(uint16_t opcode, char* buffer, int blen) { written = snprintf(buffer, blen, "#%i", info.op2.immediate); ADVANCE(written); } else if (info.operandFormat & ARM_OPERAND_MEMORY_2) { - written = _decodeMemory(info.memory, buffer, blen); + written = _decodeMemory(info.memory, pc, buffer, blen); ADVANCE(written); } else if (info.operandFormat & ARM_OPERAND_REGISTER_2) { written = _decodeRegister(info.op2.reg, buffer, blen); @@ -525,7 +563,7 @@ int ARMDisassembleThumb(uint16_t opcode, char* buffer, int blen) { written = snprintf(buffer, blen, "#%i", info.op3.immediate); ADVANCE(written); } else if (info.operandFormat & ARM_OPERAND_MEMORY_3) { - written = _decodeMemory(info.memory, buffer, blen); + written = _decodeMemory(info.memory, pc, buffer, blen); ADVANCE(written); } else if (info.operandFormat & ARM_OPERAND_REGISTER_3) { written = _decodeRegister(info.op1.reg, buffer, blen); diff --git a/src/arm/decoder.h b/src/arm/decoder.h index e06454726..ce1652d71 100644 --- a/src/arm/decoder.h +++ b/src/arm/decoder.h @@ -47,6 +47,25 @@ enum ARMMemoryFormat { ARM_MEMORY_OFFSET_SUBTRACT = 0x0040 }; +enum ARMCondition { + ARM_CONDITION_EQ = 0x0, + ARM_CONDITION_NE = 0x1, + ARM_CONDITION_CS = 0x2, + ARM_CONDITION_CC = 0x3, + ARM_CONDITION_MI = 0x4, + ARM_CONDITION_PL = 0x5, + ARM_CONDITION_VS = 0x6, + ARM_CONDITION_VC = 0x7, + ARM_CONDITION_HI = 0x8, + ARM_CONDITION_LS = 0x9, + ARM_CONDITION_GE = 0xA, + ARM_CONDITION_LT = 0xB, + ARM_CONDITION_GT = 0xC, + ARM_CONDITION_LE = 0xD, + ARM_CONDITION_AL = 0xE, + ARM_CONDITION_NV = 0xF +}; + union ARMOperand { struct { uint8_t reg; @@ -120,9 +139,10 @@ struct ThumbInstructionInfo { int traps; int accessesSpecialRegisters; int affectsCPSR; + int condition; }; void ARMDecodeThumb(uint16_t opcode, struct ThumbInstructionInfo* info); -int ARMDisassembleThumb(uint16_t opcode, char* buffer, int blen); +int ARMDisassembleThumb(uint16_t opcode, uint32_t pc, char* buffer, int blen); #endif diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index 18d7d4836..a3f68c9b8 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -144,7 +144,7 @@ static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, en printf("%08X\n", instruction); } else { uint16_t instruction = debugger->d.cpu->memory->loadU16(debugger->d.cpu->memory, address, 0); - ARMDisassembleThumb(instruction, disassembly, sizeof(disassembly)); + ARMDisassembleThumb(instruction, debugger->d.cpu->gprs[ARM_PC] + WORD_SIZE_THUMB, disassembly, sizeof(disassembly)); printf("%04X: %s\n", instruction, disassembly); } }