From 1008f8180161b3ab7c6b885cb6f6a19df59dd398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Thu, 21 Dec 2017 15:01:18 +0100 Subject: A lot of small changes in gui Added machine status. Widgets now hold size and registers dock has now scrollbars. And more... --- qtmips_gui/coreview.cpp | 36 +++++++++-------- qtmips_gui/coreview.h | 13 +++++-- qtmips_gui/mainwindow.cpp | 83 +++++++++++++++++++++++++++++++++++----- qtmips_gui/mainwindow.h | 11 ++++-- qtmips_gui/registersdock.cpp | 11 ++++-- qtmips_gui/registersdock.h | 3 +- qtmips_machine/qtmipsmachine.cpp | 67 +++++++++++++++++++++++--------- qtmips_machine/qtmipsmachine.h | 20 +++++++++- 8 files changed, 188 insertions(+), 56 deletions(-) diff --git a/qtmips_gui/coreview.cpp b/qtmips_gui/coreview.cpp index b7c17fc..f7cc416 100644 --- a/qtmips_gui/coreview.cpp +++ b/qtmips_gui/coreview.cpp @@ -1,14 +1,23 @@ #include "coreview.h" -CoreView::CoreView(QWidget *parent, machine::QtMipsMachine *machine) : QGraphicsView(parent) { +CoreView::CoreView(QWidget *parent) : QGraphicsView(parent) { setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + // TODO fitInView doesn't work as I want so reimplement or do something with it + //fitInView(0, 0, 201, 201, Qt::KeepAspectRatioByExpanding); +} + +void CoreView::resizeEvent(QResizeEvent *event) { + // fitInView(0, 0, 201, 201, Qt::KeepAspectRatioByExpanding); +} + +CoreViewScene::CoreViewScene(CoreView *view, machine::QtMipsMachine *machine) : QGraphicsScene(view) { this->machine = machine; // Identification cross - scene.addLine(400, 0, 400, 800); - scene.addLine(0, 400, 800, 400); + addLine(400, 0, 400, 800); + addLine(0, 400, 800, 400); pc = new coreview::ProgramCounter(machine); alu = new coreview::Alu(); @@ -17,22 +26,19 @@ CoreView::CoreView(QWidget *parent, machine::QtMipsMachine *machine) : QGraphics pc2pc = new coreview::Connection(pc_multiplexer->connector_out(), pc->connector_in()); - scene.addItem(pc); - scene.addItem(alu); - scene.addItem(pc_multiplexer); - scene.addItem(testlatch); - scene.addItem(pc2pc); + addItem(pc); + addItem(alu); + addItem(pc_multiplexer); + addItem(testlatch); + addItem(pc2pc); pc->setPos(100,100); alu->setPos(200, 100); pc_multiplexer->setPos(60, 100); pc_multiplexer->set(2); - setScene(&scene); - // TODO fitInView doesn't work as I want so reimplement or do something with it - //fitInView(0, 0, 201, 201, Qt::KeepAspectRatioByExpanding); -} - -void CoreView::resizeEvent(QResizeEvent *event) { - // fitInView(0, 0, 201, 201, Qt::KeepAspectRatioByExpanding); + QGraphicsScene *old_scene = view->scene(); + view->setScene(this); + if (old_scene != nullptr) + delete old_scene; } diff --git a/qtmips_gui/coreview.h b/qtmips_gui/coreview.h index 8c0701e..fddcafe 100644 --- a/qtmips_gui/coreview.h +++ b/qtmips_gui/coreview.h @@ -11,14 +11,19 @@ #include "coreview/alu.h" class CoreView : public QGraphicsView { - Q_OBJECT public: - CoreView(QWidget *parent, machine::QtMipsMachine *machine); + CoreView(QWidget *parent); private: void resizeEvent(QResizeEvent *event); +}; + +class CoreViewScene : public QGraphicsScene { + Q_OBJECT +public: + CoreViewScene(CoreView *view, machine::QtMipsMachine *machine); - QGraphicsScene scene; +private: machine::QtMipsMachine *machine; coreview::ProgramCounter *pc; @@ -31,6 +36,6 @@ private: #else class CoreView; -class CoreViewBlock; +class CoreViewScene; #endif // COREVIEW_H diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp index 6a507fa..9e1902a 100644 --- a/qtmips_gui/mainwindow.cpp +++ b/qtmips_gui/mainwindow.cpp @@ -1,13 +1,17 @@ #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { + machine = nullptr; + corescene = nullptr; settings = new QSettings("CTU", "QtMips"); - coreview = nullptr; ui = new Ui::MainWindow(); ui->setupUi(this); setWindowTitle("QtMips"); + // Prepare empty core view + coreview = new CoreView(this); + this->setCentralWidget(coreview); // Create/prepare other widgets ndialog = new NewDialog(this, settings); cache_content = new CacheContentDock(this); @@ -32,6 +36,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { MainWindow::~MainWindow() { settings->sync(); delete settings; + if (corescene != nullptr) + delete corescene; if (coreview != nullptr) delete coreview; delete ndialog; @@ -49,22 +55,34 @@ void MainWindow::start() { } void MainWindow::create_core(machine::MachineConfig *config) { + // Remove old machine + if (machine != nullptr) + delete machine; // Create machine machine = new machine::QtMipsMachine(config); // Create machine view - coreview = new CoreView(this, machine); - this->setCentralWidget(coreview); + corescene = new CoreViewScene(coreview, machine); - machine->set_speed(1000); // Set default speed to 1 sec + //machine->set_speed(1000); // Set default speed to 1 sec + machine->set_speed(0); - // Connect machine signals + // Connect machine signals and slots connect(ui->actionRun, SIGNAL(triggered(bool)), machine, SLOT(play())); connect(ui->actionPause, SIGNAL(triggered(bool)), machine, SLOT(pause())); connect(ui->actionStep, SIGNAL(triggered(bool)), machine, SLOT(step())); connect(ui->actionRestart, SIGNAL(triggered(bool)), machine, SLOT(restart())); + connect(machine, SIGNAL(status_change(machine::QtMipsMachine::Status)), this, SLOT(machine_status(machine::QtMipsMachine::Status))); + connect(machine, SIGNAL(program_exit()), this, SLOT(machine_exit())); + connect(machine, SIGNAL(program_trap(machine::QtMipsException&)), this, SLOT(machine_trap(machine::QtMipsException&))); // Setup docks registers->setup(machine); + // Set status to ready + machine_status(machine::QtMipsMachine::ST_READY); +} + +bool MainWindow::configured() { + return (machine != nullptr); } void MainWindow::new_machine() { @@ -83,15 +101,10 @@ void MainWindow::show_registers() { show_dockwidget(registers); } -bool MainWindow::configured() { - return (machine != nullptr); -} - void MainWindow::closeEvent(QCloseEvent *event) { settings->setValue("windowGeometry", saveGeometry()); settings->setValue("windowState", saveState()); settings->sync(); - QMainWindow::closeEvent(event); } void MainWindow::show_dockwidget(QDockWidget *dw) { @@ -103,3 +116,53 @@ void MainWindow::show_dockwidget(QDockWidget *dw) { dw->setFocus(); } } + +void MainWindow::machine_status(enum machine::QtMipsMachine::Status st) { + QString status; + switch (st) { + case machine::QtMipsMachine::ST_READY: + ui->actionPause->setEnabled(false); + ui->actionRun->setEnabled(true); + ui->actionStep->setEnabled(true); + status = "Ready"; + break; + case machine::QtMipsMachine::ST_RUNNING: + ui->actionPause->setEnabled(true); + ui->actionRun->setEnabled(false); + ui->actionStep->setEnabled(false); + status = "Running"; + break; + case machine::QtMipsMachine::ST_BUSY: + // Busy is not interesting (in such case we should just be running + return; + case machine::QtMipsMachine::ST_EXIT: + // machine_exit is called so we disable controls in that + status = "Exited"; + break; + case machine::QtMipsMachine::ST_TRAPPED: + // machine_trap is called so we disable controls in that + status = "Trapped"; + break; + default: + status = "Unknown"; + break; + } + ui->statusBar->showMessage(status); +} + +void MainWindow::machine_exit() { + ui->actionPause->setEnabled(false); + ui->actionRun->setEnabled(false); + ui->actionStep->setEnabled(false); +} + +void MainWindow::machine_trap(machine::QtMipsException &e) { + machine_exit(); + + QMessageBox msg(this); + msg.setText(e.msg(false)); + msg.setIcon(QMessageBox::Critical); + msg.setDetailedText(e.msg(true)); + msg.setWindowTitle("Machine trapped"); + msg.exec(); +} diff --git a/qtmips_gui/mainwindow.h b/qtmips_gui/mainwindow.h index 8b9e3e7..6f588ac 100644 --- a/qtmips_gui/mainwindow.h +++ b/qtmips_gui/mainwindow.h @@ -23,14 +23,18 @@ public: void start(); void create_core(machine::MachineConfig *config); + bool configured(); + public slots: + // Actions signals void new_machine(); - void show_cache_content(); void show_cache_statictics(); void show_registers(); - - bool configured(); + // Machine signals + void machine_status(enum machine::QtMipsMachine::Status st); + void machine_exit(); + void machine_trap(machine::QtMipsException &e); protected: void closeEvent(QCloseEvent *event); @@ -41,6 +45,7 @@ private: NewDialog *ndialog; CoreView *coreview; + CoreViewScene *corescene; CacheContentDock *cache_content; CacheStatisticsDock *cache_statictics; diff --git a/qtmips_gui/registersdock.cpp b/qtmips_gui/registersdock.cpp index 20eb9e4..5d965ca 100644 --- a/qtmips_gui/registersdock.cpp +++ b/qtmips_gui/registersdock.cpp @@ -3,8 +3,10 @@ RegistersDock::RegistersDock(QWidget *parent) : QDockWidget(parent) { regs = nullptr; - widg = new QScrollArea(this); + scrollarea = new QScrollArea(this); + widg = new QWidget(scrollarea); layout = new QFormLayout(widg); + layout->setSizeConstraint(QLayout::SetMinAndMaxSize); #define INIT(X, LABEL) do{ \ X = new QLabel(widg); \ @@ -17,10 +19,13 @@ RegistersDock::RegistersDock(QWidget *parent) : QDockWidget(parent) { INIT(gp[i], QString("GP") + QString::number(i) + QString(" ($") + QString::number(i) + QString("):")); INIT(lo, "LO:"); INIT(hi, "HI:"); - #undef INIT + widg->setLayout(layout); + scrollarea->setWidget(widg); - setWidget(widg); + setWidget(scrollarea); + setObjectName("Registers"); + setWindowTitle("Registers"); } RegistersDock::~RegistersDock() { diff --git a/qtmips_gui/registersdock.h b/qtmips_gui/registersdock.h index 654983e..3504608 100644 --- a/qtmips_gui/registersdock.h +++ b/qtmips_gui/registersdock.h @@ -24,7 +24,8 @@ private slots: private: const machine::Registers *regs; - QScrollArea *widg; + QWidget *widg; + QScrollArea *scrollarea; QFormLayout *layout; QLabel *pc; diff --git a/qtmips_machine/qtmipsmachine.cpp b/qtmips_machine/qtmipsmachine.cpp index 8d1a46a..102dff0 100644 --- a/qtmips_machine/qtmipsmachine.cpp +++ b/qtmips_machine/qtmipsmachine.cpp @@ -4,14 +4,15 @@ using namespace machine; QtMipsMachine::QtMipsMachine(const MachineConfig &cc) { + stat = ST_READY; + ProgramLoader program(cc.elf()); + mem_program_only = new Memory(); + program.to_memory(mem_program_only); + program_end = program.end(); regs = new Registers(); - mem = new Memory(); - - program.to_memory(mem); - program_end = program.end(); - program_ended = false; + mem = new Memory(*mem_program_only); MemoryAccess *coremem; switch (cc.cache()) { @@ -28,8 +29,11 @@ QtMipsMachine::QtMipsMachine(const MachineConfig &cc) { throw QTMIPS_EXCEPTION(Sanity, "Trying to configure unknown cache type", ""); } - // TODO pipelined - cr = new CoreSingle(regs, coremem); + cr_pipelined = cc.pipelined(); + if (cc.pipelined()) + cr = new CorePipelined(regs, coremem); + else + cr = new CoreSingle(regs, coremem); run_speed = 1; run_t = new QTimer(this); @@ -58,32 +62,59 @@ const Core *QtMipsMachine::core() { return cr; } +enum QtMipsMachine::Status QtMipsMachine::status() { + return stat; +} + +bool QtMipsMachine::exited() { + return stat == ST_EXIT || stat == ST_TRAPPED; +} + +// We don't allow to call control methods when machine exited or if it's busy +// We rather silently fail. +// TODO wouldn't be error better? +#define CTL_GUARD do { if (exited() || stat == ST_BUSY) return; } while(false) + void QtMipsMachine::play() { - if (program_ended) - return; + CTL_GUARD; + set_status(ST_RUNNING); run_t->start(run_speed); } void QtMipsMachine::pause() { - if (program_ended) - return; + CTL_GUARD; + set_status(ST_READY); run_t->stop(); } void QtMipsMachine::step() { - if (program_ended) // Ignore if program ended - return; + CTL_GUARD; + enum Status stat_prev = stat; + set_status(ST_BUSY); emit tick(); - cr->step(); + try { + cr->step(); + } catch (QtMipsException e) { + run_t->stop(); + set_status(ST_TRAPPED); + emit program_trap(e); + return; + } if (regs->read_pc() >= program_end) { - program_ended = true; run_t->stop(); + set_status(ST_EXIT); emit program_exit(); - } + } else + set_status(stat_prev); } void QtMipsMachine::restart() { - if (!program_ended) - run_t->stop(); // Stop timer if program is still running // TODO } + +void QtMipsMachine::set_status(enum Status st) { + bool change = st != stat; + stat = st; + if (change) + emit status_change(st); +} diff --git a/qtmips_machine/qtmipsmachine.h b/qtmips_machine/qtmipsmachine.h index 28abfa6..d2e60de 100644 --- a/qtmips_machine/qtmipsmachine.h +++ b/qtmips_machine/qtmipsmachine.h @@ -25,6 +25,16 @@ public: const Cache *cache(); const Core *core(); + enum Status { + ST_READY, // Machine is ready to be started or step to be called + ST_RUNNING, // Machine is running + ST_BUSY, // Machine is calculating step + ST_EXIT, // Machine exited + ST_TRAPPED // Machine exited with failure + }; + enum Status status(); + bool exited(); + public slots: // TODO handle speed void play(); @@ -34,19 +44,25 @@ public slots: signals: void program_exit(); + void program_trap(machine::QtMipsException &e); + void status_change(enum machine::QtMipsMachine::Status st); void tick(); // Time tick private: Registers *regs; - Memory *mem; + Memory *mem, *mem_program_only; Cache *cch; Core *cr; + bool cr_pipelined; + unsigned run_speed; QTimer *run_t; std::uint32_t program_end; - bool program_ended; + enum Status stat; + + void set_status(enum Status st); }; } -- cgit v1.2.3