aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qtmips_gui/hexlineedit.cpp4
-rw-r--r--qtmips_gui/hexlineedit.h4
-rw-r--r--qtmips_gui/mainwindow.cpp2
-rw-r--r--qtmips_gui/memorydock.cpp9
-rw-r--r--qtmips_gui/memorymodel.cpp5
-rw-r--r--qtmips_gui/memorytableview.cpp10
-rw-r--r--qtmips_gui/memorytableview.h4
-rw-r--r--qtmips_gui/memoryview.cpp246
-rw-r--r--qtmips_gui/memoryview.h113
-rw-r--r--qtmips_gui/programdock.cpp132
-rw-r--r--qtmips_gui/programdock.h35
-rw-r--r--qtmips_gui/programmodel.cpp185
-rw-r--r--qtmips_gui/programmodel.h97
-rw-r--r--qtmips_gui/programtableview.cpp155
-rw-r--r--qtmips_gui/programtableview.h68
-rw-r--r--qtmips_gui/qtmips_gui.pro10
16 files changed, 575 insertions, 504 deletions
diff --git a/qtmips_gui/hexlineedit.cpp b/qtmips_gui/hexlineedit.cpp
index c138591..761f153 100644
--- a/qtmips_gui/hexlineedit.cpp
+++ b/qtmips_gui/hexlineedit.cpp
@@ -75,13 +75,13 @@ HexLineEdit::HexLineEdit(QWidget *parent, int digits, int base, QString prefix):
set_value(0);
}
-void HexLineEdit::set_value(std::int32_t value) {
+void HexLineEdit::set_value(std::uint32_t value) {
QString s, t = "";
last_set = value;
s = QString::number(value, base);
if (s.count() < digits)
t.fill('0', digits - s.count());
- setText(prefix + t +s);
+ setText(prefix + t +s.toUpper());
}
diff --git a/qtmips_gui/hexlineedit.h b/qtmips_gui/hexlineedit.h
index 6b16edc..a00063b 100644
--- a/qtmips_gui/hexlineedit.h
+++ b/qtmips_gui/hexlineedit.h
@@ -50,10 +50,10 @@ public:
QString prefix = "0x");
public slots:
- void set_value(std::int32_t value);
+ void set_value(std::uint32_t value);
signals:
- void value_edit_finished(std::int32_t value);
+ void value_edit_finished(std::uint32_t value);
private slots:
void on_edit_finished();
diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp
index a520f9d..90d6911 100644
--- a/qtmips_gui/mainwindow.cpp
+++ b/qtmips_gui/mainwindow.cpp
@@ -145,7 +145,7 @@ void MainWindow::create_core(const machine::MachineConfig &config) {
connect(corescene, SIGNAL(request_registers()), this, SLOT(show_registers()));
connect(corescene, SIGNAL(request_program_memory()), this, SLOT(show_program()));
connect(corescene, SIGNAL(request_data_memory()), this, SLOT(show_memory()));
- connect(corescene, SIGNAL(request_jump_to_program_counter(std::uint32_t)), program, SLOT(jump_to_pc(std::uint32_t)));
+ connect(corescene, SIGNAL(request_jump_to_program_counter(std::uint32_t)), program, SIGNAL(jump_to_pc(std::uint32_t)));
connect(corescene, SIGNAL(request_cache_program()), this, SLOT(show_cache_program()));
connect(corescene, SIGNAL(request_cache_data()), this, SLOT(show_cache_data()));
// Connect signal from break to machine pause
diff --git a/qtmips_gui/memorydock.cpp b/qtmips_gui/memorydock.cpp
index dfeb9c8..ccb3b6a 100644
--- a/qtmips_gui/memorydock.cpp
+++ b/qtmips_gui/memorydock.cpp
@@ -71,7 +71,6 @@ MemoryDock::MemoryDock(QWidget *parent, QSettings *settings) : Super(parent) {
layout->addWidget(cell_size);
layout->addWidget(memory_content);
layout->addWidget(go_edit);
- layout->addWidget(go_edit);
content->setLayout(layout);
@@ -80,10 +79,10 @@ MemoryDock::MemoryDock(QWidget *parent, QSettings *settings) : Super(parent) {
connect(this, &MemoryDock::machine_setup, memory_model, &MemoryModel::setup);
connect(cell_size, SIGNAL(currentIndexChanged(int)),
memory_content, SLOT(set_cell_size(int)));
- connect(go_edit, SIGNAL(value_edit_finished(std::int32_t)),
- memory_content, SLOT(go_to_address(std::int32_t)));
- connect(memory_content, SIGNAL(address_changed(std::int32_t)),
- go_edit, SLOT(set_value(std::int32_t)));
+ connect(go_edit, SIGNAL(value_edit_finished(std::uint32_t)),
+ memory_content, SLOT(go_to_address(std::uint32_t)));
+ connect(memory_content, SIGNAL(address_changed(std::uint32_t)),
+ go_edit, SLOT(set_value(std::uint32_t)));
}
void MemoryDock::setup(machine::QtMipsMachine *machine) {
diff --git a/qtmips_gui/memorymodel.cpp b/qtmips_gui/memorymodel.cpp
index 09157bf..908f019 100644
--- a/qtmips_gui/memorymodel.cpp
+++ b/qtmips_gui/memorymodel.cpp
@@ -167,6 +167,11 @@ void MemoryModel::set_cell_size(int index) {
}
void MemoryModel::update_all() {
+ if (machine != nullptr && machine->memory() != nullptr) {
+ memory_change_counter = machine->memory()->get_change_counter();
+ if (machine->cache_data() != nullptr)
+ cache_data_change_counter = machine->cache_data()->get_change_counter();
+ }
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
}
diff --git a/qtmips_gui/memorytableview.cpp b/qtmips_gui/memorytableview.cpp
index 9b5d0ba..18e1bb1 100644
--- a/qtmips_gui/memorytableview.cpp
+++ b/qtmips_gui/memorytableview.cpp
@@ -62,21 +62,21 @@ void MemoryTableView::adjustColumnCount() {
QString t = "";
t.fill(QChar('0'), m->cellSizeBytes() * 2);
/* t + = " C"; */
- int width1 = fm.width(t) + 1;
+ int width1 = fm.width(t);
if (width1 < fm.width("+99"))
width1 = fm.width("+99");
horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
horizontalHeader()->resizeSection(1, width1);
- int w = verticalHeader()->width() + 8;
+ int w = verticalHeader()->width() + 4;
unsigned int cells;
width0 = columnWidth(0);
width1 = columnWidth(1);
w = width() - w - width0;
- if (w < width1) {
+ if (w < width1 + 2) {
cells = 1;
} else {
- cells = w / width1;
+ cells = w / (width1 + 2);
}
if (cells != m->cellsPerRow()) {
m->setCellsPerRow(cells);
@@ -167,7 +167,7 @@ void MemoryTableView::resizeEvent(QResizeEvent *event) {
}
}
-void MemoryTableView:: go_to_address(std::int32_t address) {
+void MemoryTableView:: go_to_address(std::uint32_t address) {
MemoryModel *m = dynamic_cast<MemoryModel*>(model());
int row;
if (m == nullptr)
diff --git a/qtmips_gui/memorytableview.h b/qtmips_gui/memorytableview.h
index 9ade84f..f5bf832 100644
--- a/qtmips_gui/memorytableview.h
+++ b/qtmips_gui/memorytableview.h
@@ -52,10 +52,10 @@ public:
void resizeEvent(QResizeEvent *event) override;
signals:
- void address_changed(std::int32_t address);
+ void address_changed(std::uint32_t address);
public slots:
void set_cell_size(int index);
- void go_to_address(std::int32_t address);
+ void go_to_address(std::uint32_t address);
private slots:
void adjust_scroll_pos();
private:
diff --git a/qtmips_gui/memoryview.cpp b/qtmips_gui/memoryview.cpp
deleted file mode 100644
index c4d022a..0000000
--- a/qtmips_gui/memoryview.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*******************************************************************************
- * QtMips - MIPS 32-bit Architecture Subset Simulator
- *
- * Implemented to support following courses:
- *
- * B35APO - Computer Architectures
- * https://cw.fel.cvut.cz/wiki/courses/b35apo
- *
- * B4M35PAP - Advanced Computer Architectures
- * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
- *
- * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
- * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *
- * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
- * Czech Technical University (http://www.cvut.cz/)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- ******************************************************************************/
-
-#include "memoryview.h"
-
-///////////////////////////
-// Minimal reserved range in pixels of scroll area (otherwise 10% of height are used)
-#define MIN_OFF 10
-// Focus point (this is multiplied with height of widget to know position where we want to focus)
-#define FOCUS 0.25
-// How angle maps to pixels when and scroll is used
-#define ANGLE_SCROLL 1
-///////////////////////////
-
-MemoryView::MemoryView(QWidget *parent, std::uint32_t addr0) : QWidget(parent) {
- memory = nullptr;
- addr_0 = addr0;
- change_counter = 0;
- cache_data_change_counter = 0;
-
- layout = new QVBoxLayout(this);
-
- memf= new Frame(this);
- layout->addWidget(memf);
-
-
- ctl_widg = new QWidget(this);
- layout->addWidget(ctl_widg);
-
- go_edit = new QLineEdit(ctl_widg);
- go_edit->setText("0x00000000");
- go_edit->setInputMask("\\0\\xHHHHHHHH");
- layout->addWidget(go_edit);
- connect(go_edit, SIGNAL(editingFinished()), this, SLOT(go_edit_finish()));
-}
-
-void MemoryView::setup(machine::QtMipsMachine *machine) {
- memory = (machine == nullptr) ? nullptr : machine->memory();
- cache_data = (machine == nullptr) ? nullptr : machine->cache_data();
- if (machine != nullptr)
- connect(machine, SIGNAL(post_tick()), this, SLOT(check_for_updates()));
- reload_content();
-}
-
-void MemoryView::set_focus(std::uint32_t address) {
- if (address < addr_0 || (address - addr_0)/4 > (unsigned)memf->widg->count()) {
- // This is outside of loaded area so just move it and reload everything
- addr_0 = address - 4*memf->focussed();
- addr0_save_change(addr_0);
- reload_content();
- } else {
- memf->focus((address - addr_0) / 4);
- }
- edit_load_focus();
-}
-
-std::uint32_t MemoryView::focus() const {
- return addr_0 + 4*memf->focussed();
-}
-
-std::uint32_t MemoryView::addr0() const {
- return addr_0;
-}
-
-void MemoryView::edit_load_focus() {
- go_edit->setText(QString("0x%1").arg(focus(), 8, 16, QChar('0')));
-}
-
-void MemoryView::check_for_updates() {
- bool need_update = false;
- if (memory != nullptr) {
- if (change_counter != memory->get_change_counter())
- need_update = true;
- }
- if (cache_data != nullptr) {
- if (cache_data_change_counter != cache_data->get_change_counter())
- need_update = true;
- }
- if (need_update)
- reload_content();
-}
-
-void MemoryView::reload_content() {
- int count = memf->widg->count();
- memf->widg->clearRows();
- if (memory != nullptr)
- change_counter = memory->get_change_counter();
- if (cache_data != nullptr)
- cache_data_change_counter = cache_data->get_change_counter();
- update_content(count, 0);
-}
-
-void MemoryView::update_content(int count, int shift) {
- if (abs(shift) >= memf->widg->count()) {
- // This shifts more than we have so just reload whole content
- memf->widg->clearRows();
- addr_0 += 4*shift;
- for (int i = 0; i <= count; i++)
- memf->widg->addRow(row_widget(addr_0 + 4*i, memf->widg));
- return;
- }
-
- int diff = count - memf->widg->count();
- int d_b = shift;
- int d_e = diff - shift;
-
- if (d_b > 0)
- for (int i = 0; i < d_b; i++) {
- addr_0 -= 4;
- memf->widg->insertRow(row_widget(addr_0, memf->widg), 0);
- }
- else
- for (int i = 0; i > d_b; i--) {
- addr_0 += 4;
- memf->widg->removeRow(0);
- }
- if (d_e > 0)
- for (int i = 0; i < d_e; i++)
- memf->widg->addRow(row_widget(addr_0 + 4*memf->widg->count(), memf->widg));
- else
- for (int i = 0; i > d_e; i--)
- memf->widg->removeRow(memf->widg->count() - 1);
- addr0_save_change(addr_0);
-}
-
-void MemoryView::addr0_save_change(std::uint32_t val) { /* ignore */ }
-
-void MemoryView::go_edit_finish() {
- QString hex = go_edit->text();
- hex.remove(0, 2);
-
- bool ok;
- std::uint32_t nw = hex.toUInt(&ok, 16);
- if (ok) {
- set_focus(nw);
- } else
- edit_load_focus();
-}
-
-MemoryView::Frame::Frame(MemoryView *parent) : QAbstractScrollArea(parent) {
- mv = parent;
- content_y = -3*MIN_OFF/2; // When this is initialized the width is 0 so this uses just min to inialize it
-
- widg = new StaticTable(this);
- setViewport(widg);
-
- setFrameShape(QFrame::NoFrame);
- setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- setContentsMargins(0, 0, 0, 0);
-}
-
-void MemoryView::Frame::focus(unsigned i) {
- content_y = (FOCUS*height()) - widg->row_size()*i/widg->columns() - widg->row_size()/2;
- viewport()->move(0, content_y);
- viewport()->repaint(0, content_y, width(), height());
- check_update();
-}
-
-// Calculate which row is in focus at the moment
-unsigned MemoryView::Frame::focussed() {
- int h = (FOCUS*height() - content_y) / widg->row_size() * widg->columns();
- return qMax(h, 0);
-}
-
-// This verifies that we are not scrolled too far away down or up and that we have enought height
-// We make 10% of height as buffer zone with fixed minimum in pixels
-void MemoryView::Frame::check_update() {
- int hpart = qMax(height()/10, MIN_OFF);
- int req_height = height() + 2*hpart;
-
- if ((content_y < -hpart) && (content_y > -2*hpart) && (widg->height() >= req_height))
- return;
-
- int row_h = widg->row_size();
- // Calculate how many we need and how much we need to move and update content accordingly
- int count = (req_height / row_h) + 1;
- int shift = (content_y + hpart + hpart/2)/row_h;
- mv->update_content(count * widg->columns(), shift * widg->columns());
- // Move and resize widget
- content_y -= shift * row_h;
- widg->setGeometry(0, content_y, width(), count * row_h);
-
- mv->edit_load_focus();
-}
-
-void MemoryView::Frame::resizeEvent(QResizeEvent *e) {
- QAbstractScrollArea::resizeEvent(e);
- widg->setGeometry(0, content_y, e->size().width(), widg->heightForWidth(e->size().width()));
- check_update();
-}
-
-void MemoryView::Frame::wheelEvent(QWheelEvent *e) {
- QPoint pix = e->pixelDelta();
- QPoint ang = e->angleDelta();
-
- if (!pix.isNull())
- content_y += pix.ry();
- else if (!ang.isNull())
- content_y += ang.ry() * ANGLE_SCROLL;
-
- // TODO smooth scroll
- viewport()->move(0, content_y);
- viewport()->repaint(0, content_y, width(), height());
-
- check_update();
-}
-
-bool MemoryView::Frame::viewportEvent(QEvent *e) {
- bool p = QAbstractScrollArea::viewportEvent(e);
- // Pass paint event to viewport widget
- if (e->type() == QEvent::Paint)
- p = false;
- return p;
-}
diff --git a/qtmips_gui/memoryview.h b/qtmips_gui/memoryview.h
deleted file mode 100644
index f60ac53..0000000
--- a/qtmips_gui/memoryview.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*******************************************************************************
- * QtMips - MIPS 32-bit Architecture Subset Simulator
- *
- * Implemented to support following courses:
- *
- * B35APO - Computer Architectures
- * https://cw.fel.cvut.cz/wiki/courses/b35apo
- *
- * B4M35PAP - Advanced Computer Architectures
- * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
- *
- * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
- * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *
- * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
- * Czech Technical University (http://www.cvut.cz/)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- ******************************************************************************/
-
-#ifndef MEMORYVIEW_H
-#define MEMORYVIEW_H
-
-#include <QWidget>
-#include <QAbstractScrollArea>
-#include <QBoxLayout>
-#include <QGridLayout>
-#include <QLineEdit>
-#include <QToolButton>
-#include <QList>
-#include <QVector>
-#include <cstdint>
-#include <QResizeEvent>
-#include "qtmipsmachine.h"
-#include "statictable.h"
-
-class MemoryView : public QWidget {
- Q_OBJECT
-public:
- MemoryView(QWidget *parent = nullptr, std::uint32_t addr0 = 0);
-
- virtual void setup(machine::QtMipsMachine*);
-
- void set_focus(std::uint32_t address);
- std::uint32_t focus() const;
- std::uint32_t addr0() const;
-
- void edit_load_focus(); // Set current focus to edit field
-
-public slots:
- void check_for_updates();
-
-protected:
- const machine::Memory *memory;
- const machine::Cache *cache_data;
-
- virtual QList<QWidget*> row_widget(std::uint32_t address, QWidget *parent) = 0;
-
- QVBoxLayout *layout;
-
- void reload_content(); // reload displayed data
- void update_content(int count, int shift); // update content to match given count and shift
-
- virtual void addr0_save_change(std::uint32_t val);
-
-private slots:
- void go_edit_finish();
-
-private:
- std::uint32_t change_counter;
- std::uint32_t cache_data_change_counter;
- unsigned count;
- std::uint32_t addr_0; // First address in view
-
- class Frame : public QAbstractScrollArea {
- public:
- Frame(MemoryView *parent);
-
- StaticTable *widg;
- void focus(unsigned i); // Focus on given item in widget
- unsigned focussed(); // What item is in focus
- void check_update(); // Update widget size and content if needed
-
- protected:
- MemoryView *mv;
- int content_y;
-
- bool viewportEvent(QEvent*);
- void resizeEvent(QResizeEvent*);
- void wheelEvent(QWheelEvent *event);
- };
- Frame *memf;
-
- QWidget *ctl_widg;
- QLineEdit *go_edit;
-};
-
-#endif // MEMORYVIEW_H
diff --git a/qtmips_gui/programdock.cpp b/qtmips_gui/programdock.cpp
index 4c379eb..39a3f77 100644
--- a/qtmips_gui/programdock.cpp
+++ b/qtmips_gui/programdock.cpp
@@ -33,114 +33,56 @@
*
******************************************************************************/
+#include <QWidget>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QTableView>
+#include <QComboBox>
+#include <QHeaderView>
#include "programdock.h"
-#include "qtmipsexception.h"
+#include "programmodel.h"
+#include "programtableview.h"
+#include "hexlineedit.h"
-ProgramView::ProgramView(QWidget *parent, QSettings *settings) : MemoryView(parent, settings->value("ProgramViewAddr0", 0x8001FF80).toULongLong()) {
- this->settings = settings;
- /*
- cb_single = new QComboBox(this);
- cb_single->addItems({
- "Don't follow",
- "Follow executing instruction"
- });
- cb_single->setCurrentIndex(1);
- cb_single->hide();
- layout->addWidget(cb_single);
- connect(cb_single, SIGNAL(currentIndexChanged(int)), this, SLOT(cb_single_changed(int)));
- cb_pipelined = new QComboBox(this);
- cb_pipelined->addItems({
- "Don't follow",
- "Follow Instruction fetch stage",
- "Follow Instruction decode stage",
- "Follow Execution stage",
- "Follow Memory access stage",
- "Follow Registers write back stage",
- });
- cb_pipelined->hide();
- cb_pipelined->setCurrentIndex(1);
- layout->addWidget(cb_pipelined);
- connect(cb_pipelined, SIGNAL(currentIndexChanged(int)), this, SLOT(cb_pipelined_changed(int)));
- */
-}
-
-void ProgramView::setup(machine::QtMipsMachine *machine) {
- MemoryView::setup(machine);
- if (machine == nullptr)
- return;
- /*
- bool pipelined = machine->config().pipelined();
- cb_single->setVisible(!pipelined);
- cb_pipelined->setVisible(pipelined);
- // Sync selection somewhat
- if (pipelined) {
- if (cb_single->currentIndex() == 0)
- cb_pipelined->setCurrentIndex(0);
- else if (cb_pipelined->currentIndex() == 0)
- cb_pipelined->setCurrentIndex(1);
- } else
- cb_single->setCurrentIndex(cb_pipelined->currentIndex() == 0 ? 0 : 1);
- // TODO connect to instructuion hooks
- */
-}
-
-void ProgramView::jump_to_pc(std::uint32_t addr) {
- set_focus(addr);
-}
-
-QList<QWidget*> ProgramView::row_widget(std::uint32_t address, QWidget *parent) {
- QList<QWidget*> widgs;
- QLabel *l;
-
- QFont f;
- f.setStyleHint(QFont::Monospace);
-
- l = new QLabel(" ", parent);
- l->setFont(f);
- widgs.append(l);
+ProgramDock::ProgramDock(QWidget *parent, QSettings *settings) : Super(parent) {
+ setObjectName("Program");
+ setWindowTitle("Program");
- l = new QLabel(QString("0x") + QString("%1").arg(address, 8, 16, QChar('0')).toUpper(), parent);
- l->setTextInteractionFlags(Qt::TextSelectableByMouse);
- l->setFont(f);
- widgs.append(l);
+ QWidget *content = new QWidget();
- l = new QLabel(parent);
- l->setTextInteractionFlags(Qt::TextSelectableByMouse);
- l->setFont(f);
- l->setMinimumWidth(60);
- if (memory != nullptr)
- l->setText(machine::Instruction(memory->read_word(address)).to_str(address));
- widgs.append(l);
+ QComboBox *follow_inst = new QComboBox();
+ follow_inst->addItem("Follow - none");
+ follow_inst->addItem("Follow - fetch");
- return widgs;
-}
+ QTableView *program_content = new ProgramTableView(0, settings);
+ // program_content->setSizePolicy();
+ ProgramModel *program_model = new ProgramModel(0);
+ program_content->setModel(program_model);
+ program_content->verticalHeader()->hide();
+ //program_content->setHorizontalHeader(program_model->);
-void ProgramView::addr0_save_change(std::uint32_t val) {
- settings->setValue("ProgramViewAddr0", val);
-}
+ QLineEdit *go_edit = new HexLineEdit(0, 8, 16, "0x");
-void ProgramView::cb_single_changed(int index) {
- // TODO set memory view
-}
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(follow_inst);
+ layout->addWidget(program_content);
+ layout->addWidget(go_edit);
-void ProgramView::cb_pipelined_changed(int index) {
- // TODO set memory view
-}
+ content->setLayout(layout);
-ProgramDock::ProgramDock(QWidget *parent, QSettings *settings) : QDockWidget(parent) {
- view = new ProgramView(this, settings);
- setWidget(view);
+ setWidget(content);
- setObjectName("Program");
- setWindowTitle("Program");
+ connect(this, &ProgramDock::machine_setup, program_model, &ProgramModel::setup);
+ connect(go_edit, SIGNAL(value_edit_finished(std::uint32_t)),
+ program_content, SLOT(go_to_address(std::uint32_t)));
+ connect(program_content, SIGNAL(address_changed(std::uint32_t)),
+ go_edit, SLOT(set_value(std::uint32_t)));
+ connect(this, SIGNAL(jump_to_pc(std::uint32_t)),
+ program_content, SLOT(go_to_address(std::uint32_t)));
}
void ProgramDock::setup(machine::QtMipsMachine *machine) {
- view->setup(machine);
-}
-
-void ProgramDock::jump_to_pc(std::uint32_t addr) {
- view->jump_to_pc(addr);
+ emit machine_setup(machine);
}
diff --git a/qtmips_gui/programdock.h b/qtmips_gui/programdock.h
index 8a9e4b1..10b9df1 100644
--- a/qtmips_gui/programdock.h
+++ b/qtmips_gui/programdock.h
@@ -37,49 +37,26 @@
#define PROGRAMDOCK_H
#include <QDockWidget>
-#include <QBoxLayout>
-#include <QComboBox>
#include <QLabel>
-#include <QLineEdit>
+#include <QComboBox>
#include "qtmipsmachine.h"
-#include "memoryview.h"
-class ProgramView : public MemoryView {
+class ProgramDock : public QDockWidget {
Q_OBJECT
-public:
- ProgramView(QWidget *parent, QSettings *settings);
-
- void setup(machine::QtMipsMachine*);
-
- void jump_to_pc(std::uint32_t);
-
-protected:
- QList<QWidget*> row_widget(std::uint32_t address, QWidget *parent);
- void addr0_save_change(std::uint32_t val);
+ using Super = QDockWidget;
-private slots:
- void cb_single_changed(int index);
- void cb_pipelined_changed(int index);
-
-private:
- QComboBox *cb_single;
- QComboBox *cb_pipelined;
- QSettings *settings;
-};
-
-class ProgramDock : public QDockWidget {
- Q_OBJECT
public:
ProgramDock(QWidget *parent, QSettings *settings);
void setup(machine::QtMipsMachine *machine);
-public slots:
+signals:
+ void machine_setup(machine::QtMipsMachine *machine);
void jump_to_pc(std::uint32_t);
private:
- ProgramView *view;
+
};
#endif // PROGRAMDOCK_H
diff --git a/qtmips_gui/programmodel.cpp b/qtmips_gui/programmodel.cpp
new file mode 100644
index 0000000..5387058
--- /dev/null
+++ b/qtmips_gui/programmodel.cpp
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#include <QBrush>
+
+#include "programmodel.h"
+
+ProgramModel::ProgramModel(QObject *parent)
+ : Super(parent), data_font("Monospace") {
+ index0_offset = 0;
+ data_font.setStyleHint(QFont::TypeWriter);
+ machine = nullptr;
+ memory_change_counter = 0;
+ cache_program_change_counter = 0;
+}
+
+int ProgramModel::rowCount(const QModelIndex & /*parent*/) const {
+ return 750;
+}
+
+int ProgramModel::columnCount(const QModelIndex & /*parent*/) const {
+ return 4;
+}
+
+QVariant ProgramModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal) {
+ if(role == Qt::DisplayRole) {
+ switch (section) {
+ case 0:
+ return tr("Bp");
+ case 1:
+ return tr("Address");
+ case 2:
+ return tr("Code");
+ case 3:
+ return tr("Instruction");
+ default:
+ return tr("");
+ }
+ }
+ }
+ return Super::headerData(section, orientation, role);
+}
+
+QVariant ProgramModel::data(const QModelIndex &index, int role) const {
+ if (role == Qt::DisplayRole)
+ {
+ QString s, t;
+ std::uint32_t address;
+ std::uint32_t data;
+ if (!get_row_address(address, index.row()))
+ return QString("");
+
+ if (index.column() == 1) {
+ t = QString::number(address, 16);
+ s.fill('0', 8 - t.count());
+ return "0x" + s + t.toUpper();
+ }
+
+ if (machine == nullptr)
+ return QString(" ");
+ if (machine->memory() == nullptr)
+ return QString(" ");
+
+ machine::Instruction inst(machine->memory()->read_word(address));
+
+ switch (index.column()) {
+ case 0:
+ return QString(" ");
+ case 2:
+ t = QString::number(inst.data(), 16);
+ s.fill('0', 8 - t.count());
+ return s + t.toUpper();
+ case 3: return inst.to_str(address);
+ default: return tr("");
+ }
+ }
+ if (role == Qt::BackgroundRole) {
+ std::uint32_t address;
+ if (!get_row_address(address, index.row()) ||
+ machine == nullptr || index.column() != 2)
+ return QVariant();
+ if (machine->cache_program() != nullptr) {
+ machine::LocationStatus loc_stat;
+ loc_stat = machine->cache_program()->location_status(address);
+ if (loc_stat & machine::LOCSTAT_CACHED) {
+ QBrush bgd(Qt::lightGray);
+ return bgd;
+ }
+ }
+ return QVariant();
+ }
+ if (role==Qt::FontRole)
+ return data_font;
+ return QVariant();
+}
+
+void ProgramModel::setup(machine::QtMipsMachine *machine) {
+ this->machine = machine;
+ if (machine != nullptr)
+ connect(machine, SIGNAL(post_tick()), this, SLOT(check_for_updates()));
+ emit update_all();
+}
+
+void ProgramModel::update_all() {
+ if (machine != nullptr && machine->memory() != nullptr) {
+ memory_change_counter = machine->memory()->get_change_counter();
+ if (machine->cache_program() != nullptr)
+ cache_program_change_counter = machine->cache_program()->get_change_counter();
+ }
+ emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
+}
+
+void ProgramModel::check_for_updates() {
+ bool need_update = false;
+ if (machine == nullptr)
+ return;
+ if (machine->memory() == nullptr)
+ return;
+
+ if (memory_change_counter != machine->memory()->get_change_counter())
+ need_update = true;
+ if (machine->cache_data() != nullptr) {
+ if (cache_program_change_counter != machine->cache_program()->get_change_counter())
+ need_update = true;
+ }
+ if (!need_update)
+ return;
+ update_all();
+}
+
+bool ProgramModel::adjustRowAndOffset(int &row, int optimal_row, std::uint32_t address) {
+ if (optimal_row < rowCount() / 8)
+ optimal_row = rowCount() / 8;
+ if (optimal_row >= rowCount() - rowCount() / 8)
+ optimal_row = rowCount() - rowCount() / 8;
+ row = rowCount() / 2;
+ address -= address % cellSizeBytes();
+ std::uint32_t row_bytes = cellSizeBytes();
+ std::uint32_t diff = row * row_bytes;
+ if (diff > address) {
+ row = address / row_bytes;
+ if (row == 0) {
+ index0_offset = 0;
+ } else {
+ index0_offset = address - row * row_bytes;
+ }
+ } else {
+ index0_offset = address - diff;
+ }
+ return get_row_for_address(row, address);
+}
diff --git a/qtmips_gui/programmodel.h b/qtmips_gui/programmodel.h
new file mode 100644
index 0000000..4a17e99
--- /dev/null
+++ b/qtmips_gui/programmodel.h
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#ifndef PROGRAMMODEL_H
+#define PROGRAMMODEL_H
+
+#include <QAbstractTableModel>
+#include <QFont>
+#include "qtmipsmachine.h"
+
+class ProgramModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+ using Super = QAbstractTableModel;
+public:
+ ProgramModel(QObject *parent);
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override ;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool adjustRowAndOffset(int &row, int optimal_row, std::uint32_t address);
+ void update_all();
+
+ inline const QFont *getFont() const {
+ return &data_font;
+ }
+
+ inline std::uint32_t getIndex0Offset() const {
+ return index0_offset;
+ }
+
+ inline unsigned int cellSizeBytes() const {
+ return 4;
+ }
+ inline bool get_row_address(std::uint32_t &address, int row) const {
+ address = index0_offset + row * cellSizeBytes();
+ return address >= index0_offset;
+ }
+ inline bool get_row_for_address(int &row, std::uint32_t address) const {
+ if (address < index0_offset) {
+ row = -1;
+ return false;
+ }
+ row = (address - index0_offset) / cellSizeBytes();
+ if ((address - index0_offset > 0x80000000) || row > rowCount()) {
+ row = rowCount();
+ return false;
+ }
+ return true;
+ }
+
+public slots:
+ void setup(machine::QtMipsMachine *machine);
+ void check_for_updates();
+
+private:
+ std::uint32_t index0_offset;
+ QFont data_font;
+ machine::QtMipsMachine *machine;
+ std::uint32_t memory_change_counter;
+ std::uint32_t cache_program_change_counter;
+};
+
+#endif // PROGRAMMODEL_H
diff --git a/qtmips_gui/programtableview.cpp b/qtmips_gui/programtableview.cpp
new file mode 100644
index 0000000..34a119a
--- /dev/null
+++ b/qtmips_gui/programtableview.cpp
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#include <QHeaderView>
+#include <QFontMetrics>
+#include <QScrollBar>
+#include "programtableview.h"
+#include "programmodel.h"
+
+ProgramTableView::ProgramTableView(QWidget *parent, QSettings *settings) : Super(parent) {
+ connect(verticalScrollBar() , SIGNAL(valueChanged(int)),
+ this, SLOT(adjust_scroll_pos()));
+ this->settings = settings;
+ initial_address = settings->value("ProgramViewAddr0", 0).toULongLong();
+}
+
+void ProgramTableView::addr0_save_change(std::uint32_t val) {
+ settings->setValue("ProgramViewAddr0", val);
+}
+
+void ProgramTableView::adjustColumnCount() {
+ int cwidth;
+ int totwidth;
+ ProgramModel *m = dynamic_cast<ProgramModel*>(model());
+
+ if (m == nullptr)
+ return;
+
+ QFontMetrics fm(*m->getFont());
+ cwidth = fm.width("Bp");
+ totwidth = cwidth;
+ horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
+ horizontalHeader()->resizeSection(0, cwidth);
+ cwidth = fm.width("0x00000000");
+ totwidth += cwidth;
+ horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
+ horizontalHeader()->resizeSection(1, cwidth);
+ totwidth += cwidth;
+ cwidth = fm.width("00000000");
+ horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
+ horizontalHeader()->resizeSection(2, cwidth);
+ horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
+ totwidth += fm.width("BEQ $18, $17, 0x80020058");
+ totwidth += verticalHeader()->width();
+ setColumnHidden(2, totwidth > width());
+
+ if (initial_address != 0) {
+ go_to_address(initial_address);
+ initial_address = 0;
+ }
+}
+
+
+void ProgramTableView:: adjust_scroll_pos() {
+ std::uint32_t address;
+ ProgramModel *m = dynamic_cast<ProgramModel*>(model());
+ if (m == nullptr)
+ return;
+
+ QModelIndex prev_index = currentIndex();
+ std::uint32_t row_bytes = m->cellSizeBytes();
+ std::uint32_t index0_offset = m->getIndex0Offset();
+
+ do {
+ int row = rowAt(0);
+ int prev_row = row;
+ if (row < m->rowCount() / 8) {
+ if ((row == 0) && (index0_offset < row_bytes) && (index0_offset != 0)) {
+ m->adjustRowAndOffset(row, 0, 0);
+ } else if (index0_offset > row_bytes) {
+ m->get_row_address(address, row);
+ m->adjustRowAndOffset(row, m->rowCount() / 7, address);
+ } else {
+ break;
+ }
+ } else if (row > m->rowCount() - m->rowCount() / 8) {
+ m->get_row_address(address, row);
+ m->adjustRowAndOffset(row, m->rowCount() - m->rowCount() / 7, address);
+ } else {
+ break;
+ }
+ scrollTo(m->index(row, 0), QAbstractItemView::PositionAtTop);
+ setCurrentIndex(m->index(prev_index.row() + row - prev_row,
+ prev_index.column()));
+ emit m->update_all();
+ } while(0);
+ m->get_row_address(address, rowAt(0));
+ addr0_save_change(address);
+ emit address_changed(address);
+}
+
+void ProgramTableView::resizeEvent(QResizeEvent *event) {
+ ProgramModel *m = dynamic_cast<ProgramModel*>(model());
+ std::uint32_t address;
+ bool keep_row0 = false;
+
+ if (m != nullptr) {
+ if (initial_address == 0) {
+ keep_row0 = m->get_row_address(address, rowAt(0));
+ } else {
+ address = initial_address;
+ }
+ }
+ Super::resizeEvent(event);
+ adjustColumnCount();
+ if (keep_row0) {
+ initial_address = 0;
+ go_to_address(address);
+ }
+}
+
+void ProgramTableView:: go_to_address(std::uint32_t address) {
+ ProgramModel *m = dynamic_cast<ProgramModel*>(model());
+ int row;
+ if (m == nullptr)
+ return;
+ m->adjustRowAndOffset(row, m->rowCount() / 2, address);
+ scrollTo(m->index(row, 0),
+ QAbstractItemView::PositionAtTop);
+ setCurrentIndex(m->index(row, 1));
+ addr0_save_change(address);
+ emit m->update_all();
+}
diff --git a/qtmips_gui/programtableview.h b/qtmips_gui/programtableview.h
new file mode 100644
index 0000000..b24c47d
--- /dev/null
+++ b/qtmips_gui/programtableview.h
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#ifndef PROGRAMTABLEVIEW_H
+#define PROGRAMTABLEVIEW_H
+
+#include <QObject>
+#include <QSettings>
+#include <QTableView>
+#include <QSharedPointer>
+
+class ProgramTableView : public QTableView
+{
+ Q_OBJECT
+
+ using Super = QTableView;
+
+public:
+ ProgramTableView(QWidget *parent, QSettings *settings);
+
+ void resizeEvent(QResizeEvent *event) override;
+signals:
+ void address_changed(std::uint32_t address);
+public slots:
+ void go_to_address(std::uint32_t address);
+private slots:
+ void adjust_scroll_pos();
+private:
+ void addr0_save_change(std::uint32_t val);
+ void adjustColumnCount();
+ QSettings *settings;
+
+ std::uint32_t initial_address;
+};
+
+#endif // PROGRAMTABLEVIEW_H
diff --git a/qtmips_gui/qtmips_gui.pro b/qtmips_gui/qtmips_gui.pro
index 05aa784..e3a3890 100644
--- a/qtmips_gui/qtmips_gui.pro
+++ b/qtmips_gui/qtmips_gui.pro
@@ -28,7 +28,6 @@ SOURCES += \
registersdock.cpp \
programdock.cpp \
memorydock.cpp \
- memoryview.cpp \
coreview/programcounter.cpp \
coreview/multiplexer.cpp \
coreview/connection.cpp \
@@ -49,7 +48,9 @@ SOURCES += \
coreview/value.cpp \
memorymodel.cpp \
memorytableview.cpp \
- hexlineedit.cpp
+ hexlineedit.cpp \
+ programmodel.cpp \
+ programtableview.cpp
HEADERS += \
mainwindow.h \
@@ -58,7 +59,6 @@ HEADERS += \
registersdock.h \
programdock.h \
memorydock.h \
- memoryview.h \
coreview/programcounter.h \
coreview/multiplexer.h \
coreview/connection.h \
@@ -79,7 +79,9 @@ HEADERS += \
coreview/value.h \
memorymodel.h \
memorytableview.h \
- hexlineedit.h
+ hexlineedit.h \
+ programmodel.h \
+ programtableview.h
FORMS += \
NewDialog.ui \