[Assembler] Implement rudimentary disassembling
MODIFY
src/assembler/assembler.h
src/assembler/assembler.h
@@ -48,12 +48,12 @@ class AssemblerBase {
using PseudoInstrVec = std::vector<std::shared_ptr<PseudoInstr>>;
public:
- Result assemble(const QString& program) const {
+ AssembleResult assemble(const QString& program) const {
const auto programLines = program.split(QRegExp("[\r\n]"));
return assemble(programLines);
}
- Result assemble(const QStringList& programLines) const {
- Result result;
+ AssembleResult assemble(const QStringList& programLines) const {
+ AssembleResult result;
// Tokenize each source line and separate symbol from remainder of tokens
runPass(tokenizedLines, Program, pass0, programLines);
@@ -70,7 +70,35 @@ public:
result.program = program;
return result;
}
- QString disassemble(const QByteArray& program) const;
+ DisassembleResult disassemble(const QByteArray& program, const uint32_t baseAddress = 0) const {
+ size_t i = 0;
+ if (program.size() % sizeof(uint32_t) != 0) {
+ throw std::runtime_error("Program instructions unaligned with instruction size");
+ }
+ DisassembleResult res;
+ while (i < program.size()) {
+ const uint32_t instructionWord = *reinterpret_cast<const uint32_t*>(program.data() + i);
+ auto match = m_matcher.matchInstruction(instructionWord);
+ try {
+ auto& error = std::get<Error>(match);
+ // Unknown instruction
+ res.errors.push_back(error);
+ } catch (const std::bad_variant_access&) {
+ // Got match, disassemble
+ auto tokens = std::get<const Instruction<ISA>*>(match)->disassemble(instructionWord, baseAddress + i,
+ ReverseSymbolMap());
+ try {
+ auto& error = std::get<Error>(match);
+ // Error during disassembling
+ res.errors.push_back(error);
+ } catch (const std::bad_variant_access&) {
+ res.program << std::get<LineTokens>(tokens).join(' ');
+ }
+ }
+ i += sizeof(uint32_t);
+ }
+ return res;
+ }
const Matcher<ISA>& getMatcher() { return m_matcher; }

MODIFY
src/assembler/assembler_defines.h
src/assembler/assembler_defines.h
@@ -37,11 +37,16 @@ using NoPassResult = std::monostate;
* @brief The Result struct
* An assembly result is determined to be valid iff errors is empty.
*/
-struct Result {
+struct AssembleResult {
Errors errors;
QByteArray program;
};
+struct DisassembleResult {
+ Errors errors;
+ QStringList program;
+};
+
} // namespace AssemblerTmp
} // namespace Ripes

MODIFY
src/assembler/instruction.h
src/assembler/instruction.h
@@ -43,7 +43,7 @@ struct Field {
virtual std::optional<AssemblerTmp::Error> apply(const AssemblerTmp::TokenizedSrcLine& line,
uint32_t& instruction) const = 0;
virtual std::optional<AssemblerTmp::Error> decode(const uint32_t instruction, const uint32_t address,
- const ReverseSymbolMap* symbolMap,
+ const ReverseSymbolMap& symbolMap,
AssemblerTmp::LineTokens& line) const = 0;
};
@@ -75,7 +75,7 @@ struct Opcode : public Field {
instruction |= opPart.range.apply(opPart.value);
}
}
- std::optional<AssemblerTmp::Error> decode(const uint32_t, const uint32_t, const ReverseSymbolMap*,
+ std::optional<AssemblerTmp::Error> decode(const uint32_t, const uint32_t, const ReverseSymbolMap&,
AssemblerTmp::LineTokens& line) const override {
line.push_back(name);
return {};
@@ -107,7 +107,7 @@ struct Reg : public Field {
instruction |= m_range.apply(reg);
}
std::optional<AssemblerTmp::Error> decode(const uint32_t instruction, const uint32_t address,
- const ReverseSymbolMap* symbolMap,
+ const ReverseSymbolMap& symbolMap,
AssemblerTmp::LineTokens& line) const override {
const unsigned regNumber = m_range.decode(instruction);
const QString registerName = ISA::instance()->regName(regNumber);
@@ -174,7 +174,7 @@ struct Imm : public Field {
return {};
}
std::optional<AssemblerTmp::Error> decode(const uint32_t instruction, const uint32_t address,
- const ReverseSymbolMap* symbolMap,
+ const ReverseSymbolMap& symbolMap,
AssemblerTmp::LineTokens& line) const override {
uint32_t reconstructed = 0;
for (const auto& part : parts) {
@@ -188,11 +188,11 @@ struct Imm : public Field {
line.push_back("0x" + QString::number(reconstructed, 16));
}
- if (symbolType != SymbolType::None && symbolMap != nullptr) {
+ if (symbolType != SymbolType::None) {
const int value = signextend<int32_t>(reconstructed, width);
const uint32_t symbolAddress = value + (symbolType == SymbolType::Absolute ? 0 : address);
- if (symbolMap->count(symbolAddress)) {
- line.push_back("<" + symbolMap->at(symbolAddress) + ">");
+ if (symbolMap.count(symbolAddress)) {
+ line.push_back("<" + symbolMap.at(symbolAddress) + ">");
}
}
@@ -223,7 +223,7 @@ public:
return AssembleRes(instruction);
};
m_disassembler = [](const Instruction& _this, const uint32_t instruction, const uint32_t address,
- const ReverseSymbolMap* symbolMap) {
+ const ReverseSymbolMap& symbolMap) {
AssemblerTmp::LineTokens line;
_this.m_opcode.decode(instruction, address, symbolMap, line);
for (const auto& field : _this.m_fields) {
@@ -246,7 +246,7 @@ public:
return m_assembler(*this, line);
}
DisassembleRes disassemble(const uint32_t instruction, const uint32_t address,
- const ReverseSymbolMap* symbolMap) const {
+ const ReverseSymbolMap& symbolMap) const {
return m_disassembler(*this, instruction, address, symbolMap);
}
@@ -260,7 +260,7 @@ public:
private:
std::function<AssembleRes(const Instruction&, const AssemblerTmp::TokenizedSrcLine&)> m_assembler;
- std::function<DisassembleRes(const Instruction&, const uint32_t, const uint32_t, const ReverseSymbolMap*)>
+ std::function<DisassembleRes(const Instruction&, const uint32_t, const uint32_t, const ReverseSymbolMap&)>
m_disassembler;
const Opcode m_opcode;

MODIFY
test/tst_assembler.cpp
test/tst_assembler.cpp
@@ -34,6 +34,7 @@ void tst_Assembler::tst_simpleprogram() {
res.errors.print();
QFAIL("Errors during assembly");
}
+ auto disres = assembler.disassemble(res.program);
return;
}
@@ -104,7 +105,7 @@ void tst_Assembler::tst_matcher() {
QFAIL(error.toStdString().c_str());
}
- auto disRes = matchInstr->disassemble(iter.second, 0, nullptr);
+ auto disRes = matchInstr->disassemble(iter.second, 0, {});
try {
auto& error = std::get<Error>(disRes);
QFAIL(error.second.toStdString().c_str());

[Assembler] Implement rudimentary disassembling