diff --git a/CHANGES b/CHANGES index 479578327..e6e187062 100644 --- a/CHANGES +++ b/CHANGES @@ -78,6 +78,7 @@ Misc: - GBA: Improve accuracy of event timing - Debugger: Clean up GDB stub network interfacing - Debugger: Simplify debugger state machine to play nicer with the GBA thread loop + - Debugger: Merge Thumb BL instructions when disassembling 0.1.0: (2014-12-13) - Initial release diff --git a/src/arm/decoder-thumb.c b/src/arm/decoder-thumb.c index edb37a814..fb6aed9f5 100644 --- a/src/arm/decoder-thumb.c +++ b/src/arm/decoder-thumb.c @@ -290,14 +290,21 @@ DEFINE_THUMB_DECODER(B, B, info->operandFormat = ARM_OPERAND_IMMEDIATE_1; info->branchType = ARM_BRANCH;) -DEFINE_THUMB_DECODER(BL1, BLH, +DEFINE_THUMB_DECODER(BL1, BL, int16_t immediate = (opcode & 0x07FF) << 5; - info->op1.immediate = (((int32_t) immediate) << 7); - info->operandFormat = ARM_OPERAND_IMMEDIATE_1;) + info->op1.reg = ARM_LR; + info->op2.reg = ARM_PC; + info->op3.immediate = (((int32_t) immediate) << 7); + info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2 | ARM_OPERAND_AFFECTED_2 | + ARM_OPERAND_IMMEDIATE_3;) DEFINE_THUMB_DECODER(BL2, BL, - info->op1.immediate = (opcode & 0x07FF) << 1; - info->operandFormat = ARM_OPERAND_IMMEDIATE_1; + info->op1.reg = ARM_PC; + info->op2.reg = ARM_LR; + info->op3.immediate = (opcode & 0x07FF) << 1; + info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 | + ARM_OPERAND_REGISTER_2 | ARM_OPERAND_IMMEDIATE_3; info->branchType = ARM_BRANCH_LINKED;) DEFINE_THUMB_DECODER(BX, BX, @@ -332,3 +339,33 @@ void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) { ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6]; decoder(opcode, info); } + +bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, struct ARMInstructionInfo* out) { + if (info1->execMode != MODE_THUMB || info1->mnemonic != ARM_MN_BL) { + return false; + } + if (info2->execMode != MODE_THUMB || info2->mnemonic != ARM_MN_BL) { + return false; + } + if (info1->op1.reg != ARM_LR || info1->op2.reg != ARM_PC) { + return false; + } + if (info2->op1.reg != ARM_PC || info2->op2.reg != ARM_LR) { + return false; + } + out->op1.immediate = info1->op3.immediate | info2->op3.immediate; + out->operandFormat = ARM_OPERAND_IMMEDIATE_1; + out->execMode = MODE_THUMB; + out->mnemonic = ARM_MN_BL; + out->branchType = ARM_BRANCH_LINKED; + out->traps = 0; + out->affectsCPSR = 0; + out->condition = ARM_CONDITION_AL; + out->sDataCycles = 0; + out->nDataCycles = 0; + out->sInstructionCycles = 2; + out->nInstructionCycles = 0; + out->iCycles = 0; + out->cCycles = 0; + return true; +} diff --git a/src/arm/decoder.c b/src/arm/decoder.c index a5bece314..94974fcec 100644 --- a/src/arm/decoder.c +++ b/src/arm/decoder.c @@ -223,7 +223,6 @@ static const char* _armMnemonicStrings[] = { "bic", "bkpt", "bl", - "blh", "bx", "cmn", "cmp", @@ -355,8 +354,11 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i } break; case ARM_MN_B: - written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); - ADVANCE(written); + case ARM_MN_BL: + if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { + written = _decodePCRelative(info->op1.immediate, pc, buffer, blen); + ADVANCE(written); + } break; default: if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { diff --git a/src/arm/decoder.h b/src/arm/decoder.h index abb30b004..75f30e33c 100644 --- a/src/arm/decoder.h +++ b/src/arm/decoder.h @@ -138,7 +138,6 @@ enum ARMMnemonic { ARM_MN_BIC, ARM_MN_BKPT, ARM_MN_BL, - ARM_MN_BLH, ARM_MN_BX, ARM_MN_CMN, ARM_MN_CMP, @@ -203,6 +202,7 @@ struct ARMInstructionInfo { void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info); void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info); +bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, struct ARMInstructionInfo* out); int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen); #endif diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index 6f282b9e8..f6ac301f7 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -43,7 +43,7 @@ static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*); static void _breakIntoDefault(int signal); static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode); -static void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode); +static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode); static struct CLIDebuggerCommandSummary _debuggerCommands[] = { { "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" }, @@ -172,8 +172,7 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector int i; for (i = 0; i < size; ++i) { - _printLine(debugger, address, mode); - address += wordSize; + address += _printLine(debugger, address, mode);; } } @@ -238,7 +237,7 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) } } -static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { +static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { char disassembly[48]; struct ARMInstructionInfo info; printf("%08X: ", address); @@ -247,11 +246,23 @@ static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, en ARMDecodeARM(instruction, &info); ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); printf("%08X\t%s\n", instruction, disassembly); + return WORD_SIZE_ARM; } else { + struct ARMInstructionInfo info2; + struct ARMInstructionInfo combined; uint16_t instruction = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0); + uint16_t instruction2 = debugger->d.cpu->memory.load16(debugger->d.cpu, address + WORD_SIZE_THUMB, 0); ARMDecodeThumb(instruction, &info); - ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); - printf("%04X\t%s\n", instruction, disassembly); + ARMDecodeThumb(instruction2, &info2); + if (ARMDecodeThumbCombine(&info, &info2, &combined)) { + ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + printf("%04X %04X\t%s\n", instruction, instruction2, disassembly); + return WORD_SIZE_THUMB * 2; + } else { + ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + printf("%04X \t%s\n", instruction, disassembly); + return WORD_SIZE_THUMB; + } } }