#include "gui.h" #include "./ui_gui.h" #include "byteswap.h" GUI::GUI(QWidget *parent) : QMainWindow(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); connect(worker, &Worker::if_info, this, &GUI::onWorkerFetchInfo); connect(worker, &Worker::id_info, this, &GUI::onWorkerDecodeInfo); connect(worker, &Worker::ex_info, this, &GUI::onWorkerExecuteInfo); connect(worker, &Worker::mm_info, this, &GUI::onWorkerMemoryInfo); connect(worker, &Worker::wb_info, this, &GUI::onWorkerWriteBackInfo); // 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); // Load program from worker thread connect(this, &GUI::sendLoadProgram, worker, &Worker::loadProgram, Qt::QueuedConnection); // Configure pipeline connect(this, &GUI::sendConfigure, worker, &Worker::configure, 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 = 0; 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 = 0; 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); } std::vector browseAndRetrieveFile(QWidget* parent) { QString filePath = QFileDialog::getOpenFileName(parent, "Open Binary File", QDir::homePath(), "Binary Files (*.bin *.rv);;All Files (*.*)"); std::vector program; if (filePath.isEmpty()) return program; QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(parent, "File Upload", "Unable to open file!"); return program; } while (!file.atEnd()) { char bytes[4]; if (file.read(bytes, 4) == 4) { uint32_t word = (static_cast(bytes[0]) << 24) | (static_cast(bytes[1]) << 16) | (static_cast(bytes[2]) << 8) | (static_cast(bytes[3])); program.push_back(static_cast(word)); } } file.close(); return program; } void GUI::onWorkerClockCycles(int cycles, int pc) { QFont font = ui->cycles_label->font(); font.setBold(true); font.setItalic(true); font.setPointSize(14); ui->cycles_label->setFont(font); ui->cycles_label->setText("Clock Cycles: " + QString::number(cycles) + "\t\t" + "PC: " + QString::number(pc)); } void GUI::onWorkerFetchInfo(const std::vector info) { //QString::asprintf("%04X", value) if(!info.empty()) { ui->fetch_pc->setText(QString::number(info[0])); ui->fetch_instruction_bits->setText(QString::asprintf("%04X", info[1])); } else { ui->fetch_pc->clear(); ui->fetch_instruction_bits->clear(); } } void GUI::onWorkerDecodeInfo(const std::vector info) { if(!info.empty()) { // ui->decode_mnemonic->setText(mnemonicToString((Mnemonic)info[0])); ui->decode_pc->setText(QString::number(info[0])); ui->decode_s1->setText(QString::asprintf("%04X", info[1])); // ui->decode_s2->setText(QString::asprintf("%04X", info[3])); // ui->decode_s3->setText(QString::asprintf("%04X", info[4])); } else { // ui->decode_mnemonic->clear(); ui->decode_pc->clear(); ui->decode_s1->clear(); // ui->decode_s2->clear(); // ui->decode_s3->clear(); } } void GUI::onWorkerExecuteInfo(const std::vector info) { if(!info.empty()) { ui->execute_mnemonic->setText(mnemonicToString((Mnemonic)info[0])); ui->execute_pc->setText(QString::number(info[1])); ui->execute_s1->setText(QString::asprintf("%04X", info[2])); ui->execute_s2->setText(QString::asprintf("%04X", info[3])); ui->execute_s3->setText(QString::asprintf("%04X", info[4])); } else { ui->execute_mnemonic->clear(); ui->execute_pc->clear(); ui->execute_s1->clear(); ui->execute_s2->clear(); ui->execute_s3->clear(); } } void GUI::onWorkerMemoryInfo(const std::vector info) { if(!info.empty()) { ui->memory_mnemonic->setText(mnemonicToString((Mnemonic)info[0])); ui->memory_pc->setText(QString::number(info[1])); ui->memory_s1->setText(QString::asprintf("%04X", info[2])); ui->memory_s2->setText(QString::asprintf("%04X", info[3])); ui->memory_s3->setText(QString::asprintf("%04X", info[4])); } else { ui->memory_mnemonic->clear(); ui->memory_pc->clear(); ui->memory_s1->clear(); ui->memory_s2->clear(); ui->memory_s3->clear(); } } void GUI::onWorkerWriteBackInfo(const std::vector info) { if(!info.empty()) { ui->wb_mnemonic->setText(mnemonicToString((Mnemonic)info[0])); ui->wb_pc->setText(QString::number(info[1])); ui->wb_s1->setText(QString::asprintf("%04X", info[2])); ui->wb_s2->setText(QString::asprintf("%04X", info[3])); ui->wb_s3->setText(QString::asprintf("%04X", info[4])); } else { ui->wb_mnemonic->clear(); ui->wb_pc->clear(); ui->wb_s1->clear(); ui->wb_s2->clear(); ui->wb_s3->clear(); } } 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."; std::vector program; program = browseAndRetrieveFile(ui->register_table); if(program.empty()){ QMessageBox::critical(ui->register_table, "File Upload", "Invalid Program File!"); } emit sendLoadProgram(program); emit sendRefreshDram(); QMessageBox::information(ui->register_table, "File Upload", "Instructions loaded successfully!"); } 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_set_levels_btn_clicked() { qDebug() << "Set levels button clicked."; bool ok; int value = QInputDialog::getInt(this, "Enter Value", "Enter value:", 0, 0, 10, 1, &ok); if (ok) { cache_levels = value; ui->cache_levels_dropdwn->clear(); // Clear previous entries for (int i = 0; i < cache_levels; ++i) { ui->cache_levels_dropdwn->addItem(QString::number(i)); ways.push_back(2); size.push_back(5); } } else { qDebug() << "User cancelled input."; } } void GUI::on_set_cache_btn_clicked() { int current_cache = ui->cache_levels_dropdwn->currentIndex(); // qDebug() << "current cache: " << current_cache; int prevWays = ways[current_cache]; int prevSize = size[current_cache]; QString cache_ways = ui->cache_ways_inp->text(); QString cache_size = ui->cache_size_inp->text(); ways[current_cache] = cache_ways.isEmpty() ? prevWays : cache_ways.toInt(); size[current_cache] = cache_size.isEmpty() ? prevSize : cache_size.toInt(); QMessageBox::information(ui->register_table, "Cache Configuration", "Cache" + QString::number(current_cache) + " values set successfully! Please click on Configure button to configure the pipeline or configure other caches."); // for(int i=0;inumber_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."; } void GUI::on_Configure_Btn_clicked() { emit sendConfigure(ways, size, is_pipelined, is_cache_enabled); QMessageBox::information(ui->register_table, "Pipeline Configuration", "Pipeline and memory subsystem configured successfully!"); }