diff --git a/InstructionSets/ARM/Disassembler.hpp b/InstructionSets/ARM/Disassembler.hpp index 273bc5a38..21e668728 100644 --- a/InstructionSets/ARM/Disassembler.hpp +++ b/InstructionSets/ARM/Disassembler.hpp @@ -24,18 +24,23 @@ struct Operand { // TODO: encode shifting operator std::string() const { - return ""; + switch(type) { + default: return ""; + case Type::Register: return std::string("r") + std::to_string(value); + } } }; struct Instruction { - Condition condition; + Condition condition = Condition::AL; enum class Operation { AND, EOR, SUB, RSB, ADD, ADC, SBC, RSC, TST, TEQ, CMP, CMN, ORR, MOV, BIC, MVN, + LDR, STR, + B, BL, SWI, @@ -44,6 +49,7 @@ struct Instruction { } operation = Operation::Undefined; Operand destination, operand1, operand2; + bool sets_flags = false; std::string to_string(uint32_t address) const { std::ostringstream result; @@ -77,12 +83,42 @@ struct Instruction { case Operation::MOV: result << "mov"; break; case Operation::BIC: result << "bic"; break; case Operation::MVN: result << "mvn"; break; + + case Operation::LDR: result << "ldr"; break; + case Operation::STR: result << "str"; break; } - // If this is a branch, append the target and complete. + // Append the sets-flags modifier if applicable. + if(sets_flags) result << 's'; + + // Possibly a condition code. + switch(condition) { + case Condition::EQ: result << "eq"; break; + case Condition::NE: result << "ne"; break; + case Condition::CS: result << "cs"; break; + case Condition::CC: result << "cc"; break; + case Condition::MI: result << "mi"; break; + case Condition::PL: result << "pl"; break; + case Condition::VS: result << "vs"; break; + case Condition::VC: result << "vc"; break; + case Condition::HI: result << "hi"; break; + case Condition::LS: result << "ls"; break; + case Condition::GE: result << "ge"; break; + case Condition::LT: result << "lt"; break; + case Condition::GT: result << "gt"; break; + case Condition::LE: result << "le"; break; + default: break; + } + + // If this is a branch, append the target. if(operation == Operation::B || operation == Operation::BL) { result << " 0x" << std::hex << ((address + 8 + operand1.value) & 0x3fffffc); - return result.str(); + } + + if(operation == Operation::LDR || operation == Operation::STR) { + result << ' ' << static_cast(destination); + result << ", [" << static_cast(operand1) << "]"; + // TODO: learn how ARM shifts/etc are normally represented. } return result.str(); @@ -101,9 +137,29 @@ struct Disassembler { return true; } - template void perform(DataProcessing) {} + template void perform(DataProcessing fields) { + constexpr DataProcessingFlags flags(f); + + // + instruction_.operand1.type = Operand::Type::Register; + instruction_.operand1.value = fields.operand1(); + + instruction_.sets_flags = flags.set_condition_codes(); + } + template void perform(Multiply) {} - template void perform(SingleDataTransfer) {} + template void perform(SingleDataTransfer fields) { + constexpr SingleDataTransferFlags flags(f); + instruction_.operation = + (flags.operation() == SingleDataTransferFlags::Operation::STR) ? + Instruction::Operation::STR : Instruction::Operation::LDR; + + instruction_.destination.type = Operand::Type::Register; + instruction_.destination.value = fields.destination(); + + instruction_.operand1.type = Operand::Type::Register; + instruction_.operand1.value = fields.base(); + } template void perform(BlockDataTransfer) {} template void perform(Branch fields) { constexpr BranchFlags flags(f);