Fix auto clock timer not stopping when a breakpoint is hit
MODIFY
docs/release_notes.md
docs/release_notes.md
# Ripes Release Notes
+## Ripes v2.2.7
+
+### Bug fixes and minor stuff
+- Fixed auto-clocking not being stopped when a breakpoint has been hit.
+- Fixed breakpoint set at line 0 also being mirrored at line `num instructions`.
+
+## Ripes v2.2.6
+
### Bug fixes and minor stuff
- Changed the terminology for caches, substituting "Word" for "Block". Most textbooks use the term "cache block" interchangeably with "cache line", so using "Block" for words stored in a cache line was confusing.

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -159,24 +159,27 @@ void ProcessorHandler::_triggerProcStateChangeTimer() {
class ProcessorClocker : public QRunnable {
public:
- explicit ProcessorClocker(bool &finished) : m_finished(finished) {}
+ explicit ProcessorClocker(std::mutex &clockLock) : clockLock(clockLock) {}
void run() override {
+ std::unique_lock l(clockLock);
ProcessorHandler::getProcessorNonConst()->clock();
ProcessorHandler::checkProcessorFinished();
if (ProcessorHandler::checkBreakpoint()) {
ProcessorHandler::stopRun();
}
- m_finished = true;
}
private:
- bool &m_finished;
+ std::mutex &clockLock;
};
void ProcessorHandler::_clock() {
- if (m_clockFinished) {
- m_clockFinished = false;
- QThreadPool::globalInstance()->start(new ProcessorClocker(m_clockFinished));
+ // Attempt to grab the clock lock - if not possible to acquire, this means
+ // that there already is an ongoing clock event. This _clock event will
+ // therefore be ignored.
+ if (m_clockLock.try_lock()) {
+ QThreadPool::globalInstance()->start(new ProcessorClocker(m_clockLock));
+ m_clockLock.unlock();
}
}

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -327,7 +327,7 @@ private:
QFutureWatcher<void> m_runWatcher;
bool m_stopRunningFlag = false;
- bool m_clockFinished = true;
+ std::mutex m_clockLock;
/**
* @brief To avoid excessive UI updates due to things relying on

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -230,7 +230,7 @@ void ProcessorTab::setupSimulatorActions(QToolBar *controlToolbar) {
m_autoClockTimer = new QTimer(this);
connect(m_autoClockTimer, &QTimer::timeout, this,
- [=] { ProcessorHandler::clock(); });
+ [=] { autoClockTimeout(); });
const QIcon startAutoClockIcon = QIcon(":/icons/step-clock.svg");
m_autoClockAction = new QAction(startAutoClockIcon, "Auto clock (F6)", this);
@@ -239,8 +239,7 @@ void ProcessorTab::setupSimulatorActions(QToolBar *controlToolbar) {
"Clock the circuit with the selected frequency (F6)");
m_autoClockAction->setCheckable(true);
m_autoClockAction->setChecked(false);
- connect(m_autoClockAction, &QAction::triggered, this,
- &ProcessorTab::autoClock);
+ connect(m_autoClockAction, &QAction::toggled, this, &ProcessorTab::autoClock);
controlToolbar->addAction(m_autoClockAction);
m_autoClockInterval = new QSpinBox(this);
@@ -524,6 +523,12 @@ void ProcessorTab::runFinished() {
m_statUpdateTimer->stop();
}
+void ProcessorTab::autoClockTimeout() {
+ if (ProcessorHandler::checkBreakpoint())
+ return;
+ ProcessorHandler::clock();
+}
+
void ProcessorTab::autoClock(bool state) {
const QIcon startAutoClockIcon = QIcon(":/icons/step-clock.svg");
const QIcon stopAutoTimerIcon = QIcon(":/icons/stop-clock.svg");
@@ -531,6 +536,11 @@ void ProcessorTab::autoClock(bool state) {
m_autoClockTimer->stop();
m_autoClockAction->setIcon(startAutoClockIcon);
} else {
+ // Always clock the processor to start with. Afterwards, run
+ // autoClockTimeout() which will check if the processor is at a breakpoint.
+ // This is to circumvent some annoying cross-thread, eventloop,
+ // race-condition-y state setting wrt. when exactly a breakpoint is hit.
+ ProcessorHandler::clock();
m_autoClockTimer->start();
m_autoClockAction->setIcon(stopAutoTimerIcon);
}

MODIFY
src/processortab.h
src/processortab.h
@@ -54,6 +54,7 @@ public slots:
private slots:
void run(bool state);
void autoClock(bool state);
+ void autoClockTimeout();
void setInstructionViewCenterRow(int row);
void showPipelineDiagram();

MODIFY
src/programviewer.cpp
src/programviewer.cpp
@@ -222,17 +222,20 @@ QTextBlock ProgramViewer::blockForAddress(AInt addr) const {
AInt ProgramViewer::addressForBlock(QTextBlock block, bool &ok) const {
ok = true;
- const static auto calcAddressFunc = [](int lineNumber) {
+ const static auto calcAddressFunc =
+ [&](int lineNumber) -> std::optional<AInt> {
auto m_program = ProcessorHandler::getProgram();
if (m_program) {
auto &disassembleRes = m_program->getDisassembled();
- if (disassembleRes.numInstructions() < static_cast<unsigned>(lineNumber))
- return 0;
+ if (disassembleRes.numInstructions() <
+ static_cast<unsigned>(lineNumber)) {
+ return std::nullopt;
+ }
if (auto addr = disassembleRes.indexToAddress(lineNumber);
addr.has_value())
- return static_cast<int>(addr.value());
+ return static_cast<AInt>(addr.value());
}
- return 0;
+ return std::nullopt;
};
const int lineNumber = block.blockNumber();
@@ -248,8 +251,11 @@ AInt ProgramViewer::addressForBlock(QTextBlock block, bool &ok) const {
// subtract the invalid line count up to the given point.
int adjustedLineNumber = lineNumber;
- if (m_labelAddrOffsetMap.empty())
- return calcAddressFunc(adjustedLineNumber);
+ if (m_labelAddrOffsetMap.empty()) {
+ auto calcAddressRes = calcAddressFunc(adjustedLineNumber);
+ ok = calcAddressRes.has_value();
+ return ok ? calcAddressRes.value() : 0;
+ }
auto low = m_labelAddrOffsetMap.lower_bound(lineNumber);
@@ -257,7 +263,9 @@ AInt ProgramViewer::addressForBlock(QTextBlock block, bool &ok) const {
static_cast<unsigned>(lineNumber) < low->first) {
// The line number is less that the position of the first offset block;
// address is directly inferred from linenumber.
- return calcAddressFunc(adjustedLineNumber);
+ auto calcAddressRes = calcAddressFunc(adjustedLineNumber);
+ ok = calcAddressRes.has_value();
+ return ok ? calcAddressRes.value() : 0;
}
if (low != m_labelAddrOffsetMap.begin()) {
@@ -265,7 +273,9 @@ AInt ProgramViewer::addressForBlock(QTextBlock block, bool &ok) const {
}
adjustedLineNumber -= (low->second.first + 1);
- return calcAddressFunc(adjustedLineNumber);
+ auto calcAddressRes = calcAddressFunc(adjustedLineNumber);
+ ok = calcAddressRes.has_value();
+ return ok ? calcAddressRes.value() : 0;
}
AInt ProgramViewer::addressForPos(const QPoint &pos, bool &ok) const {

Fix auto clock timer not stopping when a breakpoint is hit #260