Initial commit for cache simulation and visualization
MODIFY
external/VSRTL
external/VSRTL
-Subproject commit dd3ed69c5552a7dbb86f97c5b675dcd377db795e
+Subproject commit 7b45b1fa4f5bd667202efb1655a047a4eaf8ecbb

ADD
src/cachebase.cpp
+#include "cachebase.h"
+
+namespace Ripes {}

ADD
src/cachebase.h
+#pragma once
+
+#include <math.h>
+#include <map>
+#include <vector>
+
+#include <QObject>
+
+namespace Ripes {
+
+class CacheBase : public QObject {
+ Q_OBJECT
+public:
+ struct CacheLine {
+ uint32_t tag;
+ std::vector<uint32_t> blocks;
+ bool hasDirty = false;
+ bool hasValid = true;
+ };
+ using CacheSet = std::map<unsigned, CacheLine>;
+
+ CacheBase(QObject* parent) : QObject(parent) {}
+
+ void read(uint32_t address);
+ void write(uint32_t address);
+ void undo();
+
+ int getSizeInBits();
+
+ int getBlockBits() const { return m_blocks; }
+ int getSetBits() const { return m_sets; }
+ int getLineBits() const { return m_lines; }
+
+ int getBlocks() const { return static_cast<int>(std::pow(2, m_blocks)); }
+ int getSets() const { return static_cast<int>(std::pow(2, m_sets)); }
+ int getLines() const { return static_cast<int>(std::pow(2, m_lines)); }
+
+public slots:
+ void setBlocks(unsigned blocks) {
+ m_blocks = blocks;
+ emit parametersChanged();
+ }
+ void setLines(unsigned lines) {
+ m_lines = lines;
+ emit parametersChanged();
+ }
+ void setSets(unsigned sets) {
+ m_sets = sets;
+ emit parametersChanged();
+ }
+
+signals:
+ void parametersChanged();
+
+private:
+ int m_blocks = 1; // Some power of 2
+ int m_lines = 4; // Some power of 2
+ int m_sets = 0; // Some power of 2
+
+ std::map<unsigned, CacheSet> m_cacheSets;
+};
+
+} // namespace Ripes

ADD
src/cacheconfigwidget.cpp
+#include "cacheconfigwidget.h"
+#include "ui_cacheconfigwidget.h"
+
+#include <QSpinBox>
+
+namespace Ripes {
+
+CacheConfigWidget::CacheConfigWidget(QWidget* parent) : QWidget(parent), m_ui(new Ui::CacheConfigWidget) {
+ m_ui->setupUi(this);
+}
+
+void CacheConfigWidget::setCache(CacheBase* cache) {
+ m_cache = cache;
+
+ connect(m_ui->sets, QOverload<int>::of(&QSpinBox::valueChanged), m_cache, &CacheBase::setSets);
+ connect(m_ui->blocks, QOverload<int>::of(&QSpinBox::valueChanged), m_cache, &CacheBase::setBlocks);
+ connect(m_ui->lines, QOverload<int>::of(&QSpinBox::valueChanged), m_cache, &CacheBase::setLines);
+
+ m_ui->sets->setValue(m_cache->getSetBits());
+ m_ui->lines->setValue(m_cache->getLineBits());
+ m_ui->blocks->setValue(m_cache->getBlockBits());
+}
+
+CacheConfigWidget::~CacheConfigWidget() {
+ delete m_ui;
+}
+
+} // namespace Ripes

ADD
src/cacheconfigwidget.h
+#pragma once
+
+#include <QWidget>
+#include "cachebase.h"
+
+namespace Ripes {
+
+namespace Ui {
+class CacheConfigWidget;
+}
+
+class CacheConfigWidget : public QWidget {
+ Q_OBJECT
+public:
+ CacheConfigWidget(QWidget* parent);
+ ~CacheConfigWidget() override;
+
+ void setCache(CacheBase* cache);
+
+private:
+ CacheBase* m_cache;
+ Ui::CacheConfigWidget* m_ui = nullptr;
+};
+
+} // namespace Ripes

ADD
src/cacheconfigwidget.ui
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Ripes::CacheConfigWidget</class>
+ <widget class="QWidget" name="Ripes::CacheConfigWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>447</width>
+ <height>187</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Configuration</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="blocks">
+ <property name="maximum">
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="presets"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="sets">
+ <property name="maximum">
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QSpinBox" name="lines">
+ <property name="maximum">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Lines</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Sets</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Preset:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Statistics</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Size (bits):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Hit rate:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="sizeBreakdownButton">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit_2"/>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

ADD
src/cachegraphic.cpp
+#include "cachegraphic.h"
+
+#include <QFontMetrics>
+#include <QGraphicsLineItem>
+#include <QGraphicsSimpleTextItem>
+#include <QPen>
+
+namespace Ripes {
+
+CacheGraphic::CacheGraphic(CacheBase& cache) : QGraphicsObject(nullptr), m_cache(cache) {
+ connect(&cache, &CacheBase::parametersChanged, this, &CacheGraphic::cacheParametersChanged);
+ cacheParametersChanged();
+}
+
+void CacheGraphic::drawText(const QString& text, qreal x, qreal y) {
+ auto* textItem = new QGraphicsSimpleTextItem(text, this);
+ textItem->setFont(m_font);
+ textItem->setPos(x, y);
+}
+
+void CacheGraphic::cacheParametersChanged() {
+ prepareGeometryChange();
+
+ // Remove all items
+ for (const auto& item : childItems())
+ delete item;
+
+ // Determine cell dimensions
+ auto metrics = QFontMetricsF(m_font);
+ const qreal setHeight = metrics.height();
+ const qreal lineHeight = setHeight * m_cache.getSets();
+ const qreal blockWidth = metrics.horizontalAdvance("0xFFFFFFFF");
+ const qreal bitWidth = metrics.horizontalAdvance("0");
+ const qreal cacheHeight = lineHeight * m_cache.getLines();
+ const qreal tagWidth = blockWidth;
+
+ // Draw cache:
+
+ qreal horizontalAdvance = 0;
+ // Draw valid bit column
+ new QGraphicsLineItem(0, 0, 0, cacheHeight, this);
+ new QGraphicsLineItem(bitWidth, 0, bitWidth, cacheHeight, this);
+ const QString validBitText = "V";
+ drawText(validBitText, 0, -metrics.height());
+ horizontalAdvance += bitWidth;
+
+ // Draw tag column
+ new QGraphicsLineItem(tagWidth, 0, tagWidth, cacheHeight, this);
+ const QString tagText = "Tag";
+ drawText(tagText, horizontalAdvance + tagWidth / 2 - metrics.horizontalAdvance(tagText) / 2, -metrics.height());
+ horizontalAdvance += tagWidth;
+
+ // Draw horizontal lines between cache blocks
+ for (int i = 0; i < m_cache.getBlocks(); i++) {
+ const QString blockText = "Block " + QString::number(i);
+ drawText(blockText, horizontalAdvance + tagWidth / 2 - metrics.horizontalAdvance(blockText) / 2,
+ -metrics.height());
+ horizontalAdvance += blockWidth;
+ auto* l3 = new QGraphicsLineItem(horizontalAdvance, 0, horizontalAdvance, cacheHeight, this);
+ }
+
+ // Draw cache line rows
+ for (int i = 0; i <= m_cache.getLines(); i++) {
+ qreal verticalAdvance = i * lineHeight;
+ new QGraphicsLineItem(0, verticalAdvance, horizontalAdvance, verticalAdvance, this);
+
+ if (i < m_cache.getLines()) {
+ // Draw cache set rows
+ for (int j = 1; j < m_cache.getSets(); j++) {
+ verticalAdvance += setHeight;
+ auto* setLine = new QGraphicsLineItem(0, verticalAdvance, horizontalAdvance, verticalAdvance, this);
+ auto pen = setLine->pen();
+ pen.setStyle(Qt::DashLine);
+ setLine->setPen(pen);
+ }
+ }
+ }
+
+ // Draw line index numbers
+ for (int i = 0; i < m_cache.getLines(); i++) {
+ const QString text = QString::number(i);
+
+ const qreal y = i * lineHeight + lineHeight / 2 - setHeight / 2;
+ const qreal x = -metrics.horizontalAdvance(text) * 1.2;
+ drawText(text, x, y);
+ }
+}
+
+} // namespace Ripes

ADD
src/cachegraphic.h
+#pragma once
+
+#include <QFont>
+#include <QGraphicsItem>
+#include <QObject>
+#include "cachebase.h"
+
+namespace Ripes {
+
+class CacheGraphic : public QGraphicsObject {
+public:
+ CacheGraphic(CacheBase& cache);
+
+ QRectF boundingRect() const override {}
+
+ void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override {}
+
+ void lineChanged(uint32_t address, unsigned block);
+
+ /**
+ * @brief cacheParametersChanged
+ * Recalculates and redraws the graphic based on the current cache parameters
+ */
+ void cacheParametersChanged();
+
+private:
+ void drawText(const QString& text, qreal x, qreal y);
+
+ QFont m_font = QFont("Roboto", 12);
+ CacheBase& m_cache;
+};
+
+} // namespace Ripes

MODIFY
src/memorytab.cpp
src/memorytab.cpp
#include "memorytab.h"
#include "ui_memorytab.h"
+#include "cachebase.h"
+#include "cachegraphic.h"
+
+#include <QGraphicsItem>
+#include <QGraphicsScene>
+#include <QGraphicsView>
#include <QToolBar>
namespace Ripes {
@@ -10,6 +16,14 @@ MemoryTab::MemoryTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, par
m_ui->memoryViewerWidget->updateModel();
m_ui->memoryViewerWidget->updateView();
+
+ auto* scene = new QGraphicsScene(this);
+ auto* cacheSim = new CacheBase(this);
+ m_ui->cacheConfig->setCache(cacheSim);
+
+ auto* cacheGraphic = new CacheGraphic(*cacheSim);
+ m_ui->cacheView->setScene(scene);
+ scene->addItem(cacheGraphic);
}
void MemoryTab::update() {

MODIFY
src/memorytab.ui
src/memorytab.ui
</widget>
</item>
<item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
+ <item>
+ <widget class="CacheConfigWidget" name="cacheConfig" native="true"/>
+ </item>
+ <item>
+ <widget class="QGraphicsView" name="cacheView"/>
+ </item>
+ </layout>
</item>
</layout>
</item>
<header>memoryviewerwidget.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>CacheConfigWidget</class>
+ <extends>QWidget</extends>
+ <header>cacheconfigwidget.h</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>

Initial commit for cache simulation and visualization