Make CacheGraphic read all blocks of a cacheline when tag changes
MODIFY
src/cacheconfigwidget.cpp
src/cacheconfigwidget.cpp
@@ -47,21 +47,23 @@ void CacheConfigWidget::setCache(CacheSim* cache) {
unsigned address = std::rand() % 128;
m_cache->write(address);
});
+
+ connect(m_ui->undo, &QPushButton::clicked, m_cache, &CacheSim::undo);
}
void CacheConfigWidget::setupPresets() {
- std::vector<std::pair<QString, CachePreset>> presets;
+ std::vector<std::pair<QString, CacheSim::CachePreset>> presets;
- presets.push_back({"32-entry 4-word direct-mapped", CachePreset{2, 5, 0}});
- presets.push_back({"32-entry 4-word fully associative", CachePreset{2, 0, 5}});
- presets.push_back({"32-entry 4-word 2-way set associative", CachePreset{2, 4, 1}});
+ presets.push_back({"32-entry 4-word direct-mapped", CacheSim::CachePreset{2, 5, 0}});
+ presets.push_back({"32-entry 4-word fully associative", CacheSim::CachePreset{2, 0, 5}});
+ presets.push_back({"32-entry 4-word 2-way set associative", CacheSim::CachePreset{2, 4, 1}});
for (const auto& preset : presets) {
- m_ui->presets->addItem(preset.first, QVariant::fromValue<CachePreset>(preset.second));
+ m_ui->presets->addItem(preset.first, QVariant::fromValue<CacheSim::CachePreset>(preset.second));
}
connect(m_ui->presets, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) {
- const CachePreset preset = qvariant_cast<CachePreset>(m_ui->presets->itemData(index));
+ const CacheSim::CachePreset preset = qvariant_cast<CacheSim::CachePreset>(m_ui->presets->itemData(index));
// Block signal emmision from the value widgets; the cache sim is updated all at once internally, so no need to
// emit signals.

MODIFY
src/cacheconfigwidget.h
src/cacheconfigwidget.h
@@ -34,4 +34,4 @@ private:
} // namespace Ripes
Q_DECLARE_METATYPE(Ripes::CacheReplPlcy);
-Q_DECLARE_METATYPE(Ripes::CachePreset);
+Q_DECLARE_METATYPE(Ripes::CacheSim::CachePreset);

MODIFY
src/cacheconfigwidget.ui
src/cacheconfigwidget.ui
<rect>
<x>0</x>
<y>0</y>
- <width>799</width>
- <height>415</height>
+ <width>779</width>
+ <height>274</height>
</rect>
</property>
<property name="windowTitle">
<property name="text">
<string/>
</property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
</widget>
</item>
</layout>
<string>Statistics:</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
- <item row="1" column="0">
- <widget class="QPushButton" name="randomread">
- <property name="text">
- <string>Random read</string>
- </property>
- </widget>
- </item>
- <item row="3" 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>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="2">
</item>
</layout>
</item>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="randomread">
+ <property name="text">
+ <string>Random read</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" 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>
<item row="2" column="0">
<widget class="QPushButton" name="randomwrite">
<property name="text">
</property>
</widget>
</item>
+ <item row="3" column="0">
+ <widget class="QPushButton" name="undo">
+ <property name="text">
+ <string>Undo</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>

MODIFY
src/cachegraphic.cpp
src/cachegraphic.cpp
@@ -14,75 +14,97 @@ namespace Ripes {
CacheGraphic::CacheGraphic(CacheSim& cache) : QGraphicsObject(nullptr), m_cache(cache) {
connect(&cache, &CacheSim::configurationChanged, this, &CacheGraphic::cacheParametersChanged);
- connect(&cache, &CacheSim::accessChanged, this, &CacheGraphic::updateHighlighting);
connect(&cache, &CacheSim::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.getAccessWayIdx();
+QGraphicsSimpleTextItem* CacheGraphic::tryCreateGraphicsTextItem(QGraphicsSimpleTextItem** item, qreal x, qreal y) {
+ if (*item == nullptr) {
+ *item = new QGraphicsSimpleTextItem(this);
+ (*item)->setFont(m_font);
+ (*item)->setPos(x, y);
+ }
+ return *item;
+}
- const auto data = ProcessorHandler::get()->getMemory().readMemConst(address);
+void CacheGraphic::dataChanged(const CacheSim::CacheTransaction& transaction) {
auto fm = QFontMetricsF(m_font);
- auto& cacheline = m_cacheTextItems[lineIdx][setIdx];
+ auto& cacheline = m_cacheTextItems[transaction.lineIdx][transaction.wayIdx];
- // Try to locate a previously created text object for the block.
- QGraphicsSimpleTextItem* blockTextItem = cacheline.blocks[blockIdx];
- if (blockTextItem == nullptr) {
- blockTextItem = new QGraphicsSimpleTextItem(this);
- blockTextItem->setFont(m_font);
- cacheline.blocks[blockIdx] = blockTextItem;
- const qreal x =
- m_widthBeforeBlocks + blockIdx * m_blockWidth + (m_blockWidth / 2 - fm.horizontalAdvance("0x00000000") / 2);
- const qreal y = lineIdx * m_lineHeight + setIdx * m_setHeight;
- blockTextItem->setPos(x, y);
- }
+ if (transaction.isHit) {
+ /* The access is a hit. This implies that:
+ * - There exists a previous cycle where text objects were initialized for the given cache line
+ * - Given the above, we only need to update the block which the access is indexing to
+ */
+
+ const qreal x = m_widthBeforeBlocks + transaction.blockIdx * m_blockWidth +
+ (m_blockWidth / 2 - fm.horizontalAdvance("0x00000000") / 2);
+ const qreal y = transaction.lineIdx * m_lineHeight + transaction.wayIdx * m_setHeight;
+
+ const auto data = ProcessorHandler::get()->getMemory().readMemConst(transaction.address);
+ QGraphicsSimpleTextItem* blockTextItem =
+ tryCreateGraphicsTextItem(&cacheline.blocks[transaction.blockIdx], x, y);
const QString text = encodeRadixValue(data, Radix::Hex);
blockTextItem->setText(text);
+ } else {
+ /* The access is a miss. This implies that:
+ * - The entirety of the cache way must be reread/reinitialized given that a new cache line is to be read.
+ */
// Update tag
- QGraphicsSimpleTextItem* tagTextItem = cacheline.tag;
- if (tagTextItem == nullptr) {
- // Create tag
- tagTextItem = new QGraphicsSimpleTextItem(this);
- tagTextItem->setFont(m_font);
- cacheline.tag = tagTextItem;
- auto fm = QFontMetricsF(m_font);
const qreal x = m_widthBeforeTag + (m_tagWidth / 2 - fm.horizontalAdvance("0x00000000") / 2);
- const qreal y = lineIdx * m_lineHeight + setIdx * m_setHeight;
- tagTextItem->setPos(x, y);
- }
- const QString tagText = encodeRadixValue(m_cache.getAccessTag(), Radix::Hex);
+ const qreal y = transaction.lineIdx * m_lineHeight + transaction.wayIdx * m_setHeight;
+
+ QGraphicsSimpleTextItem* tagTextItem = tryCreateGraphicsTextItem(&cacheline.tag, x, y);
+ const QString tagText = encodeRadixValue(transaction.tag, Radix::Hex);
tagTextItem->setText(tagText);
+ tagTextItem->setToolTip("Address: " + encodeRadixValue(transaction.address, Radix::Hex));
+
+ // Update all blocks
+ for (unsigned i = 0; i < m_cache.getBlocks(); i++) {
+ const qreal x =
+ m_widthBeforeBlocks + i * m_blockWidth + (m_blockWidth / 2 - fm.horizontalAdvance("0x00000000") / 2);
+ const qreal y = transaction.lineIdx * m_lineHeight + transaction.wayIdx * m_setHeight;
+
+ QGraphicsSimpleTextItem* blockTextItem = tryCreateGraphicsTextItem(&cacheline.blocks[i], x, y);
+ const uint32_t addressForBlock = (transaction.address & ~m_cache.getBlockMask()) | (i << 2);
+ const auto data = ProcessorHandler::get()->getMemory().readMemConst(addressForBlock);
+ const QString text = encodeRadixValue(data, Radix::Hex);
+ blockTextItem->setText(text);
+ }
- // Update valid & LRU text
- // A value cannot be invalidated with the current schema (uniprocessor)
+ // Update valid
+ // Given that a value cannot be invalidated with the current schema (uniprocessor), the valid bit is simply
+ // flipped if we see a transition
+ if (transaction.transToValid) {
cacheline.valid->setText(QString::number(1));
+ }
+
+ // Update LRU fields.
+ // This field must be updated for all
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.
+ if (auto* currentAccessLine = m_cache.getLine(transaction.lineIdx)) {
+ for (const auto& way : m_cacheTextItems[transaction.lineIdx]) {
+ // 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.getWaysBits());
const QString lruText = QString::number(lruVal);
way.second.lru->setText(lruText);
// LRU text might have changed; update LRU field position to center in column
- const qreal y = lineIdx * m_lineHeight + way.first * m_setHeight;
+ const qreal y = transaction.lineIdx * m_lineHeight + way.first * m_setHeight;
const qreal x = m_bitWidth + m_lruWidth / 2 - fm.horizontalAdvance(lruText) / 2;
way.second.lru->setPos(x, y);
}
}
}
+ }
- updateHighlighting(true);
+ updateHighlighting(true, &transaction);
}
void CacheGraphic::drawText(const QString& text, qreal x, qreal y) {
@@ -91,18 +113,15 @@ void CacheGraphic::drawText(const QString& text, qreal x, qreal y) {
textItem->setPos(x, y);
}
-void CacheGraphic::updateHighlighting(bool active) {
+void CacheGraphic::updateHighlighting(bool active, const CacheSim::CacheTransaction* transaction) {
m_highlightingItems.clear();
if (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);
+ QPointF topLeft = QPointF(0, transaction->lineIdx * m_lineHeight);
+ QPointF bottomRight = QPointF(m_cacheWidth, (transaction->lineIdx + 1) * m_lineHeight);
m_highlightingItems.emplace_back(std::make_unique<QGraphicsRectItem>(QRectF(topLeft, bottomRight), this));
auto* lineRectItem = m_highlightingItems.rbegin()->get();
lineRectItem->setZValue(-2);
@@ -110,8 +129,8 @@ void CacheGraphic::updateHighlighting(bool active) {
lineRectItem->setBrush(Qt::yellow);
// Draw cache block highlighting rectangle
- topLeft = QPointF(blockIdx * m_blockWidth + m_widthBeforeBlocks, 0);
- bottomRight = QPointF((blockIdx + 1) * m_blockWidth + m_widthBeforeBlocks, m_cacheHeight);
+ topLeft = QPointF(transaction->blockIdx * m_blockWidth + m_widthBeforeBlocks, 0);
+ bottomRight = QPointF((transaction->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(-2);
@@ -119,16 +138,18 @@ void CacheGraphic::updateHighlighting(bool active) {
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);
+ topLeft = QPointF(transaction->blockIdx * m_blockWidth + m_widthBeforeBlocks,
+ transaction->lineIdx * m_lineHeight + transaction->wayIdx * m_setHeight);
+ bottomRight = QPointF((transaction->blockIdx + 1) * m_blockWidth + m_widthBeforeBlocks,
+ transaction->lineIdx * m_lineHeight + (transaction->wayIdx + 1) * m_setHeight);
m_highlightingItems.emplace_back(std::make_unique<QGraphicsRectItem>(QRectF(topLeft, bottomRight), this));
auto* hitRectItem = m_highlightingItems.rbegin()->get();
hitRectItem->setZValue(-1);
+ if (transaction->isHit) {
hitRectItem->setOpacity(0.4);
- if (m_cache.isCacheHit()) {
hitRectItem->setBrush(Qt::green);
} else {
+ hitRectItem->setOpacity(0.6);
hitRectItem->setBrush(Qt::red);
}
}

MODIFY
src/cachegraphic.h
src/cachegraphic.h
@@ -16,7 +16,8 @@ public:
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override {}
- void dataChanged(uint32_t address);
+public slots:
+ void dataChanged(const CacheSim::CacheTransaction& transaction);
/**
* @brief cacheParametersChanged
@@ -24,14 +25,17 @@ public:
*/
void cacheParametersChanged();
+ void reset();
+
private:
/**
* @brief initializeControlBits
* Constructs all of the "Valid" and "LRU" text items within the cache
*/
void initializeControlBits();
- void updateHighlighting(bool active);
+ void updateHighlighting(bool active, const CacheSim::CacheTransaction* transaction);
void drawText(const QString& text, qreal x, qreal y);
+ QGraphicsSimpleTextItem* tryCreateGraphicsTextItem(QGraphicsSimpleTextItem** item, qreal x, qreal y);
QFont m_font = QFont("Inconsolata", 12);
CacheSim& m_cache;

MODIFY
src/cachesim.cpp
src/cachesim.cpp
@@ -24,7 +24,7 @@ void CacheSim::updateCacheLineLRU(CacheLine& line, unsigned lruIdx) {
line[lruIdx].lru = 0;
}
-CacheSize CacheSim::getCacheSize() const {
+CacheSim::CacheSize CacheSim::getCacheSize() const {
CacheSize size;
const int entries = getLines() * getWays();
@@ -54,84 +54,83 @@ CacheSize CacheSim::getCacheSize() const {
return size;
}
-void CacheSim::updateCacheValue(uint32_t address) {
- const unsigned lineIdx = getAccessLineIdx();
- const unsigned blockIdx = getAccessBlockIdx();
+void CacheSim::evictAndUpdate(CacheTransaction& transaction) {
+ auto& cacheLine = m_cacheLines[transaction.lineIdx];
- auto& cacheLine = m_cacheLines[lineIdx];
+ CacheWay* currentWay = nullptr;
// Update based on replacement policy
if (m_policy == CacheReplPlcy::Random) {
// Select a random way
- 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();
+ transaction.wayIdx = std::rand() % getWays();
+ currentWay = &cacheLine[transaction.wayIdx];
} else if (m_policy == CacheReplPlcy::LRU) {
if (getWays() == 1) {
// Nothing to do if we are in LRU and only have 1 set
- 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
+ transaction.wayIdx = 0;
+ currentWay = &cacheLine[transaction.wayIdx];
+ } else {
+ // Lazily all ways in the cacheline before starting to iterate
for (int i = 0; i < getWays(); i++) {
cacheLine[i];
}
// If there is an invalid cache line, select that
- unsigned wayIdx = 0;
- CacheWay* selectedWay = nullptr;
for (auto& way : cacheLine) {
if (!way.second.valid) {
- wayIdx = way.first;
- selectedWay = &way.second;
+ transaction.wayIdx = way.first;
+ currentWay = &way.second;
break;
}
}
- if (selectedWay == nullptr) {
+ if (currentWay == nullptr) {
// Else, Find LRU way
for (auto& way : cacheLine) {
if (way.second.lru == getWays() - 1) {
- wayIdx = way.first;
- selectedWay = &way.second;
+ transaction.wayIdx = way.first;
+ currentWay = &way.second;
}
}
}
- Q_ASSERT(selectedWay != nullptr && "There must have been an issue with setting the LRU bits");
+ Q_ASSERT(currentWay != nullptr && "There must have been an issue with setting the LRU bits");
+ updateCacheLineLRU(cacheLine, transaction.wayIdx);
+ }
+ }
- m_currentWayIdx = wayIdx;
- selectedWay->valid = true;
- selectedWay->tag = getAccessTag();
- updateCacheLineLRU(cacheLine, wayIdx);
+ if (!currentWay->valid) {
+ // Record that this was an invalid->valid transition
+ transaction.transToValid = true;
+ currentWay->valid = true;
}
+
+ currentWay->tag = transaction.tag;
+ transaction.tagChanged = true;
}
void CacheSim::updateHitRate() {
+ auto oldHitRate = m_hitrate;
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);
}
+ emit hitRateChanged(m_hitrate);
}
-void CacheSim::analyzeCacheAccess() {
- const unsigned lineIdx = getAccessLineIdx();
-
- m_currentAccessLine = &m_cacheLines[lineIdx];
+void CacheSim::analyzeCacheAccess(CacheTransaction& transaction) {
+ transaction.lineIdx = getLineIdx(transaction.address);
+ transaction.blockIdx = getBlockIdx(transaction.address);
+ transaction.tag = getTag(transaction.address);
- m_currentAccessIsHit = false;
- if (m_cacheLines.count(lineIdx) != 0) {
+ transaction.isHit = false;
+ if (m_cacheLines.count(transaction.lineIdx) != 0) {
int wayIdx = 0;
- for (const auto& way : m_cacheLines.at(lineIdx)) {
- if (way.second.tag == getAccessTag() && way.second.valid) {
- m_currentWayIdx = wayIdx;
- m_currentAccessIsHit = true;
+ for (const auto& way : m_cacheLines.at(transaction.lineIdx)) {
+ if (way.second.tag == transaction.tag && way.second.valid) {
+ transaction.wayIdx = wayIdx;
+ transaction.isHit = true;
break;
}
wayIdx++;
@@ -140,53 +139,56 @@ void CacheSim::analyzeCacheAccess() {
// Update cache access trace for the current cycle
if (m_accessTrace.size() == 0) {
- m_accessTrace[0] = CacheAccessTrace(m_currentAccessIsHit);
+ m_accessTrace[0] = CacheAccessTrace(transaction.isHit);
} else {
m_accessTrace[m_accessTrace.size()] =
- CacheAccessTrace(m_accessTrace[m_accessTrace.size() - 1], m_currentAccessIsHit);
+ CacheAccessTrace(m_accessTrace[m_accessTrace.size() - 1], transaction.isHit);
}
updateHitRate();
- emit hitRateChanged(m_hitrate);
-
- return;
}
void CacheSim::read(uint32_t address) {
- m_currentAccessAddress = address;
- analyzeCacheAccess();
- if (!m_currentAccessIsHit) {
- updateCacheValue(m_currentAccessAddress);
- }
- emit dataChanged(m_currentAccessAddress);
+ address = address & ~0b11; // Disregard unaligned accesses
+ CacheTransaction transaction;
+ transaction.address = address;
+
+ analyzeCacheAccess(transaction);
+
+ if (!transaction.isHit) {
+ evictAndUpdate(transaction);
}
-void CacheSim::write(uint32_t address) {
- m_currentAccessAddress = address;
- emit accessChanged(m_currentAccessAddress);
+
+ emit dataChanged(transaction);
}
+void CacheSim::write(uint32_t address) {}
void CacheSim::undo() {}
-unsigned CacheSim::getAccessLineIdx() const {
- uint32_t maskedAddress = m_currentAccessAddress & m_lineMask;
+unsigned CacheSim::getLineIdx(const uint32_t address) const {
+ uint32_t maskedAddress = address & m_lineMask;
maskedAddress >>= 2 + getBlockBits();
return maskedAddress;
}
-unsigned CacheSim::getAccessWayIdx() const {
- return m_currentWayIdx;
-}
-
-unsigned CacheSim::getAccessTag() const {
- uint32_t maskedAddress = m_currentAccessAddress & m_tagMask;
+unsigned CacheSim::getTag(const uint32_t address) const {
+ uint32_t maskedAddress = address & m_tagMask;
maskedAddress >>= 2 + getBlockBits() + getLineBits();
return maskedAddress;
}
-unsigned CacheSim::getAccessBlockIdx() const {
- uint32_t maskedAddress = m_currentAccessAddress & m_blockMask;
+unsigned CacheSim::getBlockIdx(const uint32_t address) const {
+ uint32_t maskedAddress = address & m_blockMask;
maskedAddress >>= 2;
return maskedAddress;
}
+const CacheSim::CacheLine* CacheSim::getLine(unsigned idx) const {
+ if (m_cacheLines.count(idx)) {
+ return &m_cacheLines.at(idx);
+ } else {
+ return nullptr;
+ }
+}
+
void CacheSim::updateConfiguration() {
// Cache configuration changes shall enforce a full reset of the computing system
m_cacheLines.clear();

MODIFY
src/cachesim.h
src/cachesim.h
@@ -12,6 +12,9 @@ enum class CacheReplPlcy { Random, LRU };
static std::map<CacheReplPlcy, QString> s_cachePolicyStrings{{CacheReplPlcy::Random, "Random"},
{CacheReplPlcy::LRU, "LRU"}};
+class CacheSim : public QObject {
+ Q_OBJECT
+public:
struct CacheSize {
unsigned bits = 0;
std::vector<QString> components;
@@ -23,9 +26,33 @@ struct CachePreset {
int ways;
};
-class CacheSim : public QObject {
- Q_OBJECT
-public:
+ struct CacheTransaction {
+ uint32_t address;
+ unsigned lineIdx = -1;
+ unsigned wayIdx = -1;
+ unsigned blockIdx = -1;
+ unsigned tag = -1;
+
+ bool isHit = false;
+ bool read = false;
+ bool write = false;
+ bool transToValid = false; // True if the cacheline just transitioned from invalid to valid
+ bool tagChanged = false; // True if transToValid or the previous entry was evicted
+ };
+
+ 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 = false;
+
+ // LRU algorithm relies on invalid cache ways to have an initial high value. -1 ensures maximum value for all
+ // way sizes.
+ unsigned lru = -1;
+ };
+
+ using CacheLine = std::map<unsigned, CacheWay>;
+
CacheSim(QObject* parent);
void setReplacementPolicy(CacheReplPlcy policy) {
@@ -36,6 +63,7 @@ public:
void read(uint32_t address);
void write(uint32_t address);
void undo();
+ void reset();
CacheReplPlcy getReplacementPolicy() const { return m_policy; }
@@ -50,13 +78,15 @@ public:
int getBlocks() const { return static_cast<int>(std::pow(2, m_blocks)); }
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 getBlockMask() const { return m_blockMask; }
+ unsigned getTagMask() const { return m_tagMask; }
+ unsigned getLineMask() const { return m_lineMask; }
- unsigned getAccessLineIdx() const;
- unsigned getAccessWayIdx() const;
- unsigned getAccessBlockIdx() const;
- unsigned getAccessTag() const;
+ unsigned getLineIdx(const uint32_t address) const;
+ unsigned getBlockIdx(const uint32_t address) const;
+ unsigned getTag(const uint32_t address) const;
- bool isCacheHit() const { return m_currentAccessIsHit; }
+ const CacheLine* getLine(unsigned idx) const;
public slots:
void setBlocks(unsigned blocks);
@@ -66,47 +96,30 @@ public slots:
signals:
void configurationChanged();
- void accessChanged(bool active);
- void dataChanged(uint32_t address);
+ void dataChanged(const CacheTransaction& transaction);
void hitRateChanged(double hitrate);
private:
void updateHitRate();
- void updateCacheValue(uint32_t address);
- void analyzeCacheAccess();
+ void evictAndUpdate(CacheTransaction& transaction);
+ void analyzeCacheAccess(CacheTransaction& transaction);
void updateConfiguration();
CacheReplPlcy m_policy = CacheReplPlcy::LRU;
- uint32_t m_currentAccessAddress;
- bool m_currentAccessIsHit;
- unsigned m_currentWayIdx;
- unsigned m_blockMask;
- unsigned m_lineMask;
- unsigned m_tagMask;
+ unsigned m_blockMask = -1;
+ unsigned m_lineMask = -1;
+ unsigned m_tagMask = -1;
int m_blocks = 1; // Some power of 2
int m_lines = 2; // Some power of 2
int m_ways = 2; // Some power of 2
- double m_hitrate; // Most recent hitrate
-
- 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 = false;
+ double m_hitrate = 0; // Most recent hitrate
- // LRU algorithm relies on invalid cache ways to have an initial high value. -1 ensures maximum value for all
- // way sizes.
- unsigned lru = -1;
- };
-
- using CacheLine = std::map<unsigned, CacheWay>;
std::map<unsigned, CacheLine> m_cacheLines;
void updateCacheLineLRU(CacheLine& line, unsigned lruIdx);
- CacheLine const* m_currentAccessLine = nullptr;
struct CacheAccessTrace {
int hits = 0;
@@ -122,9 +135,6 @@ private:
}
};
std::map<unsigned, CacheAccessTrace> m_accessTrace;
-
-public:
- const CacheLine* getCurrentAccessLine() const { return m_currentAccessLine; }
};
} // namespace Ripes

Make CacheGraphic read all blocks of a cacheline when tag changes