From 95956a7457a1237385a314212c4e106bed88f05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 17 Apr 2018 12:44:44 +0200 Subject: Initial implementation of cache view It needs some more work to look nice but it already works. --- qtmips_gui/cachedock.cpp | 17 +++++-- qtmips_gui/cachedock.h | 4 ++ qtmips_gui/cacheview.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++++ qtmips_gui/cacheview.h | 39 +++++++++++++++ qtmips_gui/mainwindow.cpp | 4 +- qtmips_gui/qtmips_gui.pro | 2 + qtmips_machine/cache.cpp | 25 ++++++---- qtmips_machine/cache.h | 4 +- 8 files changed, 196 insertions(+), 17 deletions(-) create mode 100644 qtmips_gui/cacheview.cpp create mode 100644 qtmips_gui/cacheview.h 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 #include #include +#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 +#include +#include +#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; }; -- cgit v1.2.3