Highlight currently executing instructions in ProgramViewer
MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -77,6 +77,12 @@ void EditTab::clearAssemblyEditor() {
m_assembler->clear();
}
+void EditTab::updateProgramViewerHighlighting() {
+ if (isVisible()) {
+ m_ui->programViewer->updateHighlightedAddresses();
+ }
+}
+
void EditTab::emitProgramChanged() {
updateProgramViewer();
emit programChanged(&m_activeProgram);

MODIFY
src/edittab.h
src/edittab.h
@@ -27,7 +27,6 @@ public:
~EditTab() override;
void setAssemblyText(const QString& text);
- void updateProgramViewer();
QString getAssemblyText();
void newProgram();
void clearAssemblyEditor();
@@ -43,6 +42,8 @@ signals:
void editorStateChanged(bool enabled);
public slots:
+ void updateProgramViewerHighlighting();
+
void emitProgramChanged();
/**
@@ -56,6 +57,7 @@ private slots:
void on_disassembledViewButton_toggled();
private:
+ void updateProgramViewer();
bool loadFlatBinaryFile(Program& program, QFile& file, unsigned long entryPoint, unsigned long loadAt);
bool loadAssemblyFile(Program& program, QFile& file);
bool loadElfFile(Program& program, QFile& file);

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -68,6 +68,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
// setup and connect widgets
connect(m_processorTab, &ProcessorTab::update, this, &MainWindow::updateMemoryTab);
+ connect(m_processorTab, &ProcessorTab::update, m_editTab, &EditTab::updateProgramViewerHighlighting);
connect(this, &MainWindow::update, m_processorTab, &ProcessorTab::restart);
connect(this, &MainWindow::updateMemoryTab, m_memoryTab, &MemoryTab::update);
connect(m_stackedTabs, &QStackedWidget::currentChanged, m_memoryTab, &MemoryTab::update);

MODIFY
src/programviewer.cpp
src/programviewer.cpp
@@ -69,6 +69,7 @@ void ProgramViewer::updateProgram(const Program& program, bool binary) {
const auto text = binary ? Parser::getParser()->binarize(program, m_labelAddrOffsetMap)
: Parser::getParser()->disassemble(program, m_labelAddrOffsetMap);
setPlainText(text);
+ updateHighlightedAddresses();
}
void ProgramViewer::updateSidebar(const QRect& rect, int dy) {
@@ -84,6 +85,34 @@ void ProgramViewer::updateSidebarWidth(int /* newBlockCount */) {
setViewportMargins(m_sidebarWidth, 0, 0, 0);
}
+void ProgramViewer::updateHighlightedAddresses() {
+ const unsigned stages = ProcessorHandler::get()->getProcessor()->stageCount();
+ QColor bg = QColor(Qt::red).lighter(120);
+ const int decRatio = 100 + 80 / stages;
+ QList<QTextEdit::ExtraSelection> highlights;
+ std::set<unsigned long> highlightedPCs;
+
+ for (unsigned sid = 0; sid < stages; sid++) {
+ const auto stageInfo = ProcessorHandler::get()->getProcessor()->stageInfo(sid);
+ if (stageInfo.stage_valid) {
+ auto block = blockForAddress(stageInfo.pc);
+ if (!block.isValid())
+ continue;
+ if (highlightedPCs.count(stageInfo.pc)) {
+ continue;
+ }
+ QTextEdit::ExtraSelection es;
+ es.cursor = QTextCursor(block);
+ es.format.setProperty(QTextFormat::FullWidthSelection, true);
+ es.format.setBackground(bg);
+ highlights << es;
+ highlightedPCs.insert(stageInfo.pc);
+ }
+ bg = bg.lighter(decRatio);
+ }
+ setExtraSelections(highlights);
+}
+
void ProgramViewer::breakpointAreaPaintEvent(QPaintEvent* event) {
QPainter painter(m_breakpointArea);
@@ -103,20 +132,15 @@ void ProgramViewer::breakpointAreaPaintEvent(QPaintEvent* event) {
while (block.isValid() && top <= event->rect().bottom()) {
volatile int line = block.blockNumber();
- const bool invalidLine = m_labelAddrOffsetMap.count(block.blockNumber());
- if (block.isVisible() && bottom >= event->rect().top() && !invalidLine) {
- int adjustedLineNumber = block.blockNumber();
- auto offsetsToLine = m_labelAddrOffsetMap.lower_bound(adjustedLineNumber);
- if (offsetsToLine != m_labelAddrOffsetMap.end()) {
- adjustedLineNumber -= offsetsToLine->second;
- }
- const unsigned long address = ProcessorHandler::get()->getTextStart() +
- adjustedLineNumber * ProcessorHandler::get()->currentISA()->bytes();
+ if (block.isVisible() && bottom >= event->rect().top()) {
+ const long address = addressForBlock(block);
+ if (address >= 0) {
if (ProcessorHandler::get()->hasBreakpoint(address)) {
painter.drawPixmap(m_breakpointArea->padding, top, m_breakpointArea->imageWidth,
m_breakpointArea->imageHeight, m_breakpointArea->m_breakpoint);
}
}
+ }
block = block.next();
top = bottom;
@@ -124,27 +148,57 @@ void ProgramViewer::breakpointAreaPaintEvent(QPaintEvent* event) {
}
}
-long ProgramViewer::addressForPos(const QPoint& pos) const {
- // Get line height
- QTextBlock block = firstVisibleBlock();
+namespace {}
- const auto height = blockBoundingRect(block).height();
+QTextBlock ProgramViewer::blockForAddress(unsigned long addr) const {
+ const long adjustedLineNumber =
+ (addr - ProcessorHandler::get()->getTextStart()) / ProcessorHandler::get()->currentISA()->bytes();
- // Find block index in the ProgramViewer
- int index;
- if (block == document()->findBlockByLineNumber(0)) {
- index = static_cast<int>((pos.y() - contentOffset().y()) / height);
+ if (m_labelAddrOffsetMap.empty()) {
+ return document()->findBlockByNumber(adjustedLineNumber);
+ }
+
+ long lineNumber = adjustedLineNumber;
+ auto low = m_labelAddrOffsetMap.lower_bound(lineNumber);
+ auto high = low;
+ if (low != m_labelAddrOffsetMap.begin()) {
+ low = std::prev(m_labelAddrOffsetMap.lower_bound(lineNumber));
+ high = std::next(low);
} else {
- index = static_cast<int>((pos.y() + contentOffset().y()) / height);
+ high = m_labelAddrOffsetMap.end();
}
- // Get actual block index
- while (index > 0) {
- block = block.next();
- index--;
+
+ auto validBlockRange = [this, adjustedLineNumber](auto& low, auto& high, long lineNumber) {
+ if (m_labelAddrOffsetMap.count(lineNumber))
+ return false;
+
+ bool valid = true;
+ valid &= (low->first - low->second) <= adjustedLineNumber;
+ if (high != m_labelAddrOffsetMap.end()) {
+ valid &= adjustedLineNumber < (high->first - high->second);
}
- if (!block.isValid())
- return -1;
+ return valid;
+ };
+ // Adjust low and high iterators to locate the range bounds of the address
+ while (!validBlockRange(low, high, lineNumber)) {
+ if (high == m_labelAddrOffsetMap.end()) {
+ lineNumber = low->first + 1;
+ } else {
+ lineNumber = high->first + 1;
+ }
+
+ low = std::prev(m_labelAddrOffsetMap.lower_bound(lineNumber));
+ high = std::next(low);
+ }
+
+ const int offsetSum = high == m_labelAddrOffsetMap.end() ? low->second + 1 : high->second;
+ lineNumber = offsetSum + adjustedLineNumber;
+
+ return document()->findBlockByNumber(lineNumber);
+}
+
+long ProgramViewer::addressForBlock(QTextBlock block) const {
const int lineNumber = block.blockNumber();
// Clicking an invalid line? (non-instruction line)
@@ -165,6 +219,30 @@ long ProgramViewer::addressForPos(const QPoint& pos) const {
ProcessorHandler::get()->getTextStart();
}
+long ProgramViewer::addressForPos(const QPoint& pos) const {
+ // Get line height
+ QTextBlock block = firstVisibleBlock();
+
+ const auto height = blockBoundingRect(block).height();
+
+ // Find block index in the ProgramViewer
+ int index;
+ if (block == document()->findBlockByLineNumber(0)) {
+ index = static_cast<int>((pos.y() - contentOffset().y()) / height);
+ } else {
+ index = static_cast<int>((pos.y() + contentOffset().y()) / height);
+ }
+ // Get actual block index
+ while (index > 0) {
+ block = block.next();
+ index--;
+ }
+ if (!block.isValid())
+ return -1;
+
+ return addressForBlock(block);
+}
+
bool ProgramViewer::hasBreakpoint(const QPoint& pos) const {
return ProcessorHandler::get()->hasBreakpoint(static_cast<unsigned>(addressForPos(pos)));
}

MODIFY
src/programviewer.h
src/programviewer.h
@@ -21,9 +21,12 @@ public:
void breakpointAreaPaintEvent(QPaintEvent* event);
void breakpointClick(const QPoint& pos);
bool hasBreakpoint(const QPoint& pos) const;
- long addressForPos(const QPoint& pos) const;
void clearBreakpoints();
+ long addressForPos(const QPoint& pos) const;
+ long addressForBlock(QTextBlock block) const;
+ QTextBlock blockForAddress(unsigned long) const;
+
///
/// \brief updateProgram
/// Refreshes the programViewer view with @p program, using the parser to either disassemble or (if @p binary is
@@ -31,6 +34,9 @@ public:
///
void updateProgram(const Program& program, bool binary = false);
+public slots:
+ void updateHighlightedAddresses();
+
protected:
void resizeEvent(QResizeEvent* event) override;

Highlight currently executing instructions in ProgramViewer