Use new Assembler as disassembler, replacing the old Parser
MODIFY
src/assembler/assembler.h
src/assembler/assembler.h
@@ -67,7 +67,9 @@ public:
return assemble(programLines);
}
- virtual DisassembleResult disassemble(const QByteArray& program, const uint32_t baseAddress = 0) const = 0;
+ virtual DisassembleResult disassemble(const Program& program, const uint32_t baseAddress = 0) const = 0;
+ virtual std::pair<QString, std::optional<Error>> disassemble(const uint32_t word, const ReverseSymbolMap& symbols,
+ const uint32_t baseAddress = 0) const = 0;
virtual std::set<QString> getOpcodes() const = 0;
@@ -266,32 +268,39 @@ public:
return result;
}
- DisassembleResult disassemble(const QByteArray& program, const uint32_t baseAddress = 0) const override {
+ DisassembleResult disassemble(const Program& program, const uint32_t baseAddress = 0) const override {
size_t i = 0;
DisassembleResult res;
- while ((i + sizeof(uint32_t)) <= program.size()) {
- const uint32_t instructionWord = *reinterpret_cast<const uint32_t*>(program.data() + i);
- auto match = m_matcher->matchInstruction(instructionWord);
+ auto& programBits = program.getSection(".text")->data;
+ while ((i + sizeof(uint32_t)) <= programBits.size()) {
+ const uint32_t instructionWord = *reinterpret_cast<const uint32_t*>(programBits.data() + i);
+ auto disres = disassemble(instructionWord, program.symbols, baseAddress + i);
+ if (disres.second) {
+ res.errors.push_back(disres.second.value());
+ }
+ res.program << disres.first;
+ i += sizeof(uint32_t);
+ }
+ return res;
+ }
+
+ std::pair<QString, std::optional<Error>> disassemble(const uint32_t word, const ReverseSymbolMap& symbols,
+ const uint32_t baseAddress = 0) const override {
+ auto match = m_matcher->matchInstruction(word);
try {
auto& error = std::get<Error>(match);
- // Unknown instruction
- res.errors.push_back(error);
- res.program << "unknown instruction";
+ return {"unknown instruction", error};
} catch (const std::bad_variant_access&) {
// Got match, disassemble
- auto tokens = std::get<const Instruction*>(match)->disassemble(instructionWord, baseAddress + i,
- ReverseSymbolMap());
+ auto tokens = std::get<const Instruction*>(match)->disassemble(word, baseAddress, symbols);
try {
auto& error = std::get<Error>(match);
// Error during disassembling
- res.errors.push_back(error);
+ return {"invalid instruction", error};
} catch (const std::bad_variant_access&) {
- res.program << std::get<LineTokens>(tokens).join(' ');
- }
+ return {std::get<LineTokens>(tokens).join(' '), {}};
}
- i += sizeof(uint32_t);
}
- return res;
}
const Matcher& getMatcher() { return *m_matcher; }
@@ -334,8 +343,8 @@ protected:
/** @brief carry
* A symbol should refer to the next following assembler line; whether an instruction or directive.
* The carry is used to carry over symbol definitions from empty lines onto the next valid line.
- * Multiple symbol definitions is checked in this step given that a symbol may loose its source line information
- * if it is a blank symbol (no other information on line).
+ * Multiple symbol definitions is checked in this step given that a symbol may loose its source line
+ * information if it is a blank symbol (no other information on line).
*/
Symbols carry;
for (int i = 0; i < program.size(); i++) {
@@ -507,7 +516,8 @@ protected:
if (symbolMap.count(symbol) == 0) {
if (couldBeExpression(symbol)) {
- // No recorded symbol for the token; our last option is to try and evaluate a possible expression.
+ // No recorded symbol for the token; our last option is to try and evaluate a possible
+ // expression.
auto evaluate_res = evaluate(symbol, &symbolMap);
try {
auto err = std::get<Error>(evaluate_res);
@@ -570,7 +580,8 @@ protected:
}
} catch (const std::bad_variant_access&) {
}
- // Return result (containing either a valid pseudo-instruction expand error or the expanded pseudo instruction
+ // Return result (containing either a valid pseudo-instruction expand error or the expanded pseudo
+ // instruction
return {res};
}

MODIFY
src/assembler/program.h
src/assembler/program.h
@@ -43,7 +43,7 @@ struct ProgramSection {
struct Program {
unsigned long entryPoint = 0;
std::map<QString, ProgramSection> sections;
- std::map<unsigned long, QString> symbols;
+ std::map<uint32_t, QString> symbols;
const ProgramSection* getSection(const QString& name) const {
const auto secIter =
@@ -56,4 +56,5 @@ struct Program {
return &secIter->second;
}
};
+
} // namespace Ripes

MODIFY
src/edittab.cpp
src/edittab.cpp
#include <QPushButton>
#include "assembler/program.h"
-#include "assembler/rv32i_assembler.h"
#include "ccmanager.h"
#include "compilererrordialog.h"
@@ -186,25 +185,13 @@ void EditTab::sourceTypeChanged() {
}
// Notify the source type change to the code editor
- m_ui->codeEditor->setSourceType(m_currentSourceType, m_assembler->getOpcodes());
-}
-
-void EditTab::createAssemblerForCurrentISA() {
- const auto& ISA = ProcessorHandler::get()->currentISA();
-
- if (auto* rvisa = dynamic_cast<const ISAInfo<ISA::RV32I>*>(ISA)) {
- m_assembler = std::make_unique<AssemblerTmp::RV32I_Assembler>(rvisa);
- } else {
- Q_UNREACHABLE();
- }
-
- // Notify the assembler change to the code editor - opcodes might have been added or removed which must be reflected
- // in the syntax highlighter
- m_ui->codeEditor->setSourceType(m_currentSourceType, m_assembler->getOpcodes());
+ m_ui->codeEditor->setSourceType(m_currentSourceType, ProcessorHandler::get()->getAssembler()->getOpcodes());
}
void EditTab::onProcessorChanged() {
- createAssemblerForCurrentISA();
+ // Notify a possible assembler change to the code editor - opcodes might have been added or removed which must be
+ // reflected in the syntax highlighter
+ m_ui->codeEditor->setSourceType(m_currentSourceType, ProcessorHandler::get()->getAssembler()->getOpcodes());
assemble();
}
@@ -226,7 +213,7 @@ void EditTab::sourceCodeChanged() {
}
void EditTab::assemble() {
- auto res = m_assembler->assembleRaw(m_ui->codeEditor->document()->toPlainText());
+ auto res = ProcessorHandler::get()->getAssembler()->assembleRaw(m_ui->codeEditor->document()->toPlainText());
*m_sourceErrors = res.errors;
if (m_sourceErrors->size() == 0) {
m_activeProgram = std::make_shared<Program>(res.program);

MODIFY
src/edittab.h
src/edittab.h
@@ -72,7 +72,6 @@ private:
void assemble();
void compile();
- void createAssemblerForCurrentISA();
void updateProgramViewer();
bool loadFlatBinaryFile(Program& program, QFile& file, unsigned long entryPoint, unsigned long loadAt);
bool loadSourceFile(Program& program, QFile& file);
@@ -87,7 +86,6 @@ private:
QAction* m_symbolNavigatorAction = nullptr;
Ui::EditTab* m_ui = nullptr;
- std::unique_ptr<AssemblerTmp::AssemblerBase> m_assembler;
std::shared_ptr<Program> m_activeProgram;
std::shared_ptr<AssemblerTmp::Errors> m_sourceErrors;

MODIFY
src/gotocombobox.cpp
src/gotocombobox.cpp
@@ -51,7 +51,7 @@ void GoToComboBox::signalFilter(int index) {
void GoToSectionComboBox::addTargets() {
addItem("Address...", QVariant::fromValue<GoToUserData>({GoToFunction::Address, 0}));
- if (auto prog_spt = ProcessorHandler::get()->getProgram().lock()) {
+ if (auto prog_spt = ProcessorHandler::get()->getProgram()) {
for (const auto& section : prog_spt->sections) {
addItem(section.first, QVariant::fromValue<GoToUserData>({GoToFunction::Custom, 0}));
}
@@ -60,7 +60,7 @@ void GoToSectionComboBox::addTargets() {
uint32_t GoToSectionComboBox::addrForIndex(int i) {
const QString& sectionName = itemText(i);
- if (auto prog_spt = ProcessorHandler::get()->getProgram().lock()) {
+ if (auto prog_spt = ProcessorHandler::get()->getProgram()) {
return prog_spt->getSection(sectionName)->address;
} else {
return -1;

MODIFY
src/instructionmodel.h
src/instructionmodel.h
@@ -14,14 +14,14 @@ class Parser;
class Pipeline;
static inline uint32_t indexToAddress(const QModelIndex& index) {
- if (auto prog_spt = ProcessorHandler::get()->getProgram().lock()) {
+ if (auto prog_spt = ProcessorHandler::get()->getProgram()) {
return (index.row() * 4) + prog_spt->getSection(TEXT_SECTION_NAME)->address;
}
return 0;
}
static inline int addressToIndex(uint32_t addr) {
- if (auto prog_spt = ProcessorHandler::get()->getProgram().lock()) {
+ if (auto prog_spt = ProcessorHandler::get()->getProgram()) {
if (prog_spt->getSection(TEXT_SECTION_NAME) != nullptr) {
return (addr - prog_spt->getSection(TEXT_SECTION_NAME)->address) / 4;
}

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
#include "processorhandler.h"
-#include "assembler/program.h"
#include "parser.h"
#include "processorregistry.h"
#include "ripessettings.h"
#include "statusmanager.h"
+#include "assembler/program.h"
+#include "assembler/rv32i_assembler.h"
+
#include "syscall/riscv_syscall.h"
#include <QMessageBox>
@@ -146,6 +148,16 @@ void ProcessorHandler::clearBreakpoints() {
m_breakpoints.clear();
}
+void ProcessorHandler::createAssemblerForCurrentISA() {
+ const auto& ISA = currentISA();
+
+ if (auto* rvisa = dynamic_cast<const ISAInfo<ISA::RV32I>*>(ISA)) {
+ m_currentAssembler = std::make_shared<AssemblerTmp::RV32I_Assembler>(rvisa);
+ } else {
+ Q_UNREACHABLE();
+ }
+}
+
void ProcessorHandler::selectProcessor(const ProcessorID& id, const QStringList& extensions,
RegisterInitialization setup) {
m_program = nullptr;
@@ -176,6 +188,7 @@ void ProcessorHandler::selectProcessor(const ProcessorID& id, const QStringList&
}
m_currentProcessor->verifyAndInitialize();
+ createAssemblerForCurrentISA();
emit processorChanged();
}

MODIFY
src/processorhandler.h
src/processorhandler.h
#include <QFutureWatcher>
#include <QObject>
+#include "assembler/assembler.h"
#include "assembler/program.h"
#include "processorregistry.h"
#include "syscall/ripes_syscall.h"
@@ -30,8 +31,9 @@ public:
vsrtl::core::RipesProcessor* getProcessorNonConst() { return m_currentProcessor.get(); }
const vsrtl::core::RipesProcessor* getProcessor() { return m_currentProcessor.get(); }
+ const std::shared_ptr<AssemblerTmp::AssemblerBase> getAssembler() { return m_currentAssembler; }
const ProcessorID& getID() const { return m_currentID; }
- std::weak_ptr<const Program> getProgram() const { return m_program; }
+ std::shared_ptr<const Program> getProgram() const { return m_program; }
const ISAInfoBase* currentISA() const { return m_currentProcessor->implementsISA(); }
const SyscallManager& getSyscallManager() const { return *m_syscallManager; }
@@ -178,6 +180,7 @@ private slots:
void asyncTrap();
private:
+ void createAssemblerForCurrentISA();
void setStopRunFlag();
ProcessorHandler();
@@ -185,6 +188,7 @@ private:
ProcessorID m_currentID;
std::unique_ptr<vsrtl::core::RipesProcessor> m_currentProcessor;
std::unique_ptr<SyscallManager> m_syscallManager;
+ std::shared_ptr<AssemblerTmp::AssemblerBase> m_currentAssembler;
/**
* @brief m_vsrtlWidget

MODIFY
src/programviewer.cpp
src/programviewer.cpp
@@ -47,9 +47,8 @@ void ProgramViewer::resizeEvent(QResizeEvent* e) {
void ProgramViewer::updateProgram(bool binary) {
m_labelAddrOffsetMap.clear();
- const QString text =
- binary ? Parser::getParser()->binarize(ProcessorHandler::get()->getProgram(), m_labelAddrOffsetMap)
- : Parser::getParser()->disassemble(ProcessorHandler::get()->getProgram(), m_labelAddrOffsetMap);
+ const QString text = binary ? AssemblerTmp::binobjdump(ProcessorHandler::get()->getProgram(), m_labelAddrOffsetMap)
+ : AssemblerTmp::objdump(ProcessorHandler::get()->getProgram(), m_labelAddrOffsetMap);
// A memory occurs within QPlainTextEdit::clear if extra selections has been set. This is most possibly a bug,
// but seems to be fixed if we manually clear the selections before we clear (and add new text) to the text

MODIFY
src/programviewer.h
src/programviewer.h
#include <QScrollBar>
#include <QTimer>
+#include "assembler/objdump.h"
+#include "assembler/program.h"
#include "parser.h"
#include "processorhandler.h"
-#include "assembler/program.h"
namespace Ripes {
@@ -31,7 +32,7 @@ public:
QTextBlock blockForAddress(unsigned long) const;
void setCenterAddress(const long address);
- const AddrOffsetMap& addressOffsetMap() const { return m_labelAddrOffsetMap; }
+ const AssemblerTmp::AddrOffsetMap& addressOffsetMap() const { return m_labelAddrOffsetMap; }
///
/// \brief updateProgram
@@ -77,7 +78,7 @@ private:
* from 0) which does >not< correspond with an address. The value of the key corresponds to the total sum of
* non-address lines encountered up to and including the given label.
*/
- AddrOffsetMap m_labelAddrOffsetMap;
+ AssemblerTmp::AddrOffsetMap m_labelAddrOffsetMap;
std::map<QTextBlock, QStringList> m_highlightedBlocksText;
};

MODIFY
src/stagetablemodel.cpp
src/stagetablemodel.cpp
namespace Ripes {
static inline uint32_t indexToAddress(unsigned index) {
- if (auto spt = ProcessorHandler::get()->getProgram().lock()) {
+ if (auto spt = ProcessorHandler::get()->getProgram()) {
return (index * ProcessorHandler::get()->currentISA()->bytes()) + spt->getSection(TEXT_SECTION_NAME)->address;
}
return 0;

MODIFY
src/symbolnavigator.cpp
src/symbolnavigator.cpp
namespace Ripes {
-SymbolNavigator::SymbolNavigator(const AddrOffsetMap& symbolmap, QWidget* parent)
+SymbolNavigator::SymbolNavigator(const AssemblerTmp::AddrOffsetMap& symbolmap, QWidget* parent)
: QDialog(parent), m_ui(new Ui::SymbolNavigator) {
m_ui->setupUi(this);

MODIFY
src/symbolnavigator.h
src/symbolnavigator.h
#include <QDialog>
+#include "assembler/objdump.h"
#include "parser.h"
namespace Ripes {
@@ -14,7 +15,7 @@ class SymbolNavigator : public QDialog {
Q_OBJECT
public:
- SymbolNavigator(const AddrOffsetMap& symbolmap, QWidget* parent = nullptr);
+ SymbolNavigator(const AssemblerTmp::AddrOffsetMap& symbolmap, QWidget* parent = nullptr);
~SymbolNavigator();
long getSelectedSymbolAddress() const;

Use new Assembler as disassembler, replacing the old Parser