summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiddarth-Suresh <65844402+Siddarth-Suresh@users.noreply.github.com>2025-04-01 21:54:38 -0400
committerSiddarth-Suresh <65844402+Siddarth-Suresh@users.noreply.github.com>2025-04-01 21:54:38 -0400
commitcc2781682a47dc331f7bbcb5d7842db5197d29fc (patch)
tree248c770c6e1a51756c5a8fa904ec4873fb66644e
parent6f536bd1bd1abab307c79d688c993e930cf7c250 (diff)
GUI and controller on separate threads
-rw-r--r--gui/gui.cc228
-rw-r--r--gui/gui.h46
-rw-r--r--gui/gui.ui34
-rw-r--r--gui/worker.cc67
-rw-r--r--gui/worker.h50
-rw-r--r--inc/controller.h4
-rw-r--r--src/sim/controller.cc4
7 files changed, 416 insertions, 17 deletions
diff --git a/gui/gui.cc b/gui/gui.cc
index 5a4c779..b96d65d 100644
--- a/gui/gui.cc
+++ b/gui/gui.cc
@@ -6,9 +6,237 @@ GUI::GUI(QWidget *parent)
, ui(new Ui::GUI)
{
ui->setupUi(this);
+
+ ui->enabl_cache_checkbox->setChecked(true);
+ ui->enable_pipeline_checkbox->setChecked(true);
+
+ worker = new Worker();
+ worker->moveToThread(&workerThread);
+
+ // Connect worker thread lifecycle
+ connect(&workerThread, &QThread::started, worker, &Worker::doWork);
+
+ // Display clock cycles and PC
+ connect(worker, &Worker::clock_cycles, this, &GUI::onWorkerClockCycles);
+
+ // Display dram
+ connect(worker, &Worker::dram_storage, this, &GUI::onWorkerShowDram);
+
+ // Display cache
+ connect(worker, &Worker::cache_storage, this, &GUI::onWorkerShowCache);
+
+ // Display registers
+ connect(worker, &Worker::register_storage, this, &GUI::onWorkerShowRegisters);
+
+ // Refresh DRAM from worker thread
+ connect(this, &GUI::sendRefreshDram, worker, &Worker::refreshDram, Qt::QueuedConnection);
+
+ // Refresh Cache from worker thread
+ connect(this, &GUI::sendRefreshCache, worker, &Worker::refreshCache, Qt::QueuedConnection);
+
+ // Refresh Registers from worker thread
+ connect(this, &GUI::sendRefreshRegisters, worker, &Worker::refreshRegisters, Qt::QueuedConnection);
+
+ // Advance controller by #steps
+ connect(this, &GUI::sendRunSteps, worker, &Worker::runSteps, Qt::QueuedConnection);
+
+ // Advance controller by 1 step
+ connect(this, &GUI::sendRunStep, worker, &Worker::runStep, Qt::QueuedConnection);
+
+ // Proper cleanup when worker finishes
+ connect(worker, &Worker::finished, this, &GUI::onWorkerFinished);
+ connect(worker, &Worker::finished, &workerThread, &QThread::quit);
+ connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
+
+ workerThread.start(); // Start the worker thread
}
GUI::~GUI()
{
+ workerThread.quit();
+ workerThread.wait(); // Ensure proper cleanup
delete ui;
}
+
+void displayArrayHTML(QTextEdit *textEdit, const std::array<int, GPR_NUM> &data) {
+ textEdit->setReadOnly(false);
+ QString tableText = "<table border='1' cellspacing='0' cellpadding='8' style='border-collapse: collapse; width: 100%; border: 2px solid black;'>";
+
+ tableText += "<tr>";
+ int index = 1;
+ for (int value : data) {
+ tableText += QString("<td align='center' style='border: 2px solid black; min-width: 60px; padding: 10px;'>"
+ "%1 <sup style='font-size: 10px; font-weight: bold; color: black;'>%2</sup>"
+ "</td>")
+ .arg(QString::asprintf("%04X", value))
+ .arg(index);
+ index++;
+ }
+ tableText += "</tr>";
+ tableText += "</table>";
+
+ textEdit->setHtml(tableText);
+ textEdit->setReadOnly(true);
+}
+
+void displayTableHTML(QTextEdit *textEdit, const std::vector<std::array<signed int, LINE_SIZE>> &data) {
+ textEdit->setReadOnly(false);
+ QString tableText = "<table border='1' cellspacing='0' cellpadding='8' style='border-collapse: collapse; width: 100%; border: 2px solid black;'>";
+
+ int index = 1;
+ for (const auto &row : data) {
+ tableText += "<tr>";
+ for (signed int value : row) {
+ tableText += QString("<td align='center' style='border: 2px solid black; min-width: 60px; padding: 10px;'>"
+ "%1 <sup style='font-size: 10px; font-weight: bold; color: black;'>%2</sup>"
+ "</td>")
+ .arg(QString::asprintf("%04X", value))
+ .arg(index);
+ index++;
+ }
+ tableText += "</tr>";
+ }
+
+ tableText += "</table>";
+
+ textEdit->setHtml(tableText);
+ textEdit->setReadOnly(true);
+}
+
+void browseAndUploadFile(QTextEdit *textEdit) {
+ QString filePath = QFileDialog::getOpenFileName(nullptr, "Open File", QDir::homePath(), "Text Files (*.txt);;All Files (*.*)");
+
+ if (filePath.isEmpty()) {
+ return;
+ }
+
+ QFile file(filePath);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ textEdit->setPlainText("Error: Unable to open file!");
+ return;
+ }
+
+ QTextStream in(&file);
+ QString content;
+ int lineNumber = 1;
+
+ while (!in.atEnd()) {
+ QString line = in.readLine();
+
+ content += QString("<div id='line_%1' style='display: flex; justify-content: space-between; align-items: center;'>"
+ "<span style='font-size: 10px; font-weight: bold; color: gray;'>%1.</span>"
+ "<span>%2</span>"
+ "</div><hr>")
+ .arg(lineNumber)
+ .arg(line);
+
+ lineNumber++;
+ }
+
+ file.close();
+
+ textEdit->setReadOnly(false);
+ textEdit->setHtml(content);
+ textEdit->setReadOnly(true);
+}
+
+void GUI::onWorkerClockCycles(int cycles, int pc) {
+ ui->cycles_label->setText("Clock Cycles: " + QString::number(cycles) + "\t\t" + "PC: " + QString::number(pc));
+}
+
+void GUI::onWorkerShowDram(const std::vector<std::array<signed int, LINE_SIZE>> data) {
+ displayTableHTML(ui->dram_table, data);
+}
+
+void GUI::onWorkerShowCache(const std::vector<std::array<signed int, LINE_SIZE>> data) {
+ displayTableHTML(ui->cache_table, data);
+}
+
+void GUI::onWorkerShowRegisters(const std::array<int, GPR_NUM> &data) {
+ displayArrayHTML(ui->register_table, data);
+}
+
+void GUI::onWorkerFinished() {
+ qDebug() << "Worker has finished processing.";
+}
+
+void GUI::on_upload_intructions_btn_clicked()
+{
+ qDebug() << "Upload intructions button clicked.";
+ browseAndUploadFile(ui->instruction_table);
+
+}
+
+
+void GUI::on_upload_program_state_btn_clicked()
+{
+ //TODO:Upload and set program state ( have to decide how to use this)
+ qDebug() << "upload program state button is clicked.";
+}
+
+
+void GUI::on_refresh_dram_btn_clicked()
+{
+ qDebug() << "Refresh DRAM button clicked.";
+ emit sendRefreshDram();
+
+}
+
+
+void GUI::on_refresh_cache_btn_clicked()
+{
+ qDebug() << "Refresh cache button clicked.";
+ emit sendRefreshCache();
+}
+
+
+void GUI::on_refresh_registers_btn_clicked()
+{
+ qDebug() << "Refresh registers button clicked.";
+ emit sendRefreshRegisters();
+}
+
+
+void GUI::on_enable_pipeline_checkbox_checkStateChanged(const Qt::CheckState &arg1)
+{
+ //TODO: handle pipeline enabling
+ if(arg1 == Qt::CheckState::Checked) {
+ qDebug() << "enable pipeline checkbox checked.";
+ } else {
+ qDebug() << "enable pipeline checkbox unchecked.";
+ }
+}
+
+
+void GUI::on_enabl_cache_checkbox_checkStateChanged(const Qt::CheckState &arg1)
+{
+ //TODO: handle cache enabling
+ if(arg1 == Qt::CheckState::Checked) {
+ qDebug() << "enable cache checkbox checked.";
+ } else {
+ qDebug() << "enable cache checkbox unchecked.";
+ }
+
+}
+
+
+void GUI::on_run_steps_btn_clicked()
+{
+ qDebug() << "Run steps button clicked.";
+ emit sendRunSteps(ui->number_steps_inp->text().toInt());
+}
+
+
+void GUI::on_step_btn_clicked()
+{
+ qDebug() << "Run step button clicked.";
+ emit sendRunStep();
+}
+
+
+void GUI::on_save_program_state_btn_clicked()
+{
+ //TODO: save program state
+ qDebug() << "save program state button is clicked.";
+}
+
diff --git a/gui/gui.h b/gui/gui.h
index 1b700cc..77a8867 100644
--- a/gui/gui.h
+++ b/gui/gui.h
@@ -2,6 +2,12 @@
#define GUI_H
#include <QMainWindow>
+#include <QThread>
+#include <QFileDialog>
+#include <QFile>
+#include <QTextStream>
+#include <QTextEdit>
+#include "worker.h"
QT_BEGIN_NAMESPACE
namespace Ui {
@@ -17,7 +23,47 @@ public:
GUI(QWidget *parent = nullptr);
~GUI();
+signals:
+ void sendRefreshDram();
+ void sendRefreshCache();
+ void sendRefreshRegisters();
+ void sendRunSteps(int steps);
+ void sendRunStep();
+
+private slots:
+ void onWorkerClockCycles(int value, int pc);
+
+ void onWorkerShowDram(const std::vector<std::array<signed int, LINE_SIZE>> data);
+
+ void onWorkerShowCache(const std::vector<std::array<signed int, LINE_SIZE>> data);
+
+ void onWorkerShowRegisters(const std::array<int, GPR_NUM> &data);
+
+ void onWorkerFinished();
+
+ void on_upload_intructions_btn_clicked();
+
+ void on_upload_program_state_btn_clicked();
+
+ void on_refresh_dram_btn_clicked();
+
+ void on_refresh_cache_btn_clicked();
+
+ void on_refresh_registers_btn_clicked();
+
+ void on_enable_pipeline_checkbox_checkStateChanged(const Qt::CheckState &arg1);
+
+ void on_enabl_cache_checkbox_checkStateChanged(const Qt::CheckState &arg1);
+
+ void on_run_steps_btn_clicked();
+
+ void on_step_btn_clicked();
+
+ void on_save_program_state_btn_clicked();
+
private:
Ui::GUI *ui;
+ QThread workerThread;
+ Worker *worker;
};
#endif // GUI_H
diff --git a/gui/gui.ui b/gui/gui.ui
index 00bcbd4..f515b58 100644
--- a/gui/gui.ui
+++ b/gui/gui.ui
@@ -13,7 +13,7 @@
<property name="windowTitle">
<string>RISC V[ECTOR]</string>
</property>
- <widget class="QWidget" name="centralwidget">
+ <widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<layout class="QGridLayout" name="gridLayout">
@@ -46,7 +46,7 @@
</widget>
</item>
<item>
- <widget class="QTextEdit" name="textEdit"/>
+ <widget class="QTextEdit" name="instruction_table"/>
</item>
</layout>
</item>
@@ -74,7 +74,7 @@
</widget>
</item>
<item>
- <widget class="QTextEdit" name="textEdit_2"/>
+ <widget class="QTextEdit" name="register_table"/>
</item>
</layout>
</item>
@@ -109,7 +109,7 @@
</widget>
</item>
<item>
- <widget class="QTextEdit" name="textEdit_4"/>
+ <widget class="QTextEdit" name="cache_table"/>
</item>
</layout>
</item>
@@ -142,7 +142,7 @@
</widget>
</item>
<item>
- <widget class="QTextEdit" name="textEdit_3"/>
+ <widget class="QTextEdit" name="dram_table"/>
</item>
</layout>
</item>
@@ -197,7 +197,7 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
- <widget class="QPushButton" name="pushButton_5">
+ <widget class="QPushButton" name="upload_intructions_btn">
<property name="text">
<string>Upload Instruction File</string>
</property>
@@ -206,7 +206,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
- <widget class="QPushButton" name="pushButton_6">
+ <widget class="QPushButton" name="upload_program_state_btn">
<property name="text">
<string>Upload Program State File</string>
</property>
@@ -251,21 +251,21 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
- <widget class="QPushButton" name="pushButton_4">
+ <widget class="QPushButton" name="refresh_dram_btn">
<property name="text">
<string>Refresh DRAM</string>
</property>
</widget>
</item>
<item>
- <widget class="QPushButton" name="pushButton_2">
+ <widget class="QPushButton" name="refresh_cache_btn">
<property name="text">
<string>Refresh Cache</string>
</property>
</widget>
</item>
<item>
- <widget class="QPushButton" name="pushButton">
+ <widget class="QPushButton" name="refresh_registers_btn">
<property name="text">
<string>Refresh Registers</string>
</property>
@@ -276,14 +276,14 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <widget class="QCheckBox" name="checkBox">
+ <widget class="QCheckBox" name="enable_pipeline_checkbox">
<property name="text">
<string>Enable Pipeline</string>
</property>
</widget>
</item>
<item>
- <widget class="QCheckBox" name="checkBox_2">
+ <widget class="QCheckBox" name="enabl_cache_checkbox">
<property name="text">
<string>Enable Cache</string>
</property>
@@ -328,14 +328,14 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
- <widget class="QLineEdit" name="lineEdit">
+ <widget class="QLineEdit" name="number_steps_inp">
<property name="placeholderText">
<string># Steps</string>
</property>
</widget>
</item>
<item>
- <widget class="QPushButton" name="pushButton_7">
+ <widget class="QPushButton" name="run_steps_btn">
<property name="text">
<string>Run Steps</string>
</property>
@@ -344,7 +344,7 @@
</layout>
</item>
<item>
- <widget class="QPushButton" name="pushButton_8">
+ <widget class="QPushButton" name="step_btn">
<property name="text">
<string>Step</string>
</property>
@@ -383,14 +383,14 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="label_6">
+ <widget class="QLabel" name="cycles_label">
<property name="text">
<string>Clock Cycles</string>
</property>
</widget>
</item>
<item>
- <widget class="QPushButton" name="pushButton_3">
+ <widget class="QPushButton" name="save_program_state_btn">
<property name="text">
<string>Save Current Program State</string>
</property>
diff --git a/gui/worker.cc b/gui/worker.cc
new file mode 100644
index 0000000..ca3ec4b
--- /dev/null
+++ b/gui/worker.cc
@@ -0,0 +1,67 @@
+#include "worker.h"
+
+Worker::Worker(QObject *parent) : QObject(parent) {}
+
+void Worker::doWork() {
+ qDebug() << "Initializing...";
+ this->d = new Dram(0);
+ this->c = new Cache(this->d, 0);
+ this->if_stage = new IF(nullptr);
+ this->id_stage = new ID(if_stage);
+ this->ex_stage = new EX(id_stage);
+ this->mm_stage = new MM(ex_stage);
+ this->wb_stage = new WB(mm_stage);
+ this->ct = new Controller(wb_stage, this->c, true);
+
+ emit clock_cycles(this->ct->get_clock_cycle(), this->ct->get_pc());
+ emit dram_storage(this->d->view(0,32));
+ emit cache_storage(this->c->view(0,8));
+ emit register_storage(this->ct->get_gprs());
+
+ signed int w;
+ w = 0x11223344;
+ this->d->write_word(MEM, w, 0x0);
+ this->c->write_word(MEM, w, 0x0);
+ this->ct->set_gprs(0, w);
+}
+
+Worker::~Worker() {
+ emit finished();
+ qDebug() << "Worker destructor called in thread:" << QThread::currentThread();
+ delete this->ct;
+ delete this->c;
+}
+
+
+void Worker::refreshDram() {
+ qDebug() << "Refreshing Dram";
+ emit dram_storage(this->d->view(0,32));
+}
+
+void Worker::refreshCache() {
+ qDebug() << "Refreshing Dram";
+ emit cache_storage(this->c->view(0,8));
+}
+
+void Worker::refreshRegisters() {
+ qDebug() << "Refreshing Registers";
+ emit register_storage(this->ct->get_gprs());
+}
+
+void Worker::runSteps(int steps) {
+ qDebug() << "Running for steps: " << steps;
+ this->ct->run_for(steps);
+ emit dram_storage(this->d->view(0,32));
+ emit cache_storage(this->c->view(0,8));
+ emit register_storage(this->ct->get_gprs());
+ emit clock_cycles(this->ct->get_clock_cycle(), this->ct->get_pc());
+}
+
+void Worker::runStep() {
+ qDebug() << "Running for 1 step " ;
+ this->ct->advance(OK);
+ emit dram_storage(this->d->view(0,32));
+ emit cache_storage(this->c->view(0,8));
+ emit register_storage(this->ct->get_gprs());
+ emit clock_cycles(this->ct->get_clock_cycle(), this->ct->get_pc());
+} \ No newline at end of file
diff --git a/gui/worker.h b/gui/worker.h
new file mode 100644
index 0000000..99ab39a
--- /dev/null
+++ b/gui/worker.h
@@ -0,0 +1,50 @@
+#ifndef WORKER_H
+#define WORKER_H
+
+#include <QObject>
+#include <QThread>
+#include <QDebug>
+
+#include "controller.h"
+#include "dram.h"
+#include "cache.h"
+#include "id.h"
+#include "if.h"
+#include "ex.h"
+#include "mm.h"
+#include "wb.h"
+
+class Worker : public QObject {
+ Q_OBJECT
+
+private:
+ Cache *c;
+ Dram *d;
+ Controller *ct;
+ ID *id_stage;
+ IF *if_stage;
+ EX *ex_stage;
+ MM *mm_stage;
+ WB *wb_stage;
+
+public:
+ explicit Worker(QObject *parent = nullptr);
+ ~Worker();
+
+public slots:
+ void doWork();
+ void refreshDram();
+ void refreshCache();
+ void refreshRegisters();
+ void runSteps(int steps);
+ void runStep();
+
+signals:
+ void clock_cycles(int value, int pc);
+ void dram_storage(const std::vector<std::array<signed int, LINE_SIZE>> data);
+ void cache_storage(const std::vector<std::array<signed int, LINE_SIZE>> data);
+ void register_storage(const std::array<int, GPR_NUM> data);
+ void finished();
+};
+
+#endif // WORKER_H \ No newline at end of file
diff --git a/inc/controller.h b/inc/controller.h
index 17aba37..f56b1b4 100644
--- a/inc/controller.h
+++ b/inc/controller.h
@@ -38,6 +38,10 @@ class Controller : public Stage
*/
int get_pc();
+ void set_gprs(int index, int value);
+
+ void set_pipelined(bool value);
+
private:
void advance_helper() override;
};
diff --git a/src/sim/controller.cc b/src/sim/controller.cc
index 89ff4e7..7e24b3d 100644
--- a/src/sim/controller.cc
+++ b/src/sim/controller.cc
@@ -26,6 +26,10 @@ int Controller::get_clock_cycle() { return this->clock_cycle; }
std::array<int, GPR_NUM> Controller::get_gprs() { return this->gprs; }
+void Controller::set_gprs(int index, int value) { this->gprs[index] = value; }
+
+void Controller::set_pipelined(bool value) { this->is_pipelined = value; }
+
int Controller::get_pc() { return this->pc; }
InstrDTO *Controller::advance(Response p)