Add initial write handling in cache simulator
MODIFY
src/cacheconfigwidget.cpp
src/cacheconfigwidget.cpp
@@ -116,7 +116,7 @@ void CacheConfigWidget::setHitRate(double hitrate) {
void CacheConfigWidget::showSizeBreakdown() {
QString sizeText;
- auto cacheSize = m_cache->getCacheSize();
+ const auto cacheSize = m_cache->getCacheSize();
for (const auto& component : cacheSize.components) {
sizeText += component + "\n";

MODIFY
src/cacheconfigwidget.ui
src/cacheconfigwidget.ui
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>

MODIFY
src/cachegraphic.cpp
src/cachegraphic.cpp
@@ -31,7 +31,8 @@ QGraphicsSimpleTextItem* CacheGraphic::tryCreateGraphicsTextItem(QGraphicsSimple
void CacheGraphic::dataChanged(const CacheSim::CacheTransaction& transaction) {
auto fm = QFontMetricsF(m_font);
- auto& cacheline = m_cacheTextItems[transaction.lineIdx][transaction.wayIdx];
+ auto& cacheWay = m_cacheTextItems[transaction.lineIdx][transaction.wayIdx];
+ auto& simCacheWay = m_cache.getLine(transaction.lineIdx)->at(transaction.wayIdx);
if (transaction.isHit) {
/* The access is a hit. This implies that:
@@ -44,8 +45,7 @@ void CacheGraphic::dataChanged(const CacheSim::CacheTransaction& transaction) {
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);
+ QGraphicsSimpleTextItem* blockTextItem = cacheWay.blocks[transaction.blockIdx];
const QString text = encodeRadixValue(data, Radix::Hex);
blockTextItem->setText(text);
} else {
@@ -53,21 +53,13 @@ void CacheGraphic::dataChanged(const CacheSim::CacheTransaction& transaction) {
* - The entirety of the cache way must be reread/reinitialized given that a new cache line is to be read.
*/
- // Update tag
- const qreal x = m_widthBeforeTag + (m_tagWidth / 2 - fm.horizontalAdvance("0x00000000") / 2);
- 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);
-
// 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);
+ QGraphicsSimpleTextItem* blockTextItem = tryCreateGraphicsTextItem(&cacheWay.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);
@@ -79,7 +71,46 @@ void CacheGraphic::dataChanged(const CacheSim::CacheTransaction& transaction) {
// 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));
+ cacheWay.valid->setText(QString::number(1));
+ }
+ }
+
+ // Update dirty field
+ if (m_cache.getWritePolicy() == CacheSim::WritePolicy::WriteBack) {
+ cacheWay.dirty->setText(QString::number(simCacheWay.dirty));
+ }
+
+ // Update dirty blocks
+ if (transaction.tagChanged) {
+ // Tag changing implies that the entries of the way was evicted. Clear any highlighting blocks for the way,
+ // before setting new write blocks.
+ cacheWay.dirtyBlocks.clear();
+
+ // Update tag
+ const qreal x = m_widthBeforeTag + (m_tagWidth / 2 - fm.horizontalAdvance("0x00000000") / 2);
+ const qreal y = transaction.lineIdx * m_lineHeight + transaction.wayIdx * m_setHeight;
+
+ QGraphicsSimpleTextItem* tagTextItem = tryCreateGraphicsTextItem(&cacheWay.tag, x, y);
+ const QString tagText = encodeRadixValue(transaction.tag, Radix::Hex);
+ tagTextItem->setText(tagText);
+ }
+
+ if (transaction.type == CacheSim::AccessType::Write) {
+ if (cacheWay.dirtyBlocks.count(transaction.blockIdx) == 0) {
+ // The block was dirtied by this transaction; create a dirty rect
+ const auto topLeft = QPointF(transaction.blockIdx * m_blockWidth + m_widthBeforeBlocks,
+ transaction.lineIdx * m_lineHeight + transaction.wayIdx * m_setHeight);
+ const auto bottomRight =
+ QPointF((transaction.blockIdx + 1) * m_blockWidth + m_widthBeforeBlocks,
+ transaction.lineIdx * m_lineHeight + (transaction.wayIdx + 1) * m_setHeight);
+ cacheWay.dirtyBlocks[transaction.blockIdx] =
+ std::make_unique<QGraphicsRectItem>(QRectF(topLeft, bottomRight), this);
+
+ const auto& dirtyRectItem = cacheWay.dirtyBlocks[transaction.blockIdx];
+ dirtyRectItem->setZValue(-1);
+ dirtyRectItem->setOpacity(0.4);
+ dirtyRectItem->setBrush(Qt::darkCyan);
+ }
}
// Update LRU fields.
@@ -102,7 +133,6 @@ void CacheGraphic::dataChanged(const CacheSim::CacheTransaction& transaction) {
}
}
}
- }
updateHighlighting(true, &transaction);
}
@@ -150,7 +180,7 @@ void CacheGraphic::updateHighlighting(bool active, const CacheSim::CacheTransact
hitRectItem->setOpacity(0.4);
hitRectItem->setBrush(Qt::green);
} else {
- hitRectItem->setOpacity(0.6);
+ hitRectItem->setOpacity(0.8);
hitRectItem->setBrush(Qt::red);
}
}

MODIFY
src/cachegraphic.h
src/cachegraphic.h
@@ -68,6 +68,7 @@ private:
QGraphicsSimpleTextItem* lru = nullptr;
QGraphicsSimpleTextItem* valid = nullptr;
QGraphicsSimpleTextItem* dirty = nullptr;
+ std::map<unsigned, std::unique_ptr<QGraphicsRectItem>> dirtyBlocks;
};
using CacheLine = std::map<unsigned, CacheWay>;

MODIFY
src/cachesim.cpp
src/cachesim.cpp
@@ -101,7 +101,6 @@ void CacheSim::evictAndUpdate(CacheTransaction& transaction) {
}
Q_ASSERT(currentWay != nullptr && "There must have been an issue with setting the LRU bits");
- updateCacheLineLRU(cacheLine, transaction.wayIdx);
}
}
@@ -111,6 +110,7 @@ void CacheSim::evictAndUpdate(CacheTransaction& transaction) {
currentWay->valid = true;
}
+ currentWay->dirty = false;
currentWay->tag = transaction.tag;
transaction.tagChanged = true;
}
@@ -133,14 +133,12 @@ void CacheSim::analyzeCacheAccess(CacheTransaction& transaction) {
transaction.isHit = false;
if (m_cacheLines.count(transaction.lineIdx) != 0) {
- int wayIdx = 0;
for (const auto& way : m_cacheLines.at(transaction.lineIdx)) {
- if (way.second.tag == transaction.tag && way.second.valid) {
- transaction.wayIdx = wayIdx;
+ if ((way.second.tag == transaction.tag) && way.second.valid) {
+ transaction.wayIdx = way.first;
transaction.isHit = true;
break;
}
- wayIdx++;
}
}
@@ -154,10 +152,11 @@ void CacheSim::analyzeCacheAccess(CacheTransaction& transaction) {
updateHitRate();
}
-void CacheSim::access(uint32_t address, AccessType access) {
+void CacheSim::access(uint32_t address, AccessType type) {
address = address & ~0b11; // Disregard unaligned accesses
CacheTransaction transaction;
transaction.address = address;
+ transaction.type = type;
analyzeCacheAccess(transaction);
@@ -165,6 +164,18 @@ void CacheSim::access(uint32_t address, AccessType access) {
evictAndUpdate(transaction);
}
+ // Lazily ensure that the located way has been initialized
+ m_cacheLines[transaction.lineIdx][transaction.wayIdx];
+
+ if (type == AccessType::Write) {
+ CacheWay& way = m_cacheLines[transaction.lineIdx][transaction.wayIdx];
+ way.dirty = true;
+ }
+
+ if (getReplacementPolicy() == ReplPolicy::LRU) {
+ updateCacheLineLRU(m_cacheLines[transaction.lineIdx], transaction.wayIdx);
+ }
+
emit dataChanged(transaction);
}

MODIFY
src/cachesim.h
src/cachesim.h
@@ -34,8 +34,7 @@ public:
unsigned tag = -1;
bool isHit = false;
- bool read = false;
- bool write = false;
+ AccessType type;
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
};

Add initial write handling in cache simulator