Add reading from main memory
MODIFY
src/cachebase.cpp
src/cachebase.cpp
#include "cachebase.h"
+#include "binutils.h"
-namespace Ripes {}
+#include <random>
+
+namespace Ripes {
+
+void CacheBase::updateCacheValue(uint32_t address, uint32_t value) {
+ const unsigned lineIdx = getAccessLineIdx();
+ const unsigned blockIdx = getAccessBlockIdx();
+
+ auto& cacheLine = m_cacheLines[lineIdx];
+
+ // Update based on replacement policy
+ if (m_policy == CacheReplPlcy::Random) {
+ // Select a random way
+ const unsigned wayIdx = std::rand() % getSets();
+ auto& way = cacheLine[wayIdx];
+ // Todo: this is not valid; the entire cache line (all blocks) should be read
+ way.valid = true;
+ emit dataChanged(address);
+ }
+}
+
+bool CacheBase::checkCacheHit() {
+ const unsigned lineIdx = getAccessLineIdx();
+
+ if (m_cacheLines.count(lineIdx) != 0) {
+ int setIdx = 0;
+ for (const auto& way : m_cacheLines.at(lineIdx)) {
+ if (way.second.tag == getAccessTag()) {
+ m_currentSetIdx = setIdx;
+ return true;
+ }
+ setIdx++;
+ }
+ }
+ return false;
+}
+
+void CacheBase::read(uint32_t address) {
+ m_currentAccessAddress = address;
+ m_currentAccessIsHit = checkCacheHit();
+ emit dataChanged(m_currentAccessAddress);
+}
+void CacheBase::write(uint32_t address) {
+ m_currentAccessAddress = address;
+ emit accessChanged(m_currentAccessAddress);
+}
+void CacheBase::undo() {}
+
+unsigned CacheBase::getAccessLineIdx() const {
+ uint32_t maskedAddress = m_currentAccessAddress & m_lineMask;
+ maskedAddress >>= 2 + getBlockBits();
+ return maskedAddress;
+}
+
+unsigned CacheBase::getAccessSetIdx() const {
+ return m_currentSetIdx;
+}
+
+unsigned CacheBase::getAccessTag() const {
+ uint32_t maskedAddress = m_currentAccessAddress & m_lineMask;
+ maskedAddress >>= 2 + getBlockBits() + getLineBits();
+ return maskedAddress;
+}
+
+unsigned CacheBase::getAccessBlockIdx() const {
+ uint32_t maskedAddress = m_currentAccessAddress & m_blockMask;
+ maskedAddress >>= 2;
+ return maskedAddress;
+}
+
+void CacheBase::updateConfiguration() {
+ // Recalculate masks
+ int bitoffset = 2; // 2^2 = 4-byte offset (32-bit words in cache)
+
+ m_blockMask = generateBitmask(getBlockBits()) << bitoffset;
+ bitoffset += getBlockBits();
+
+ m_lineMask = generateBitmask(getLineBits()) << bitoffset;
+ bitoffset += getLineBits();
+
+ m_tagMask = generateBitmask(32 - bitoffset) << bitoffset;
+
+ emit configurationChanged();
+}
+
+} // namespace Ripes

MODIFY
src/cachebase.h
src/cachebase.h
namespace Ripes {
+enum class CacheReplPlcy { Random, LRU };
+
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);
@@ -35,29 +29,60 @@ public:
int getSets() const { return static_cast<int>(std::pow(2, m_sets)); }
int getLines() const { return static_cast<int>(std::pow(2, m_lines)); }
+ unsigned getAccessLineIdx() const;
+ unsigned getAccessSetIdx() const;
+ unsigned getAccessBlockIdx() const;
+ unsigned getAccessTag() const;
+
+ bool isCacheHit() const { return m_currentAccessIsHit; }
+
public slots:
void setBlocks(unsigned blocks) {
m_blocks = blocks;
- emit parametersChanged();
+ updateConfiguration();
}
void setLines(unsigned lines) {
m_lines = lines;
- emit parametersChanged();
+ updateConfiguration();
}
void setSets(unsigned sets) {
m_sets = sets;
- emit parametersChanged();
+ updateConfiguration();
}
signals:
- void parametersChanged();
+ void configurationChanged();
+ void accessChanged(bool active);
+ void dataChanged(uint32_t address);
private:
+ void updateCacheValue(uint32_t address, uint32_t value);
+ bool checkCacheHit();
+ void updateConfiguration();
+
+ CacheReplPlcy m_policy = CacheReplPlcy::Random;
+ uint32_t m_currentAccessAddress;
+ bool m_currentAccessIsHit;
+ unsigned m_currentSetIdx;
+
+ unsigned m_blockMask;
+ unsigned m_lineMask;
+ unsigned m_tagMask;
+
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;
+ struct CacheWay {
+ uint32_t tag;
+ // std::map<unsigned, uint32_t> blocks; we do not store the actual data; no reason to!
+ bool dirty = false;
+ bool valid = true;
+ unsigned lru = 0;
+ };
+
+ using CacheLine = std::map<unsigned, CacheWay>;
+ std::map<unsigned, CacheLine> m_cacheLines;
};
} // namespace Ripes

MODIFY
src/cacheconfigwidget.ui
src/cacheconfigwidget.ui
<rect>
<x>0</x>
<y>0</y>
- <width>447</width>
- <height>187</height>
+ <width>650</width>
+ <height>216</height>
</rect>
</property>
<property name="windowTitle">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
- <string>Configuration</string>
+ <string>Cache 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">
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="sets">
+ <property name="maximum">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
<property name="text">
- <string>Blocks</string>
+ <string>Lines</string>
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="blocks">
- <property name="maximum">
- <number>4</number>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Sets</string>
</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>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Blocks</string>
</property>
</widget>
</item>
</property>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_4">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
<property name="text">
- <string>Lines</string>
+ <string>Preset:</string>
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_2">
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="blocks">
+ <property name="maximum">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="checkBox">
<property name="text">
- <string>Sets</string>
+ <string>Valid bit</string>
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="checkBox_2">
<property name="text">
- <string>Preset:</string>
+ <string>Dirty bit</string>
</property>
</widget>
</item>
<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 row="1" column="2">
+ <widget class="QPushButton" name="sizeBreakdownButton">
+ <property name="text">
+ <string>Breakdown</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit_2"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
</property>
</widget>
</item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
</property>
</widget>
</item>
- <item row="1" column="2">
- <widget class="QPushButton" name="sizeBreakdownButton">
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_7">
<property name="text">
- <string/>
+ <string>Writebacks:</string>
</property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="lineEdit_2"/>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lineEdit_3"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="title">
+ <string>View settings:</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_7">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="gridLayout_6">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="checkBox_3">
+ <property name="text">
+ <string>Follow accesses</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer_2">
+ <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>

MODIFY
src/cachegraphic.cpp
src/cachegraphic.cpp
#include <QFontMetrics>
#include <QGraphicsLineItem>
+#include <QGraphicsRectItem>
+#include <QGraphicsScene>
#include <QGraphicsSimpleTextItem>
#include <QPen>
+#include "processorhandler.h"
+
namespace Ripes {
CacheGraphic::CacheGraphic(CacheBase& cache) : QGraphicsObject(nullptr), m_cache(cache) {
- connect(&cache, &CacheBase::parametersChanged, this, &CacheGraphic::cacheParametersChanged);
+ connect(&cache, &CacheBase::configurationChanged, this, &CacheGraphic::cacheParametersChanged);
+ connect(&cache, &CacheBase::accessChanged, this, &CacheGraphic::updateHighlighting);
+ connect(&cache, &CacheBase::dataChanged, this, &CacheGraphic::dataChanged);
+
cacheParametersChanged();
}
+void CacheGraphic::dataChanged(uint32_t address) {
+ const unsigned lineIdx = m_cache.getAccessLineIdx();
+ const unsigned blockIdx = m_cache.getAccessBlockIdx();
+ const unsigned setIdx = m_cache.getAccessSetIdx();
+
+ const auto data = ProcessorHandler::get()->getMemory().readMemConst(address);
+
+ // Try to locate a previously created text object for the block.
+ QGraphicsSimpleTextItem* blockTextItem = m_cacheTextItems[lineIdx][setIdx][blockIdx];
+ if (blockTextItem == nullptr) {
+ blockTextItem = new QGraphicsSimpleTextItem(this);
+ m_cacheTextItems[lineIdx][setIdx][blockIdx] = blockTextItem;
+ }
+
+ blockTextItem->setText("0x" + QString::number(data, 16));
+
+ const qreal x = m_widthBeforeBlocks + blockIdx * m_blockWidth;
+ const qreal y = lineIdx * m_lineHeight + setIdx * m_setHeight;
+ blockTextItem->setPos(x, y);
+ updateHighlighting(true);
+}
+
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::updateHighlighting(bool active) {
+ m_highlightingItems.clear();
+
+ if (active) {
+ // Redraw highlighting rectangles indicating the current indexing
+ const unsigned lineIdx = m_cache.getAccessLineIdx();
+ const unsigned blockIdx = m_cache.getAccessBlockIdx();
+
+ // Draw cache line highlighting rectangle
+ QPointF topLeft = QPointF(0, lineIdx * m_lineHeight);
+ QPointF bottomRight = QPointF(m_cacheWidth, (lineIdx + 1) * m_lineHeight);
+ m_highlightingItems.emplace_back(std::make_unique<QGraphicsRectItem>(QRectF(topLeft, bottomRight), this));
+ auto* lineRectItem = m_highlightingItems.rbegin()->get();
+ lineRectItem->setZValue(-1);
+ lineRectItem->setOpacity(0.25);
+ lineRectItem->setBrush(Qt::red);
+
+ // Draw cache block highlighting rectangle
+ topLeft = QPointF(blockIdx * m_blockWidth + m_widthBeforeBlocks, 0);
+ bottomRight = QPointF((blockIdx + 1) * m_blockWidth + m_widthBeforeBlocks, m_cacheHeight);
+ m_highlightingItems.emplace_back(std::make_unique<QGraphicsRectItem>(QRectF(topLeft, bottomRight), this));
+ auto* blockRectItem = m_highlightingItems.rbegin()->get();
+ blockRectItem->setZValue(-1);
+ blockRectItem->setOpacity(0.25);
+ blockRectItem->setBrush(Qt::yellow);
+ }
+}
+
void CacheGraphic::cacheParametersChanged() {
prepareGeometryChange();
// Remove all items
+ m_highlightingItems.clear();
+ m_cacheTextItems.clear();
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;
+ m_setHeight = metrics.height();
+ m_lineHeight = m_setHeight * m_cache.getSets();
+ m_blockWidth = metrics.horizontalAdvance("0xFFFFFFFF");
+ m_bitWidth = metrics.horizontalAdvance("00");
+ m_cacheHeight = m_lineHeight * m_cache.getLines();
+ m_tagWidth = m_blockWidth;
// Draw cache:
qreal horizontalAdvance = 0;
// Draw valid bit column
- new QGraphicsLineItem(0, 0, 0, cacheHeight, this);
- new QGraphicsLineItem(bitWidth, 0, bitWidth, cacheHeight, this);
+ new QGraphicsLineItem(0, 0, 0, m_cacheHeight, this);
+ new QGraphicsLineItem(m_bitWidth, 0, m_bitWidth, m_cacheHeight, this);
const QString validBitText = "V";
drawText(validBitText, 0, -metrics.height());
- horizontalAdvance += bitWidth;
+ horizontalAdvance += m_bitWidth;
// Draw tag column
- new QGraphicsLineItem(tagWidth, 0, tagWidth, cacheHeight, this);
+ new QGraphicsLineItem(m_tagWidth + horizontalAdvance, 0, m_tagWidth + horizontalAdvance, m_cacheHeight, this);
const QString tagText = "Tag";
- drawText(tagText, horizontalAdvance + tagWidth / 2 - metrics.horizontalAdvance(tagText) / 2, -metrics.height());
- horizontalAdvance += tagWidth;
+ drawText(tagText, horizontalAdvance + m_tagWidth / 2 - metrics.horizontalAdvance(tagText) / 2, -metrics.height());
+ horizontalAdvance += m_tagWidth;
+
+ m_widthBeforeBlocks = horizontalAdvance;
// 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,
+ drawText(blockText, horizontalAdvance + m_tagWidth / 2 - metrics.horizontalAdvance(blockText) / 2,
-metrics.height());
- horizontalAdvance += blockWidth;
- auto* l3 = new QGraphicsLineItem(horizontalAdvance, 0, horizontalAdvance, cacheHeight, this);
+ horizontalAdvance += m_blockWidth;
+ auto* l3 = new QGraphicsLineItem(horizontalAdvance, 0, horizontalAdvance, m_cacheHeight, this);
}
+ m_cacheWidth = horizontalAdvance;
+
// Draw cache line rows
for (int i = 0; i <= m_cache.getLines(); i++) {
- qreal verticalAdvance = i * lineHeight;
- new QGraphicsLineItem(0, verticalAdvance, horizontalAdvance, verticalAdvance, this);
+ qreal verticalAdvance = i * m_lineHeight;
+ new QGraphicsLineItem(0, verticalAdvance, m_cacheWidth, 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);
+ verticalAdvance += m_setHeight;
+ auto* setLine = new QGraphicsLineItem(0, verticalAdvance, m_cacheWidth, verticalAdvance, this);
auto pen = setLine->pen();
pen.setStyle(Qt::DashLine);
setLine->setPen(pen);
@@ -80,7 +143,7 @@ void CacheGraphic::cacheParametersChanged() {
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 y = i * m_lineHeight + m_lineHeight / 2 - m_setHeight / 2;
const qreal x = -metrics.horizontalAdvance(text) * 1.2;
drawText(text, x, y);
}

MODIFY
src/cachegraphic.h
src/cachegraphic.h
#include <QFont>
#include <QGraphicsItem>
#include <QObject>
+#include <memory>
#include "cachebase.h"
namespace Ripes {
@@ -15,7 +16,7 @@ public:
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override {}
- void lineChanged(uint32_t address, unsigned block);
+ void dataChanged(uint32_t address);
/**
* @brief cacheParametersChanged
@@ -24,10 +25,28 @@ public:
void cacheParametersChanged();
private:
+ void updateHighlighting(bool active);
void drawText(const QString& text, qreal x, qreal y);
QFont m_font = QFont("Roboto", 12);
CacheBase& m_cache;
+
+ std::vector<std::unique_ptr<QGraphicsRectItem>> m_highlightingItems;
+
+ // Drawing dimensions
+ qreal m_setHeight = 0;
+ qreal m_lineHeight = 0;
+ qreal m_blockWidth = 0;
+ qreal m_bitWidth = 0;
+ qreal m_cacheHeight = 0;
+ qreal m_tagWidth = 0;
+ qreal m_cacheWidth = 0;
+ qreal m_widthBeforeBlocks = 0;
+
+ // Data structure modelling the cache; keeping graphics text items for each entry
+ using CacheWay = std::map<unsigned, QGraphicsSimpleTextItem*>;
+ using CacheLine = std::map<unsigned, CacheWay>;
+ std::map<unsigned, CacheLine> m_cacheTextItems;
};
} // namespace Ripes

MODIFY
src/memorytab.cpp
src/memorytab.cpp
#include <QGraphicsView>
#include <QToolBar>
+#include <QTimer>
+
namespace Ripes {
MemoryTab::MemoryTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent), m_ui(new Ui::MemoryTab) {
@@ -24,6 +26,16 @@ MemoryTab::MemoryTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, par
auto* cacheGraphic = new CacheGraphic(*cacheSim);
m_ui->cacheView->setScene(scene);
scene->addItem(cacheGraphic);
+
+ auto* accessTimer = new QTimer(this);
+ accessTimer->setInterval(500);
+ connect(accessTimer, &QTimer::timeout, [=] {
+ static unsigned address = 0x0;
+ cacheSim->read(address);
+ address += 4;
+ });
+
+ accessTimer->start();
}
void MemoryTab::update() {

Add reading from main memory