From cc2781682a47dc331f7bbcb5d7842db5197d29fc Mon Sep 17 00:00:00 2001 From: Siddarth-Suresh <65844402+Siddarth-Suresh@users.noreply.github.com> Date: Tue, 1 Apr 2025 21:54:38 -0400 Subject: GUI and controller on separate threads --- gui/gui.cc | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gui/gui.h | 46 ++++++++++++ gui/gui.ui | 34 ++++----- gui/worker.cc | 67 +++++++++++++++++ gui/worker.h | 50 +++++++++++++ 5 files changed, 408 insertions(+), 17 deletions(-) create mode 100644 gui/worker.cc create mode 100644 gui/worker.h (limited to 'gui') 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 &data) { + textEdit->setReadOnly(false); + QString tableText = ""; + + tableText += ""; + int index = 1; + for (int value : data) { + tableText += QString("") + .arg(QString::asprintf("%04X", value)) + .arg(index); + index++; + } + tableText += ""; + tableText += "
" + "%1 %2" + "
"; + + textEdit->setHtml(tableText); + textEdit->setReadOnly(true); +} + +void displayTableHTML(QTextEdit *textEdit, const std::vector> &data) { + textEdit->setReadOnly(false); + QString tableText = ""; + + int index = 1; + for (const auto &row : data) { + tableText += ""; + for (signed int value : row) { + tableText += QString("") + .arg(QString::asprintf("%04X", value)) + .arg(index); + index++; + } + tableText += ""; + } + + tableText += "
" + "%1 %2" + "
"; + + 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("
" + "%1." + "%2" + "

") + .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> data) { + displayTableHTML(ui->dram_table, data); +} + +void GUI::onWorkerShowCache(const std::vector> data) { + displayTableHTML(ui->cache_table, data); +} + +void GUI::onWorkerShowRegisters(const std::array &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 +#include +#include +#include +#include +#include +#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> data); + + void onWorkerShowCache(const std::vector> data); + + void onWorkerShowRegisters(const std::array &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 @@ RISC V[ECTOR] - + @@ -46,7 +46,7 @@ - + @@ -74,7 +74,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -142,7 +142,7 @@ - + @@ -197,7 +197,7 @@ - + Upload Instruction File @@ -206,7 +206,7 @@ - + Upload Program State File @@ -251,21 +251,21 @@ - + Refresh DRAM - + Refresh Cache - + Refresh Registers @@ -276,14 +276,14 @@ - + Enable Pipeline - + Enable Cache @@ -328,14 +328,14 @@ - + # Steps - + Run Steps @@ -344,7 +344,7 @@ - + Step @@ -383,14 +383,14 @@ - + Clock Cycles - + Save Current Program State 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 +#include +#include + +#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> data); + void cache_storage(const std::vector> data); + void register_storage(const std::array data); + void finished(); +}; + +#endif // WORKER_H \ No newline at end of file -- cgit v1.2.3