[WIP] Implementing circuit 'running', asynchronously executing processor
missing:
A run dialog
Test with ELF file which doesn't terminate
a note that pipeline table trace will not be recorded during running
MODIFY
external/VSRTL
external/VSRTL
-Subproject commit d1a70ecf625c2b1a78d2e68cbf828175b8996dec
+Subproject commit 2d9585f420bf5c3941548fe912a3723c69636dab

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -30,6 +30,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
setWindowIcon(QIcon(":/icons/logo.svg"));
showMaximized();
+ // Initialize processor handler
+ ProcessorHandler::get();
+
// Create tabs
m_stackedTabs = new QStackedWidget(this);
m_ui->centrallayout->addWidget(m_stackedTabs);
@@ -70,6 +73,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
connect(ProcessorHandler::get(), &ProcessorHandler::reqReloadProgram, m_editTab, &EditTab::emitProgramChanged);
connect(ProcessorHandler::get(), &ProcessorHandler::print, m_processorTab, &ProcessorTab::printToLog);
connect(ProcessorHandler::get(), &ProcessorHandler::exit, m_processorTab, &ProcessorTab::processorFinished);
+ connect(ProcessorHandler::get(), &ProcessorHandler::runFinished, m_processorTab, &ProcessorTab::runFinished);
connect(m_ui->actionAbout, &QAction::triggered, this, &MainWindow::about);
connect(m_ui->actionOpen_wiki, &QAction::triggered, this, &MainWindow::wiki);

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
#include "program.h"
#include <QMessageBox>
+#include <QtConcurrent/QtConcurrent>
namespace Ripes {
@@ -54,6 +55,22 @@ const vsrtl::core::SparseArray& ProcessorHandler::getRegisters() const {
return m_currentProcessor->getRegisters();
}
+void ProcessorHandler::run() {
+ auto future = QtConcurrent::run([=] {
+ m_currentProcessor->setEnableSignals(false);
+ bool stopRunning = m_stopRunningFlag;
+ while (!stopRunning) {
+ m_currentProcessor->clock();
+ ProcessorHandler::get()->checkValidExecutionRange();
+ stopRunning |=
+ ProcessorHandler::get()->checkBreakpoint() || m_currentProcessor->finished() || m_stopRunningFlag;
+ }
+ m_currentProcessor->setEnableSignals(true);
+ });
+ m_runWatcher.setFuture(future);
+ connect(&m_runWatcher, &QFutureWatcher<void>::finished, this, &ProcessorHandler::runFinished);
+}
+
void ProcessorHandler::setBreakpoint(const uint32_t address, bool enabled) {
if (enabled) {
m_breakpoints.insert(address);
@@ -70,11 +87,9 @@ bool ProcessorHandler::hasBreakpoint(const uint32_t address) const {
return m_breakpoints.count(address);
}
-void ProcessorHandler::checkBreakpoint() {
+bool ProcessorHandler::checkBreakpoint() {
const auto pc = m_currentProcessor->pcForStage(0);
- if (m_breakpoints.count(pc)) {
- emit hitBreakpoint(pc);
- }
+ return m_breakpoints.count(pc);
}
void ProcessorHandler::toggleBreakpoint(const uint32_t address) {
@@ -92,7 +107,6 @@ void ProcessorHandler::selectProcessor(const ProcessorID& id, RegisterSetup setu
// Processor initializations
m_currentProcessor = ProcessorRegistry::constructProcessor(m_currentID);
m_currentProcessor->handleSysCall.Connect(this, &ProcessorHandler::handleSysCall);
- m_currentProcessor->finished.Connect(this, &ProcessorHandler::processorFinished);
// Register initializations
auto& regs = m_currentProcessor->getRegisters();
@@ -165,10 +179,18 @@ void ProcessorHandler::handleSysCall() {
}
}
-void ProcessorHandler::processorFinished() {
+void ProcessorHandler::checkProcessorFinished() {
+ if (m_currentProcessor->finished())
emit exit();
}
+void ProcessorHandler::stop() {
+ if (m_runWatcher.isRunning())
+ m_stopRunningFlag = true;
+ m_runWatcher.waitForFinished();
+ m_stopRunningFlag = false;
+}
+
void ProcessorHandler::checkValidExecutionRange() const {
const auto pc = m_currentProcessor->nextPcForStage(0);
if (!(m_validExecutionRange.first <= pc && pc < m_validExecutionRange.second)) {

MODIFY
src/processorhandler.h
src/processorhandler.h
#pragma once
+#include <QFuture>
+#include <QFutureWatcher>
#include <QObject>
#include "processorregistry.h"
@@ -81,11 +83,26 @@ public:
*/
uint32_t getRegisterValue(const unsigned idx) const;
- void checkBreakpoint();
+ bool checkBreakpoint();
void setBreakpoint(const uint32_t address, bool enabled);
void toggleBreakpoint(const uint32_t address);
bool hasBreakpoint(const uint32_t address) const;
void clearBreakpoints();
+ void checkProcessorFinished();
+
+ /**
+ * @brief run
+ * Asynchronously runs the current processor. During this, the processor will not be emitting signals for updating
+ * its graphical representation. Will break upon hitting a breakpoint, going out of bounds wrt. the allowed
+ * execution area or if the stop flag has been set through stop().
+ */
+ void run();
+
+ /**
+ * @brief stop
+ * Sets the m_stopRunningFlag, and waits for any currently running asynchronous run execution to finish.
+ */
+ void stop();
signals:
/**
@@ -114,18 +131,13 @@ signals:
*/
void exit();
- /**
- * @brief hitBreakpoint
- * Emitted whenever the instruction at breakpoint @param address is fetched into the processor
- */
- void hitBreakpoint(uint32_t address);
+ void runFinished();
public slots:
void loadProgram(const Program* p);
private slots:
void handleSysCall();
- void processorFinished();
private:
ProcessorHandler();
@@ -142,5 +154,8 @@ private:
std::pair<uint32_t, uint32_t> m_validExecutionRange;
std::set<uint32_t> m_breakpoints;
const Program* m_program = nullptr;
+
+ QFutureWatcher<void> m_runWatcher;
+ bool m_stopRunningFlag = false;
};
} // namespace Ripes

MODIFY
src/processors/ripesprocessor.h
src/processors/ripesprocessor.h
@@ -125,10 +125,9 @@ public:
/**
* @brief finished
- * Signal emitted by the processor to notify the outside environment that it has finished executing. Must be
- * preceeded by a call to RipesProcessor::finalize, performed by the outside environment.
+ * @returns true if the processor has finished executing.
*/
- Gallant::Signal0<> finished;
+ virtual bool finished() const = 0;
private:
// Statistics

MODIFY
src/processors/ss/riscv_ss.h
src/processors/ss/riscv_ss.h
@@ -162,6 +162,7 @@ public:
// Allow one additional clock cycle to clear the current instruction
m_finishInNextCycle = true;
}
+ bool finished() const override { return m_finished; }
void setRegister(unsigned i, uint32_t v) override { setSynchronousValue(registerFile->_wr_mem, i, v); }
@@ -171,7 +172,7 @@ public:
const bool finishInThisCycle = m_finishInNextCycle;
Design::clock();
if (finishInThisCycle) {
- finished.Emit();
+ m_finished = true;
}
}
@@ -179,15 +180,18 @@ public:
Design::rewind();
// Ensure that rewinds performed when we expected to finish in the following cycle, clears this expectation.
m_finishInNextCycle = false;
+ m_finished = false;
}
void reset() override {
Design::reset();
m_finishInNextCycle = false;
+ m_finished = false;
}
private:
bool m_finishInNextCycle = false;
+ bool m_finished = false;
};
} // namespace core

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -34,8 +34,6 @@ ProcessorTab::ProcessorTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolba
m_ui->registerWidget->updateModel();
connect(this, &ProcessorTab::update, m_ui->registerWidget, &RegisterWidget::updateView);
- connect(ProcessorHandler::get(), &ProcessorHandler::hitBreakpoint, this, &ProcessorTab::pause);
-
setupSimulatorActions();
// Connect ECALL functionality to application output log and scroll to bottom
@@ -120,9 +118,10 @@ void ProcessorTab::setupSimulatorActions() {
const QIcon runIcon = QIcon(":/icons/run.svg");
m_runAction = new QAction(runIcon, "Run (F8)", this);
m_runAction->setShortcut(QKeySequence("F8"));
- // connect(m_runAction, &QAction::triggered, this, &ProcessorTab::run);
+ m_runAction->setCheckable(true);
+ m_runAction->setChecked(false);
+ connect(m_runAction, &QAction::toggled, this, &ProcessorTab::run);
m_toolbar->addAction(m_runAction);
-
m_toolbar->addSeparator();
const QIcon tagIcon = QIcon(":/icons/tag.svg");
@@ -145,6 +144,8 @@ void ProcessorTab::setupSimulatorActions() {
void ProcessorTab::pause() {
m_autoClockAction->setChecked(false);
+ m_runAction->setChecked(false);
+ m_reverseAction->setEnabled(m_vsrtlWidget->isRewindable());
}
void ProcessorTab::processorSelection() {
@@ -200,26 +201,13 @@ ProcessorTab::~ProcessorTab() {
delete m_ui;
}
-/*
-void ProcessorTab::run() {
- m_autoClockAction->setChecked(false);
- auto pipeline = Pipeline::getPipeline();
- RunDialog dialog(this);
- if (pipeline->isReady()) {
- if (dialog.exec() && pipeline->isFinished()) {
- emit update();
- enableSimulatorControls();
- }
- }
-}
-*/
-
void ProcessorTab::processorFinished() {
// Disallow further clocking of the circuit
m_clockAction->setEnabled(false);
m_autoClockAction->setChecked(false);
m_autoClockAction->setEnabled(false);
m_runAction->setEnabled(false);
+ m_runAction->setChecked(false);
}
void ProcessorTab::enableSimulatorControls() {
@@ -257,6 +245,20 @@ void ProcessorTab::setInstructionViewCenterAddr(uint32_t address) {
}
}
+void ProcessorTab::runFinished() {
+ pause();
+ ProcessorHandler::get()->checkProcessorFinished();
+ emit update();
+}
+
+void ProcessorTab::run(bool state) {
+ if (state) {
+ ProcessorHandler::get()->run();
+ } else {
+ ProcessorHandler::get()->stop();
+ }
+}
+
void ProcessorTab::rewind() {
m_vsrtlWidget->rewind();
enableSimulatorControls();
@@ -266,7 +268,10 @@ void ProcessorTab::rewind() {
void ProcessorTab::clock() {
m_vsrtlWidget->clock();
ProcessorHandler::get()->checkValidExecutionRange();
- ProcessorHandler::get()->checkBreakpoint();
+ if (ProcessorHandler::get()->checkBreakpoint()) {
+ pause();
+ }
+ ProcessorHandler::get()->checkProcessorFinished();
m_reverseAction->setEnabled(m_vsrtlWidget->isRewindable());
emit update();

MODIFY
src/processortab.h
src/processortab.h
@@ -44,10 +44,12 @@ public slots:
void rewind();
void printToLog(const QString&);
void processorFinished();
+ void runFinished();
void processorSelection();
private slots:
+ void run(bool state);
void clock();
void setInstructionViewCenterAddr(uint32_t address);
void showStageTable();

[WIP] Implementing circuit 'running', asynchronously executing processor

missing:
- A run dialog
- Test with ELF file which doesn't terminate
- a note that pipeline table trace will not be recorded during running