aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Kočí <cynerd@email.cz>2018-04-17 12:44:44 +0200
committerKarel Kočí <cynerd@email.cz>2018-04-17 12:44:44 +0200
commit95956a7457a1237385a314212c4e106bed88f05d (patch)
tree0ab000468c9e281c0a59fc5991252a87e115d154
parent6c360d8e42053d9045bbe2fc78c23143f8a334b7 (diff)
downloadqtmips-95956a7457a1237385a314212c4e106bed88f05d.tar.gz
qtmips-95956a7457a1237385a314212c4e106bed88f05d.tar.bz2
qtmips-95956a7457a1237385a314212c4e106bed88f05d.zip
Initial implementation of cache view
It needs some more work to look nice but it already works.
-rw-r--r--qtmips_gui/cachedock.cpp17
-rw-r--r--qtmips_gui/cachedock.h4
-rw-r--r--qtmips_gui/cacheview.cpp118
-rw-r--r--qtmips_gui/cacheview.h39
-rw-r--r--qtmips_gui/mainwindow.cpp4
-rw-r--r--qtmips_gui/qtmips_gui.pro2
-rw-r--r--qtmips_machine/cache.cpp25
-rw-r--r--qtmips_machine/cache.h4
8 files changed, 196 insertions, 17 deletions
diff --git a/qtmips_gui/cachedock.cpp b/qtmips_gui/cachedock.cpp
index eb96e06..79097b3 100644
--- a/qtmips_gui/cachedock.cpp
+++ b/qtmips_gui/cachedock.cpp
@@ -18,7 +18,10 @@ CacheDock::CacheDock(QWidget *parent, const QString &type) : QDockWidget(parent)
l_miss = new QLabel("0", top_form);
layout_top_form->addRow("Miss:", l_miss);
- // TODO cache view
+ graphicsview = new GraphicsView(top_widget);
+ graphicsview->setVisible(false);
+ layout_box->addWidget(graphicsview);
+ cachescene = nullptr;
setObjectName(type + "Cache");
setWindowTitle(type + " Cache");
@@ -27,12 +30,18 @@ CacheDock::CacheDock(QWidget *parent, const QString &type) : QDockWidget(parent)
void CacheDock::setup(const machine::Cache *cache) {
l_hit->setText("0");
l_miss->setText("0");
- if (cache) {
+ if (cache->config().enabled()) {
connect(cache, SIGNAL(hit_update(uint)), this, SLOT(hit_update(uint)));
connect(cache, SIGNAL(miss_update(uint)), this, SLOT(miss_update(uint)));
}
- top_form->setVisible((bool)cache);
- no_cache->setVisible(!(bool)cache);
+ top_form->setVisible(cache->config().enabled());
+ no_cache->setVisible(!cache->config().enabled());
+
+ if (cachescene)
+ delete cachescene;
+ cachescene = new CacheViewScene(cache);
+ graphicsview->setScene(cachescene);
+ graphicsview->setVisible(cache->config().enabled());
}
void CacheDock::hit_update(unsigned val) {
diff --git a/qtmips_gui/cachedock.h b/qtmips_gui/cachedock.h
index a13cd08..598a9c7 100644
--- a/qtmips_gui/cachedock.h
+++ b/qtmips_gui/cachedock.h
@@ -4,6 +4,8 @@
#include <QDockWidget>
#include <QLabel>
#include <QFormLayout>
+#include "cacheview.h"
+#include "graphicsview.h"
#include "qtmipsmachine.h"
class CacheDock : public QDockWidget {
@@ -22,6 +24,8 @@ private:
QWidget *top_widget, *top_form;
QFormLayout *layout_top_form;
QLabel *l_hit, *l_miss, *no_cache;
+ GraphicsView *graphicsview;
+ CacheViewScene *cachescene;
};
#endif // CACHEDOCK_H
diff --git a/qtmips_gui/cacheview.cpp b/qtmips_gui/cacheview.cpp
new file mode 100644
index 0000000..8582e63
--- /dev/null
+++ b/qtmips_gui/cacheview.cpp
@@ -0,0 +1,118 @@
+#include "cacheview.h"
+
+//////////////////////
+#define ROW_HEIGHT 14
+#define VD_WIDTH 10
+#define DATA_WIDTH 72
+#define PENW 1
+//////////////////////
+
+CacheViewBlock::CacheViewBlock(const machine::Cache *cache, unsigned block) : QGraphicsObject(nullptr) {
+ this->block = block;
+ rows = cache->config().sets();
+ columns = cache->config().blocks();
+
+ QFont font;
+ font.setPointSize(7);
+
+ validity = new QGraphicsSimpleTextItem*[rows];
+ if (cache->config().write_policy() == machine::MachineConfigCache::WP_BACK)
+ dirty = new QGraphicsSimpleTextItem*[rows];
+ else
+ dirty = nullptr;
+ tag = new QGraphicsSimpleTextItem*[rows];
+ data = new QGraphicsSimpleTextItem**[rows];
+ int row_y = 1;
+ for (unsigned i = 0; i < rows; i++) {
+ int row_x = 2;
+ validity[i] = new QGraphicsSimpleTextItem("0", this);
+ validity[i]->setPos(row_x, row_y);
+ validity[i]->setFont(font);
+ row_x += VD_WIDTH;
+ if (dirty) {
+ dirty[i] = new QGraphicsSimpleTextItem(this);
+ dirty[i]->setPos(row_x, row_y);
+ dirty[i]->setFont(font);
+ row_x += VD_WIDTH;
+ }
+ tag[i] = new QGraphicsSimpleTextItem(this);
+ tag[i]->setPos(row_x, row_y);
+ tag[i]->setFont(font);
+ row_x += DATA_WIDTH;
+
+ data[i] = new QGraphicsSimpleTextItem*[columns];
+ for (unsigned y = 0; y < columns; y++) {
+ data[i][y] = new QGraphicsSimpleTextItem(this);
+ data[i][y]->setPos(row_x, row_y);
+ data[i][y]->setFont(font);
+ row_x += DATA_WIDTH;
+ }
+
+ row_y += ROW_HEIGHT;
+ }
+
+ connect(cache, SIGNAL(cache_update(uint,uint,bool,bool,std::uint32_t,const std::uint32_t*)), this, SLOT(cache_update(uint,uint,bool,bool,std::uint32_t,const std::uint32_t*)));
+}
+
+CacheViewBlock::~CacheViewBlock() {
+ delete validity;
+ delete dirty;
+ delete tag;
+ for (unsigned y = 0; y < rows; y++)
+ delete data[y];
+ delete data;
+}
+
+QRectF CacheViewBlock::boundingRect() const {
+ return QRectF(
+ -PENW / 2,
+ -PENW / 2,
+ VD_WIDTH + (dirty ? VD_WIDTH : 0) + DATA_WIDTH*(columns+1) + PENW,
+ ROW_HEIGHT*rows + PENW
+ );
+}
+
+void CacheViewBlock::paint(QPainter *painter, const QStyleOptionGraphicsItem *option __attribute__((unused)), QWidget *widget __attribute__((unused))) {
+ // Draw horizontal lines
+ for (unsigned i = 0; i <= rows; i++)
+ painter->drawLine(0, i * ROW_HEIGHT, VD_WIDTH + (dirty ? VD_WIDTH : 0) + DATA_WIDTH*(columns + 1), i * ROW_HEIGHT);
+ // Draw vertical lines
+ painter->drawLine(0, 0, 0, rows*ROW_HEIGHT);
+ int c_width = VD_WIDTH;
+ painter->drawLine(c_width, 0, c_width, rows*ROW_HEIGHT);
+ if (dirty) {
+ c_width += VD_WIDTH;
+ painter->drawLine(c_width, 0, c_width, rows*ROW_HEIGHT);
+ }
+ c_width += DATA_WIDTH;
+ painter->drawLine(c_width, 0, c_width, rows*ROW_HEIGHT);
+ for (unsigned i = 0; i <= columns; i++) {
+ c_width += DATA_WIDTH;
+ painter->drawLine(c_width, 0, c_width, rows*ROW_HEIGHT);
+ }
+}
+
+void CacheViewBlock::cache_update(unsigned associat, unsigned set, bool valid, bool dirty, std::uint32_t tag, const std::uint32_t *data) {
+ if (associat != block)
+ return; // Ignore blocks that are not us
+ validity[set]->setText(valid ? "1" : "0");
+ if (this->dirty)
+ this->dirty[set]->setText(valid ? (dirty ? "1" : "0") : "");
+ // TODO calculate correct size of tag
+ this->tag[set]->setText(valid ? QString("0x") + QString("%1").arg(tag, 8, 16, QChar('0')).toUpper() : "");
+ for (unsigned i = 0; i < columns; i++)
+ this->data[set][i]->setText(valid ? QString("0x") + QString("%1").arg(data[i], 8, 16, QChar('0')).toUpper() : "");
+}
+
+
+CacheViewScene::CacheViewScene(const machine::Cache *cache) {
+ associativity = cache->config().associativity();
+ block = new CacheViewBlock*[associativity];
+ int offset = 0;
+ for (unsigned i = 0; i < associativity; i++) {
+ block[i] = new CacheViewBlock(cache, i);
+ addItem(block[i]);
+ block[i]->setPos(1, offset);
+ offset += block[i]->boundingRect().height() + 3;
+ }
+}
diff --git a/qtmips_gui/cacheview.h b/qtmips_gui/cacheview.h
new file mode 100644
index 0000000..1fb224f
--- /dev/null
+++ b/qtmips_gui/cacheview.h
@@ -0,0 +1,39 @@
+#ifndef CACHEVIEW_H
+#define CACHEVIEW_H
+
+#include <QGraphicsView>
+#include <QGraphicsScene>
+#include <QGraphicsObject>
+#include "graphicsview.h"
+#include "qtmipsmachine.h"
+
+class CacheViewBlock : public QGraphicsObject {
+ Q_OBJECT
+public:
+ CacheViewBlock(const machine::Cache *cache, unsigned block);
+ ~CacheViewBlock();
+
+ QRectF boundingRect() const;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+
+private slots:
+ void cache_update(unsigned associat, unsigned set, bool valid, bool dirty, std::uint32_t tag, const std::uint32_t *data);
+
+private:
+ unsigned block;
+ unsigned rows, columns;
+ QGraphicsSimpleTextItem **validity, **dirty, **tag, ***data;
+};
+
+class CacheViewScene : public QGraphicsScene {
+ Q_OBJECT
+public:
+ CacheViewScene(const machine::Cache *cache);
+
+private:
+ unsigned associativity;
+ CacheViewBlock **block;
+};
+
+#endif // CACHEVIEW_H
diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp
index d3434bc..4fb9cbf 100644
--- a/qtmips_gui/mainwindow.cpp
+++ b/qtmips_gui/mainwindow.cpp
@@ -118,8 +118,8 @@ void MainWindow::create_core(const machine::MachineConfig &config) {
registers->setup(machine);
program->setup(machine);
memory->setup(machine);
- cache_program->setup(machine->config().cache_program().enabled() ? machine->cache_program() : nullptr);
- cache_data->setup(machine->config().cache_data().enabled() ? machine->cache_data() : nullptr);
+ cache_program->setup(machine->cache_program());
+ cache_data->setup(machine->cache_data());
// Set status to ready
machine_status(machine::QtMipsMachine::ST_READY);
}
diff --git a/qtmips_gui/qtmips_gui.pro b/qtmips_gui/qtmips_gui.pro
index e12eaef..eb5f392 100644
--- a/qtmips_gui/qtmips_gui.pro
+++ b/qtmips_gui/qtmips_gui.pro
@@ -36,6 +36,7 @@ SOURCES += \
coreview/logicblock.cpp \
coreview/and.cpp \
statictable.cpp \
+ cacheview.cpp \
cachedock.cpp \
graphicsview.cpp
@@ -61,6 +62,7 @@ HEADERS += \
coreview/logicblock.h \
coreview/and.h \
statictable.h \
+ cacheview.h \
cachedock.h \
graphicsview.h
diff --git a/qtmips_machine/cache.cpp b/qtmips_machine/cache.cpp
index d8c1fff..753027a 100644
--- a/qtmips_machine/cache.cpp
+++ b/qtmips_machine/cache.cpp
@@ -42,9 +42,8 @@ void Cache::wword(std::uint32_t address, std::uint32_t value) {
return;
}
- std::uint32_t *data;
- access(address, &data, false);
- *data = value;
+ std::uint32_t data;
+ access(address, &data, true, value);
if (cnf.write_policy() == MachineConfigCache::WP_TROUGH)
mem->wword(address, value);
@@ -54,9 +53,9 @@ std::uint32_t Cache::rword(std::uint32_t address) const {
if (!cnf.enabled())
return mem->read_word(address);
- std::uint32_t *data;
- access(address, &data, true);
- return *data;
+ std::uint32_t data;
+ access(address, &data, false);
+ return data;
}
void Cache::flush() {
@@ -96,13 +95,16 @@ void Cache::reset() {
// Trigger signals
emit hit_update(hitc);
emit miss_update(missc);
+ for (unsigned as = 0; as < cnf.associativity(); as++)
+ for (unsigned st = 0; st < cnf.sets(); st++)
+ emit cache_update(as, st, false, false, 0, 0);
}
const MachineConfigCache &Cache::config() const {
return cnf;
}
-void Cache::access(std::uint32_t address, std::uint32_t **data, bool read) const {
+void Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std::uint32_t value) const {
address = address >> 2;
unsigned ssize = cnf.blocks() * cnf.sets();
std::uint32_t tag = address / ssize;
@@ -177,9 +179,14 @@ void Cache::access(std::uint32_t address, std::uint32_t **data, bool read) const
}
cd.valid = true; // We either write to it or we read from memory. Either way it's valid when we leave Cache class
- cd.dirty = cd.dirty || !read;
+ cd.dirty = cd.dirty || !write;
cd.tag = tag;
- *data = &cd.data[col];
+ *data = cd.data[col];
+
+ if (write)
+ cd.data[col] = value;
+
+ emit cache_update(indx, row, cd.valid, cd.dirty, cd.tag, cd.data);
}
void Cache::kick(unsigned associat_indx, unsigned row) const {
diff --git a/qtmips_machine/cache.h b/qtmips_machine/cache.h
index 8321bbf..d7bd967 100644
--- a/qtmips_machine/cache.h
+++ b/qtmips_machine/cache.h
@@ -25,11 +25,11 @@ public:
void reset(); // Reset whole state of cache
const MachineConfigCache &config() const;
- // TODO getters for cells
signals:
void hit_update(unsigned) const;
void miss_update(unsigned) const;
+ void cache_update(unsigned associat, unsigned set, bool valid, bool dirty, std::uint32_t tag, const std::uint32_t *data) const;
private:
MachineConfigCache cnf;
@@ -49,7 +49,7 @@ private:
mutable unsigned hitc, missc; // Hit and miss counters
- void access(std::uint32_t address, std::uint32_t **data, bool read) const;
+ void access(std::uint32_t address, std::uint32_t *data, bool write, std::uint32_t value = 0) const;
void kick(unsigned associat_indx, unsigned row) const;
std::uint32_t base_address(std::uint32_t tag, unsigned row) const;
};