Rename cache sets -> cache ways
MODIFY
src/cachebase.cpp
src/cachebase.cpp
@@ -29,22 +29,22 @@ void CacheBase::updateCacheValue(uint32_t address) {
// Update based on replacement policy
if (m_policy == CacheReplPlcy::Random) {
// Select a random way
- m_currentSetIdx = std::rand() % getSets();
- auto& way = cacheLine[m_currentSetIdx];
+ m_currentWayIdx = std::rand() % getWays();
+ auto& way = cacheLine[m_currentWayIdx];
// Todo: this is not valid; the entire cache line (all blocks) should be read
way.valid = true;
way.tag = getAccessTag();
} else if (m_policy == CacheReplPlcy::LRU) {
- if (getSets() == 1) {
+ if (getWays() == 1) {
// Nothing to do if we are in LRU and only have 1 set
- m_currentSetIdx = 0;
- cacheLine[m_currentSetIdx].valid = true;
- cacheLine[m_currentSetIdx].tag = getAccessTag();
+ m_currentWayIdx = 0;
+ cacheLine[m_currentWayIdx].valid = true;
+ cacheLine[m_currentWayIdx].tag = getAccessTag();
return;
}
// Ensure that all ways in the cache line has been initialized
- for (int i = 0; i < getSets(); i++) {
+ for (int i = 0; i < getWays(); i++) {
cacheLine[i];
}
@@ -61,7 +61,7 @@ void CacheBase::updateCacheValue(uint32_t address) {
if (selectedWay == nullptr) {
// Else, Find LRU way
for (auto& way : cacheLine) {
- if (way.second.lru == getSets() - 1) {
+ if (way.second.lru == getWays() - 1) {
wayIdx = way.first;
selectedWay = &way.second;
}
@@ -70,34 +70,56 @@ void CacheBase::updateCacheValue(uint32_t address) {
Q_ASSERT(selectedWay != nullptr && "There must have been an issue with setting the LRU bits");
- m_currentSetIdx = wayIdx;
+ m_currentWayIdx = wayIdx;
selectedWay->valid = true;
selectedWay->tag = getAccessTag();
updateCacheLineLRU(cacheLine, wayIdx);
}
}
-bool CacheBase::analyzeCacheHit() {
+void CacheBase::updateHitRate() {
+ if (m_accessTrace.size() == 0) {
+ m_hitrate = 0;
+ } else {
+ auto& trace = m_accessTrace.rbegin()->second;
+ m_hitrate = static_cast<double>(trace.hits) / (trace.hits + trace.misses);
+ }
+}
+
+void CacheBase::analyzeCacheAccess() {
const unsigned lineIdx = getAccessLineIdx();
m_currentAccessLine = &m_cacheLines[lineIdx];
+ m_currentAccessIsHit = false;
if (m_cacheLines.count(lineIdx) != 0) {
- int setIdx = 0;
+ int wayIdx = 0;
for (const auto& way : m_cacheLines.at(lineIdx)) {
if (way.second.tag == getAccessTag() && way.second.valid) {
- m_currentSetIdx = setIdx;
- return true;
+ m_currentWayIdx = wayIdx;
+ m_currentAccessIsHit = true;
+ break;
}
- setIdx++;
+ wayIdx++;
}
}
- return false;
+
+ // Update cache access trace for the current cycle
+ if (m_accessTrace.size() == 0) {
+ m_accessTrace[0] = CacheAccessTrace(m_currentAccessIsHit);
+ } else {
+ m_accessTrace[m_accessTrace.size()] =
+ CacheAccessTrace(m_accessTrace[m_accessTrace.size() - 1], m_currentAccessIsHit);
+ }
+ updateHitRate();
+ emit hitRateChanged(m_hitrate);
+
+ return;
}
void CacheBase::read(uint32_t address) {
m_currentAccessAddress = address;
- m_currentAccessIsHit = analyzeCacheHit();
+ analyzeCacheAccess();
if (!m_currentAccessIsHit) {
updateCacheValue(m_currentAccessAddress);
}
@@ -115,8 +137,8 @@ unsigned CacheBase::getAccessLineIdx() const {
return maskedAddress;
}
-unsigned CacheBase::getAccessSetIdx() const {
- return m_currentSetIdx;
+unsigned CacheBase::getAccessWayIdx() const {
+ return m_currentWayIdx;
}
unsigned CacheBase::getAccessTag() const {
@@ -134,6 +156,7 @@ unsigned CacheBase::getAccessBlockIdx() const {
void CacheBase::updateConfiguration() {
// Cache configuration changes shall enforce a full reset of the computing system
m_cacheLines.clear();
+ m_accessTrace.clear();
// Recalculate masks
int bitoffset = 2; // 2^2 = 4-byte offset (32-bit words in cache)
@@ -146,6 +169,7 @@ void CacheBase::updateConfiguration() {
m_tagMask = generateBitmask(32 - bitoffset) << bitoffset;
+ emit hitRateChanged(m_hitrate);
emit configurationChanged();
}

MODIFY
src/cachebase.h
src/cachebase.h
@@ -28,18 +28,19 @@ public:
CacheReplPlcy getReplacementPolicy() const { return m_policy; }
+ double getHitRate() const;
int getSizeInBits();
int getBlockBits() const { return m_blocks; }
- int getSetBits() const { return m_sets; }
+ int getWaysBits() const { return m_ways; }
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 getWays() const { return static_cast<int>(std::pow(2, m_ways)); }
int getLines() const { return static_cast<int>(std::pow(2, m_lines)); }
unsigned getAccessLineIdx() const;
- unsigned getAccessSetIdx() const;
+ unsigned getAccessWayIdx() const;
unsigned getAccessBlockIdx() const;
unsigned getAccessTag() const;
@@ -54,8 +55,8 @@ public slots:
m_lines = lines;
updateConfiguration();
}
- void setSets(unsigned sets) {
- m_sets = sets;
+ void setWays(unsigned ways) {
+ m_ways = ways;
updateConfiguration();
}
@@ -63,16 +64,18 @@ signals:
void configurationChanged();
void accessChanged(bool active);
void dataChanged(uint32_t address);
+ void hitRateChanged(double hitrate);
private:
+ void updateHitRate();
void updateCacheValue(uint32_t address);
- bool analyzeCacheHit();
+ void analyzeCacheAccess();
void updateConfiguration();
CacheReplPlcy m_policy = CacheReplPlcy::LRU;
uint32_t m_currentAccessAddress;
bool m_currentAccessIsHit;
- unsigned m_currentSetIdx;
+ unsigned m_currentWayIdx;
unsigned m_blockMask;
unsigned m_lineMask;
@@ -80,7 +83,9 @@ private:
int m_blocks = 1; // Some power of 2
int m_lines = 2; // Some power of 2
- int m_sets = 2; // Some power of 2
+ int m_ways = 2; // Some power of 2
+
+ double m_hitrate; // Most recent hitrate
struct CacheWay {
uint32_t tag;
@@ -89,7 +94,7 @@ private:
bool valid = false;
// LRU algorithm relies on invalid cache ways to have an initial high value. -1 ensures maximum value for all
- // set sizes.
+ // way sizes.
unsigned lru = -1;
};
@@ -99,6 +104,21 @@ private:
void updateCacheLineLRU(CacheLine& line, unsigned lruIdx);
CacheLine const* m_currentAccessLine = nullptr;
+ struct CacheAccessTrace {
+ int hits = 0;
+ int misses = 0;
+ CacheAccessTrace() {}
+ CacheAccessTrace(bool hit) {
+ hits = hit ? 1 : 0;
+ misses = hit ? 0 : 1;
+ }
+ CacheAccessTrace(const CacheAccessTrace& pre, bool hit) {
+ hits = pre.hits + (hit ? 1 : 0);
+ misses = pre.misses + (hit ? 0 : 1);
+ }
+ };
+ std::map<unsigned, CacheAccessTrace> m_accessTrace;
+
public:
const CacheLine* getCurrentAccessLine() const { return m_currentAccessLine; }
};

MODIFY
src/cacheconfigwidget.cpp
src/cacheconfigwidget.cpp
@@ -12,15 +12,19 @@ CacheConfigWidget::CacheConfigWidget(QWidget* parent) : QWidget(parent), m_ui(ne
void CacheConfigWidget::setCache(CacheBase* cache) {
m_cache = cache;
- connect(m_ui->sets, QOverload<int>::of(&QSpinBox::valueChanged), m_cache, &CacheBase::setSets);
+ connect(m_ui->ways, QOverload<int>::of(&QSpinBox::valueChanged), m_cache, &CacheBase::setWays);
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->ways->setValue(m_cache->getWaysBits());
m_ui->lines->setValue(m_cache->getLineBits());
m_ui->blocks->setValue(m_cache->getBlockBits());
}
+void CacheConfigWidget::setHitRate(double hitrate) {
+ m_ui->hitrate->setText(QString::number(hitrate));
+}
+
CacheConfigWidget::~CacheConfigWidget() {
delete m_ui;
}

MODIFY
src/cacheconfigwidget.h
src/cacheconfigwidget.h
@@ -17,6 +17,9 @@ public:
void setCache(CacheBase* cache);
+public slots:
+ void setHitRate(double hitrate);
+
private:
CacheBase* m_cache;
Ui::CacheConfigWidget* m_ui = nullptr;

MODIFY
src/cacheconfigwidget.ui
src/cacheconfigwidget.ui
<rect>
<x>0</x>
<y>0</y>
- <width>650</width>
- <height>216</height>
+ <width>661</width>
+ <height>247</height>
</rect>
</property>
<property name="windowTitle">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
- <item row="5" column="0">
- <widget class="QCheckBox" name="checkBox">
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_8">
<property name="text">
- <string>Valid bit</string>
+ <string>Repl. policy:</string>
</property>
</widget>
</item>
+ <item row="4" column="1">
+ <widget class="QComboBox" name="replacementPolicy"/>
+ </item>
<item row="0" column="1">
<widget class="QComboBox" name="presets"/>
</item>
</widget>
</item>
<item row="1" column="1">
- <widget class="QSpinBox" name="sets">
+ <widget class="QSpinBox" name="ways">
<property name="maximum">
<number>10</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
- <string>Sets</string>
+ <string>Ways</string>
</property>
</widget>
</item>
</property>
</widget>
</item>
- <item row="5" column="1">
- <widget class="QCheckBox" name="checkBox_2">
+ <item row="5" column="0">
+ <widget class="QCheckBox" name="writeback">
<property name="toolTip">
<string>Setting the valid bit implies a write-back cache</string>
</property>
<property name="text">
- <string>Dirty bit (WB)</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="label_8">
- <property name="text">
- <string>Repl. policy:</string>
+ <string>Writeback</string>
</property>
</widget>
</item>
- <item row="4" column="1">
- <widget class="QComboBox" name="replacementPolicy"/>
- </item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
- <widget class="QLineEdit" name="lineEdit_2"/>
+ <widget class="QLineEdit" name="hitrate"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
</widget>
</item>
<item row="1" column="1">
- <widget class="QLineEdit" name="lineEdit"/>
+ <widget class="QLineEdit" name="size"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
</widget>
</item>
<item row="2" column="1">
- <widget class="QLineEdit" name="lineEdit_3"/>
+ <widget class="QLineEdit" name="writebacks"/>
</item>
</layout>
</item>

MODIFY
src/cachegraphic.cpp
src/cachegraphic.cpp
@@ -23,7 +23,7 @@ CacheGraphic::CacheGraphic(CacheBase& cache) : QGraphicsObject(nullptr), m_cache
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 unsigned setIdx = m_cache.getAccessWayIdx();
const auto data = ProcessorHandler::get()->getMemory().readMemConst(address);
auto fm = QFontMetricsF(m_font);
@@ -62,14 +62,14 @@ void CacheGraphic::dataChanged(uint32_t address) {
// Update valid & LRU text
// A value cannot be invalidated with the current schema (uniprocessor)
cacheline.valid->setText(QString::number(1));
- if (m_cache.getReplacementPolicy() == CacheReplPlcy::LRU && m_cache.getSets() > 1) {
+ if (m_cache.getReplacementPolicy() == CacheReplPlcy::LRU && m_cache.getWays() > 1) {
if (m_cache.getCurrentAccessLine()) {
auto* currentAccessLine = m_cache.getCurrentAccessLine();
for (const auto& way : m_cacheTextItems[m_cache.getAccessLineIdx()]) {
// If LRU was just initialized, the actual (software) LRU value may be very large. Mask to the number of
// actual LRU bits.
unsigned lruVal = currentAccessLine->at(way.first).lru;
- lruVal &= generateBitmask(m_cache.getSetBits());
+ lruVal &= generateBitmask(m_cache.getWaysBits());
const QString lruText = QString::number(lruVal);
way.second.lru->setText(lruText);
@@ -98,13 +98,14 @@ void CacheGraphic::updateHighlighting(bool active) {
// Redraw highlighting rectangles indicating the current indexing
const unsigned lineIdx = m_cache.getAccessLineIdx();
const unsigned blockIdx = m_cache.getAccessBlockIdx();
+ const unsigned setIdx = m_cache.getAccessWayIdx();
// 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->setZValue(-2);
lineRectItem->setOpacity(0.25);
lineRectItem->setBrush(Qt::yellow);
@@ -113,9 +114,23 @@ void CacheGraphic::updateHighlighting(bool active) {
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->setZValue(-2);
blockRectItem->setOpacity(0.25);
blockRectItem->setBrush(Qt::yellow);
+
+ // Draw highlighting on the currently accessed block
+ topLeft = QPointF(blockIdx * m_blockWidth + m_widthBeforeBlocks, lineIdx * m_lineHeight + setIdx * m_setHeight);
+ bottomRight = QPointF((blockIdx + 1) * m_blockWidth + m_widthBeforeBlocks,
+ lineIdx * m_lineHeight + (setIdx + 1) * m_setHeight);
+ m_highlightingItems.emplace_back(std::make_unique<QGraphicsRectItem>(QRectF(topLeft, bottomRight), this));
+ auto* hitRectItem = m_highlightingItems.rbegin()->get();
+ hitRectItem->setZValue(-1);
+ hitRectItem->setOpacity(0.4);
+ if (m_cache.isCacheHit()) {
+ hitRectItem->setBrush(Qt::green);
+ } else {
+ hitRectItem->setBrush(Qt::red);
+ }
}
}
@@ -124,7 +139,7 @@ void CacheGraphic::initializeControlBits() {
for (int lineIdx = 0; lineIdx < m_cache.getLines(); lineIdx++) {
auto& line = m_cacheTextItems[lineIdx];
- for (int setIdx = 0; setIdx < m_cache.getSets(); setIdx++) {
+ for (int setIdx = 0; setIdx < m_cache.getWays(); setIdx++) {
const qreal y = lineIdx * m_lineHeight + setIdx * m_setHeight;
qreal x;
@@ -136,11 +151,11 @@ void CacheGraphic::initializeControlBits() {
validItem->setPos(x, y);
line[setIdx].valid = validItem;
- if (m_cache.getReplacementPolicy() == CacheReplPlcy::LRU && m_cache.getSets() > 1) {
+ if (m_cache.getReplacementPolicy() == CacheReplPlcy::LRU && m_cache.getWays() > 1) {
// Create LRU field
auto* lruItem = new QGraphicsSimpleTextItem(this);
lruItem->setFont(m_font);
- const QString lruText = QString::number(m_cache.getSets() - 1);
+ const QString lruText = QString::number(m_cache.getWays() - 1);
lruItem->setText(lruText);
x = m_bitWidth + m_lruWidth / 2 - fm.horizontalAdvance(lruText) / 2;
lruItem->setPos(x, y);
@@ -162,10 +177,10 @@ void CacheGraphic::cacheParametersChanged() {
// Determine cell dimensions
auto metrics = QFontMetricsF(m_font);
m_setHeight = metrics.height();
- m_lineHeight = m_setHeight * m_cache.getSets();
+ m_lineHeight = m_setHeight * m_cache.getWays();
m_blockWidth = metrics.horizontalAdvance(" 0x00000000 ");
m_bitWidth = metrics.horizontalAdvance("00");
- m_lruWidth = metrics.horizontalAdvance(QString::number(m_cache.getSets()) + " ");
+ m_lruWidth = metrics.horizontalAdvance(QString::number(m_cache.getWays()) + " ");
m_cacheHeight = m_lineHeight * m_cache.getLines();
m_tagWidth = m_blockWidth;
@@ -179,7 +194,7 @@ void CacheGraphic::cacheParametersChanged() {
drawText(validBitText, 0, -metrics.height());
horizontalAdvance += m_bitWidth;
- if (m_cache.getReplacementPolicy() == CacheReplPlcy::LRU && m_cache.getSets() > 1) {
+ if (m_cache.getReplacementPolicy() == CacheReplPlcy::LRU && m_cache.getWays() > 1) {
// Draw LRU bit column
new QGraphicsLineItem(horizontalAdvance, 0, horizontalAdvance, m_cacheHeight, this);
new QGraphicsLineItem(m_bitWidth + m_lruWidth, 0, m_bitWidth + m_lruWidth, m_cacheHeight, this);
@@ -217,7 +232,7 @@ void CacheGraphic::cacheParametersChanged() {
if (i < m_cache.getLines()) {
// Draw cache set rows
- for (int j = 1; j < m_cache.getSets(); j++) {
+ for (int j = 1; j < m_cache.getWays(); j++) {
verticalAdvance += m_setHeight;
auto* setLine = new QGraphicsLineItem(0, verticalAdvance, m_cacheWidth, verticalAdvance, this);
auto pen = setLine->pen();

MODIFY
src/memorytab.cpp
src/memorytab.cpp
@@ -23,6 +23,7 @@ MemoryTab::MemoryTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, par
auto* cacheSim = new CacheBase(this);
m_ui->cacheConfig->setCache(cacheSim);
+ connect(cacheSim, &CacheBase::hitRateChanged, m_ui->cacheConfig, &CacheConfigWidget::setHitRate);
auto* cacheGraphic = new CacheGraphic(*cacheSim);
m_ui->cacheView->setScene(scene);
scene->addItem(cacheGraphic);
@@ -33,6 +34,9 @@ MemoryTab::MemoryTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, par
static unsigned address = 0x0;
cacheSim->read(address);
address += 4;
+ if (address > 128) {
+ address = 0;
+ }
});
accessTimer->start();

Rename cache sets -> cache ways