diff options
author | Siddarth-Suresh <65844402+Siddarth-Suresh@users.noreply.github.com> | 2025-04-01 21:54:38 -0400 |
---|---|---|
committer | Siddarth-Suresh <65844402+Siddarth-Suresh@users.noreply.github.com> | 2025-04-01 21:54:38 -0400 |
commit | cc2781682a47dc331f7bbcb5d7842db5197d29fc (patch) | |
tree | 248c770c6e1a51756c5a8fa904ec4873fb66644e /gui | |
parent | 6f536bd1bd1abab307c79d688c993e930cf7c250 (diff) |
GUI and controller on separate threads
Diffstat (limited to 'gui')
-rw-r--r-- | gui/gui.cc | 228 | ||||
-rw-r--r-- | gui/gui.h | 46 | ||||
-rw-r--r-- | gui/gui.ui | 34 | ||||
-rw-r--r-- | gui/worker.cc | 67 | ||||
-rw-r--r-- | gui/worker.h | 50 |
5 files changed, 408 insertions, 17 deletions
@@ -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."; +} + @@ -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 @@ -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 |