Cache disassembled version of program
ADD
src/assembler/program.cpp
+#include "program.h"
+
+#include "processorhandler.h"
+
+namespace Ripes {
+
+const ProgramSection* Program::getSection(const QString& name) const {
+ const auto secIter =
+ std::find_if(sections.begin(), sections.end(), [=](const auto& section) { return section.first == name; });
+
+ if (secIter == sections.end()) {
+ return nullptr;
+ }
+
+ return &secIter->second;
+}
+
+const std::map<VInt, QString>& Program::getDisassembled() const {
+ const auto* textSection = getSection(TEXT_SECTION_NAME);
+ if (!textSection || textSection->data.size() == 0) {
+ disassembled.clear();
+ return disassembled;
+ }
+ if (disassembled.size() == 0) {
+ // Initialize caching
+ const unsigned instrBytes = ProcessorHandler::currentISA()->instrBytes();
+ const VInt textSectionBaseAddr = textSection->address;
+ for (AInt addr = 0; addr < (AInt)ProcessorHandler::getCurrentProgramSize();) {
+ const VInt disassembleAddr = addr + textSectionBaseAddr;
+ auto disRes = ProcessorHandler::getAssembler()->disassemble(
+ ProcessorHandler::getMemory().readMem(disassembleAddr, instrBytes),
+ ProcessorHandler::getProgram()->symbols, disassembleAddr);
+ // todo(mortbopet): shouldn't we do something about the possibility of the disassembling returning an error?
+ const VInt realAddr = textSectionBaseAddr + addr;
+ disassembled[realAddr] = disRes.repr;
+ addr += disRes.bytesDisassembled;
+ }
+ }
+ return disassembled;
+}
+
+} // namespace Ripes

MODIFY
src/assembler/program.h
src/assembler/program.h
@@ -65,21 +65,25 @@ struct ProgramSection {
* Wrapper around a program to be loaded into simulator memory. Text section shall contain the instructions of the
* program. Others section may contain all other program sections (.bss, .data, ...)
*/
-struct Program {
+class Program {
+public:
AInt entryPoint = 0;
std::map<QString, ProgramSection> sections;
ReverseSymbolMap symbols;
- const ProgramSection* getSection(const QString& name) const {
- const auto secIter =
- std::find_if(sections.begin(), sections.end(), [=](const auto& section) { return section.first == name; });
+ /// Returns the program section corresponding to the provided name. Return nullptr if no section was found with the
+ /// given name.
+ const ProgramSection* getSection(const QString& name) const;
- if (secIter == sections.end()) {
- return nullptr;
- }
+ /// Returns the disassembled version of this program. The result is an ordered map of
+ /// [instruction address : disassembled instruction]
+ const std::map<VInt, QString>& getDisassembled() const;
- return &secIter->second;
- }
+private:
+ /// A caching of the disassembled version of this program. An ordered map of
+ /// [instruction address : disassembled instruction] with the iterator index equating to the line # of a given
+ /// instruction if the disassembly is printed.
+ mutable std::map<VInt, QString> disassembled;
};
} // namespace Ripes

MODIFY
src/instructionmodel.cpp
src/instructionmodel.cpp
namespace Ripes {
AInt InstructionModel::indexToAddress(const QModelIndex& index) const {
- if (auto prog_spt = ProcessorHandler::getProgram()) {
- return m_indexToAddress.at(index.row()) + prog_spt->getSection(TEXT_SECTION_NAME)->address;
+ if (m_program) {
+ auto& disassembleRes = m_program->getDisassembled();
+ if (disassembleRes.size() < static_cast<unsigned>(index.row()))
+ return -1;
+ /// Since disassembly results are ordered from low to high addresses, we take the row index'th disassembled
+ /// instruction, and return its address.
+ auto it = disassembleRes.begin();
+ std::advance(it, index.row());
+ return it->first;
}
return 0;
}
int InstructionModel::addressToRow(AInt addr) const {
- if (auto prog_spt = ProcessorHandler::getProgram()) {
- const AInt addrC = addr - prog_spt->getSection(TEXT_SECTION_NAME)->address;
-
- for (unsigned int rowC = 0; rowC < m_indexToAddress.size(); rowC++) {
- if (m_indexToAddress.at(rowC) >= addrC) {
- return rowC;
- }
- }
+ if (m_program) {
+ const AInt addrAdjusted = addr - m_program->getSection(TEXT_SECTION_NAME)->address;
+ auto& disassembleRes = m_program->getDisassembled();
+ auto it = disassembleRes.lower_bound(addrAdjusted);
+ if (it == disassembleRes.end())
+ return 0;
+ return std::distance(disassembleRes.begin(), it);
}
return 0;
}
@@ -36,6 +42,9 @@ InstructionModel::InstructionModel(QObject* parent) : QAbstractTableModel(parent
}
void InstructionModel::onProcessorReset() {
+ // Update handle to program
+ m_program = ProcessorHandler::getProgram();
+
updateRowCount();
beginResetModel();
endResetModel();
@@ -47,21 +56,11 @@ int InstructionModel::columnCount(const QModelIndex&) const {
}
void InstructionModel::updateRowCount() {
- m_indexToAddress.clear();
- m_indexToAddress[0] = 0;
+ if (m_program) {
+ auto& disassembleRes = m_program->getDisassembled();
+ m_rowCount = disassembleRes.size();
+ } else
m_rowCount = 0;
- const unsigned instrBytes = ProcessorHandler::currentISA()->instrBytes();
- if (auto prog_spt = ProcessorHandler::getProgram()) {
- for (AInt addr = 0; addr < (AInt)ProcessorHandler::getCurrentProgramSize();) {
- auto disRes = ProcessorHandler::getAssembler()->disassemble(
- ProcessorHandler::getMemory().readMem(addr + prog_spt->getSection(TEXT_SECTION_NAME)->address,
- instrBytes),
- ProcessorHandler::getProgram()->symbols, addr + prog_spt->getSection(TEXT_SECTION_NAME)->address);
- addr += disRes.bytesDisassembled;
- m_rowCount++;
- m_indexToAddress[m_rowCount] = addr;
- }
- }
}
int InstructionModel::rowCount(const QModelIndex&) const {
@@ -91,7 +90,7 @@ void InstructionModel::updateStageInfo() {
emit dataChanged(newIdx, newIdx, {Qt::DisplayRole});
}
if (firstStageChanged) {
- emit firstStageInstrChanged(m_stageInfos.at(0).pc);
+ emit firstStageInstrChanged(addressToRow(m_stageInfos.at(0).pc));
firstStageChanged = false;
}
}
@@ -148,7 +147,14 @@ QVariant InstructionModel::stageData(AInt addr) const {
}
QVariant InstructionModel::instructionData(AInt addr) const {
- return ProcessorHandler::disassembleInstr(addr);
+ if (m_program) {
+ auto& disres = m_program->getDisassembled();
+ auto it = disres.find(addr);
+ if (it == disres.end())
+ return QVariant();
+ return it->second;
+ }
+ return QVariant();
}
QVariant InstructionModel::data(const QModelIndex& index, int role) const {

MODIFY
src/instructionmodel.h
src/instructionmodel.h
#include <QAbstractTableModel>
#include <QColor>
+#include "assembler/program.h"
#include "processors/interface/ripesprocessor.h"
namespace Ripes {
@@ -32,10 +33,10 @@ public:
signals:
/**
* @brief firstStageInstrChanged
- * Emitted whenever the PC of the first stage, changed. Argument is the address of the instruction now present in
- * the first stage.
+ * Emitted whenever the PC of the first stage, changed. Argument is the row of the instruction now present
+ * in the first stage.
*/
- void firstStageInstrChanged(AInt);
+ void firstStageInstrChanged(int row);
private:
void updateStageInfo();
@@ -47,10 +48,10 @@ private:
void updateRowCount();
void onProcessorReset();
+ std::shared_ptr<const Program> m_program;
QStringList m_stageNames;
using StageID = unsigned;
std::map<StageID, StageInfo> m_stageInfos;
int m_rowCount = 0;
- std::map<unsigned int, AInt> m_indexToAddress;
};
} // namespace Ripes

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -382,7 +382,7 @@ void ProcessorTab::updateInstructionModel() {
m_ui->instructionView->horizontalHeader()->setSectionResizeMode(InstructionModel::Instruction,
QHeaderView::Stretch);
// Make the instruction view follow the instruction which is currently present in the first stage of the
- connect(m_instrModel, &InstructionModel::firstStageInstrChanged, this, &ProcessorTab::setInstructionViewCenterAddr);
+ connect(m_instrModel, &InstructionModel::firstStageInstrChanged, this, &ProcessorTab::setInstructionViewCenterRow);
if (oldModel) {
delete oldModel;
@@ -449,20 +449,19 @@ void ProcessorTab::reset() {
SystemIO::printString("\n");
}
-void ProcessorTab::setInstructionViewCenterAddr(AInt address) {
- const auto index = m_instrModel->addressToRow(address);
+void ProcessorTab::setInstructionViewCenterRow(int row) {
const auto view = m_ui->instructionView;
const auto rect = view->rect();
- int indexTop = view->indexAt(rect.topLeft()).row();
- int indexBot = view->indexAt(rect.bottomLeft()).row();
- indexBot = indexBot < 0 ? m_instrModel->rowCount() : indexBot;
+ int rowTop = view->indexAt(rect.topLeft()).row();
+ int rowBot = view->indexAt(rect.bottomLeft()).row();
+ rowBot = rowBot < 0 ? m_instrModel->rowCount() : rowBot;
- const int nItemsVisible = indexBot - indexTop;
+ const int nItemsVisible = rowBot - rowTop;
// move scrollbar if if is not visible
- if (index <= indexTop || index >= indexBot) {
+ if (row <= rowTop || row >= rowBot) {
auto scrollbar = view->verticalScrollBar();
- scrollbar->setValue(index - nItemsVisible / 2);
+ scrollbar->setValue(row - nItemsVisible / 2);
}
}

MODIFY
src/processortab.h
src/processortab.h
@@ -51,7 +51,7 @@ public slots:
private slots:
void run(bool state);
- void setInstructionViewCenterAddr(AInt address);
+ void setInstructionViewCenterRow(int row);
void showPipelineDiagram();
private:

Cache disassembled version of program (#142)