Add CacheInterface for making CacheSims stackable
The L1CacheShim has been added to wrap around the VSRTL memory elements in the processor, into the cache simulator.
MODIFY
src/cachesim/cacheconfigwidget.h
src/cachesim/cacheconfigwidget.h
@@ -16,7 +16,7 @@ public:
CacheConfigWidget(QWidget* parent);
~CacheConfigWidget() override;
- void setCache(CacheSim* cache);
+ void setCache(std::shared_ptr<CacheSim>& cache);
signals:
void configurationChanged();
@@ -31,7 +31,7 @@ private:
void updateIndexingText();
void setupPresets();
void showSizeBreakdown();
- CacheSim* m_cache;
+ std::shared_ptr<CacheSim> m_cache;
Ui::CacheConfigWidget* m_ui = nullptr;
std::vector<QObject*> m_configItems;

MODIFY
src/cachesim/cachegraphic.cpp
src/cachesim/cachegraphic.cpp
@@ -25,12 +25,11 @@ std::set<TK> keys(std::map<TK, TV> const& input_map) {
namespace Ripes {
CacheGraphic::CacheGraphic(CacheSim& cache) : QGraphicsObject(nullptr), m_cache(cache), m_fm(m_font) {
- connect(&cache, &CacheSim::configurationChanged, this, &CacheGraphic::cacheParametersChanged);
connect(&cache, &CacheSim::dataChanged, this, &CacheGraphic::dataChanged);
connect(&cache, &CacheSim::wayInvalidated, this, &CacheGraphic::wayInvalidated);
connect(&cache, &CacheSim::cacheInvalidated, this, &CacheGraphic::cacheInvalidated);
- cacheParametersChanged();
+ cacheInvalidated();
}
void CacheGraphic::updateLineReplFields(unsigned lineIdx) {
@@ -170,6 +169,108 @@ std::unique_ptr<QGraphicsSimpleTextItem> CacheGraphic::createGraphicsTextItemSP(
}
void CacheGraphic::cacheInvalidated() {
+ // Remove all items
+ m_highlightingItems.clear();
+ m_cacheTextItems.clear();
+ for (const auto& item : childItems())
+ delete item;
+
+ // Determine cell dimensions
+ m_setHeight = m_fm.height();
+ m_lineHeight = m_setHeight * m_cache.getWays();
+ m_blockWidth = m_fm.width(" 0x00000000 ");
+ m_bitWidth = m_fm.width("00");
+ m_lruWidth = m_fm.width(QString::number(m_cache.getWays()) + " ");
+ m_cacheHeight = m_lineHeight * m_cache.getLines();
+ m_tagWidth = m_blockWidth;
+
+ // Draw cache:
+ new QGraphicsLineItem(0, 0, 0, m_cacheHeight, this);
+
+ qreal width = 0;
+ // Draw valid bit column
+ new QGraphicsLineItem(m_bitWidth, 0, m_bitWidth, m_cacheHeight, this);
+ const QString validBitText = "V";
+ auto* validItem = drawText(validBitText, 0, -m_fm.height());
+ validItem->setToolTip("Valid bit");
+ width += m_bitWidth;
+
+ if (m_cache.getWritePolicy() == CacheSim::WritePolicy::WriteBack) {
+ m_widthBeforeDirty = width;
+
+ // Draw dirty bit column
+ new QGraphicsLineItem(width + m_bitWidth, 0, width + m_bitWidth, m_cacheHeight, this);
+ const QString dirtyBitText = "D";
+ auto* dirtyItem = drawText(dirtyBitText, m_widthBeforeDirty, -m_fm.height());
+ dirtyItem->setToolTip("Dirty bit");
+ width += m_bitWidth;
+ }
+
+ m_widthBeforeLRU = width;
+
+ if (m_cache.getReplacementPolicy() == CacheSim::ReplPolicy::LRU && m_cache.getWays() > 1) {
+ // Draw LRU bit column
+ new QGraphicsLineItem(width + m_lruWidth, 0, width + m_lruWidth, m_cacheHeight, this);
+ const QString LRUBitText = "LRU";
+ auto* textItem = drawText(LRUBitText, width + m_lruWidth / 2 - m_fm.width(LRUBitText) / 2, -m_fm.height());
+ textItem->setToolTip("Least Recently Used bits");
+ width += m_lruWidth;
+ }
+
+ m_widthBeforeTag = width;
+
+ // Draw tag column
+ new QGraphicsLineItem(m_tagWidth + width, 0, m_tagWidth + width, m_cacheHeight, this);
+ const QString tagText = "Tag";
+ drawText(tagText, width + m_tagWidth / 2 - m_fm.width(tagText) / 2, -m_fm.height());
+ width += m_tagWidth;
+
+ m_widthBeforeBlocks = width;
+
+ // Draw horizontal lines between cache blocks
+ for (int i = 0; i < m_cache.getBlocks(); i++) {
+ const QString blockText = "Block " + QString::number(i);
+ drawText(blockText, width + m_tagWidth / 2 - m_fm.width(blockText) / 2, -m_fm.height());
+ width += m_blockWidth;
+ new QGraphicsLineItem(width, 0, width, m_cacheHeight, this);
+ }
+
+ m_cacheWidth = width;
+
+ // Draw cache line rows
+ for (int i = 0; i <= m_cache.getLines(); i++) {
+ 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.getWays(); j++) {
+ verticalAdvance += m_setHeight;
+ auto* setLine = new QGraphicsLineItem(0, verticalAdvance, m_cacheWidth, 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 * m_lineHeight + m_lineHeight / 2 - m_setHeight / 2;
+ const qreal x = -m_fm.width(text) * 1.2;
+ drawText(text, x, y);
+ }
+
+ // Draw index column text
+ const QString indexText = "Index";
+ const qreal x = -m_fm.width(indexText) * 1.2;
+ drawText(indexText, x, -m_fm.height());
+
+ initializeControlBits();
+
+ // Update all entries in the cache
for (int lineIdx = 0; lineIdx < m_cache.getLines(); lineIdx++) {
if (const auto* line = m_cache.getLine(lineIdx)) {
for (const auto& way : *line) {
@@ -276,109 +377,4 @@ QRectF CacheGraphic::boundingRect() const {
return childrenBoundingRect();
}
-void CacheGraphic::cacheParametersChanged() {
- // Remove all items
- m_highlightingItems.clear();
- m_cacheTextItems.clear();
- const auto children = childItems();
- for (const auto& item : qAsConst(children)) {
- delete item;
- }
-
- // Determine cell dimensions
- m_setHeight = m_fm.height();
- m_lineHeight = m_setHeight * m_cache.getWays();
- m_blockWidth = m_fm.width(" 0x00000000 ");
- m_bitWidth = m_fm.width("00");
- m_lruWidth = m_fm.width(QString::number(m_cache.getWays()) + " ");
- m_cacheHeight = m_lineHeight * m_cache.getLines();
- m_tagWidth = m_blockWidth;
-
- // Draw cache:
- new QGraphicsLineItem(0, 0, 0, m_cacheHeight, this);
-
- qreal width = 0;
- // Draw valid bit column
- new QGraphicsLineItem(m_bitWidth, 0, m_bitWidth, m_cacheHeight, this);
- const QString validBitText = "V";
- auto* validItem = drawText(validBitText, 0, -m_fm.height());
- validItem->setToolTip("Valid bit");
- width += m_bitWidth;
-
- if (m_cache.getWritePolicy() == CacheSim::WritePolicy::WriteBack) {
- m_widthBeforeDirty = width;
-
- // Draw dirty bit column
- new QGraphicsLineItem(width + m_bitWidth, 0, width + m_bitWidth, m_cacheHeight, this);
- const QString dirtyBitText = "D";
- auto* dirtyItem = drawText(dirtyBitText, m_widthBeforeDirty, -m_fm.height());
- dirtyItem->setToolTip("Dirty bit");
- width += m_bitWidth;
- }
-
- m_widthBeforeLRU = width;
-
- if (m_cache.getReplacementPolicy() == CacheSim::ReplPolicy::LRU && m_cache.getWays() > 1) {
- // Draw LRU bit column
- new QGraphicsLineItem(width + m_lruWidth, 0, width + m_lruWidth, m_cacheHeight, this);
- const QString LRUBitText = "LRU";
- auto* textItem = drawText(LRUBitText, width + m_lruWidth / 2 - m_fm.width(LRUBitText) / 2, -m_fm.height());
- textItem->setToolTip("Least Recently Used bits");
- width += m_lruWidth;
- }
-
- m_widthBeforeTag = width;
-
- // Draw tag column
- new QGraphicsLineItem(m_tagWidth + width, 0, m_tagWidth + width, m_cacheHeight, this);
- const QString tagText = "Tag";
- drawText(tagText, width + m_tagWidth / 2 - m_fm.width(tagText) / 2, -m_fm.height());
- width += m_tagWidth;
-
- m_widthBeforeBlocks = width;
-
- // Draw horizontal lines between cache blocks
- for (int i = 0; i < m_cache.getBlocks(); i++) {
- const QString blockText = "Block " + QString::number(i);
- drawText(blockText, width + m_tagWidth / 2 - m_fm.width(blockText) / 2, -m_fm.height());
- width += m_blockWidth;
- new QGraphicsLineItem(width, 0, width, m_cacheHeight, this);
- }
-
- m_cacheWidth = width;
-
- // Draw cache line rows
- for (int i = 0; i <= m_cache.getLines(); i++) {
- 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.getWays(); j++) {
- verticalAdvance += m_setHeight;
- auto* setLine = new QGraphicsLineItem(0, verticalAdvance, m_cacheWidth, 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 * m_lineHeight + m_lineHeight / 2 - m_setHeight / 2;
- const qreal x = -m_fm.width(text) * 1.2;
- drawText(text, x, y);
- }
-
- // Draw index column text
- const QString indexText = "Index";
- const qreal x = -m_fm.width(indexText) * 1.2;
- drawText(indexText, x, -m_fm.height());
-
- initializeControlBits();
-}
-
} // namespace Ripes

MODIFY
src/cachesim/cachesim.cpp
src/cachesim/cachesim.cpp
namespace Ripes {
-CacheSim::CacheSim(QObject* parent) : QObject(parent) {
- connect(ProcessorHandler::get(), &ProcessorHandler::reqProcessorReset, this, &CacheSim::processorReset);
+void CacheInterface::reset() {
+ auto nlc = m_nextLevelCache.lock();
+ if (nlc) {
+ static_cast<CacheInterface*>(nlc.get())->reset();
+ }
+}
+
+void CacheInterface::reverse() {
+ auto nlc = m_nextLevelCache.lock();
+ if (nlc) {
+ static_cast<CacheInterface*>(nlc.get())->reverse();
+ }
+}
+CacheSim::CacheSim(QObject* parent) : CacheInterface(parent) {
connect(ProcessorHandler::get(), &ProcessorHandler::runFinished, this, [=] {
// Given that we are not updating the graphical state of the cache simulator whilst the processor is running,
// once running is finished, the entirety of the cache view should be reloaded in the graphical view.
@@ -20,24 +32,7 @@ CacheSim::CacheSim(QObject* parent) : QObject(parent) {
emit cacheInvalidated();
});
- updateConfiguration();
-}
-
-void CacheSim::setType(CacheSim::CacheType type) {
- m_type = type;
- reassociateMemory();
-}
-
-void CacheSim::reassociateMemory() {
- if (m_type == CacheType::DataCache) {
- m_memory.rw = ProcessorHandler::getDataMemory();
- Q_ASSERT(m_memory.rw != nullptr);
- } else if (m_type == CacheType::InstrCache) {
- m_memory.rom = ProcessorHandler::getInstrMemory();
- Q_ASSERT(m_memory.rom != nullptr);
- } else {
- Q_ASSERT(false);
- }
+ emit configurationChanged();
}
void CacheSim::updateCacheLineReplFields(CacheLine& line, unsigned wayIdx) {
@@ -435,47 +430,7 @@ const CacheSim::CacheLine* CacheSim::getLine(unsigned idx) const {
}
}
-void CacheSim::processorWasClocked() {
- if (m_type == CacheType::DataCache) {
- AccessType type;
- // Determine whether the memory is being accessed in the current cycle, and if so, the access type.
- switch (m_memory.rw->op.uValue()) {
- case MemOp::SB:
- case MemOp::SH:
- case MemOp::SW:
- if (m_memory.rw->wr_en.uValue() == 1) {
- type = AccessType::Write;
- break;
- } else {
- // Nothing to do
- return;
- }
- case MemOp::LB:
- case MemOp::LBU:
- case MemOp::LH:
- case MemOp::LHU:
- case MemOp::LW:
- type = AccessType::Read;
- break;
- case MemOp::NOP:
- default:
- // Nothing to do
- return;
- }
-
- if (m_memory.rw && m_memory.rw->mem->accessRegion() == vsrtl::core::AddressSpace::RegionType::IO) {
- // Skip accesses to IO (write-through)
- return;
- }
-
- access(m_memory.rw->addr.uValue(), type);
- } else {
- // ROM; read in every cycle
- access(m_memory.rom->addr.uValue(), AccessType::Read);
- }
-}
-
-void CacheSim::processorWasReversed() {
+void CacheSim::reverse() {
if (m_accessTrace.size() == 0) {
// Nothing to reverse
return;
@@ -489,80 +444,65 @@ void CacheSim::processorWasReversed() {
// It is now safe to undo the cycle at the top of our access stack(s).
undo();
+
+ CacheInterface::reverse();
}
-void CacheSim::updateConfiguration() {
- // Cache configuration changed. Reset all state
+void CacheSim::reset() {
+ /** see comment of m_isResetting */
+ if (m_isResetting) {
+ return;
+ }
+
+ m_isResetting = true;
+
m_cacheLines.clear();
m_accessTrace.clear();
m_traceStack.clear();
// 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;
+ m_isResetting = false;
- // Reset the graphical view & processor
- emit configurationChanged();
-
- if (m_memory.rw || m_memory.rom) {
- // Reload the initial (cycle 0) state of the processor. This is necessary to reflect ie. the instruction which
- // is loaded from the instruction memory in cycle 0.
- processorWasClocked();
- }
-}
-
-void CacheSim::processorReset() {
- /** see comment of m_isResetting */
- if (m_isResetting) {
- return;
- }
+ emit hitrateChanged();
+ emit cacheInvalidated();
- m_isResetting = true;
- // The processor might have changed. Since our signals/slot library cannot check for existing connection, we do the
- // safe, slightly redundant, thing of disconnecting and reconnecting the VSRTL design update signals.
- reassociateMemory();
- auto* proc = ProcessorHandler::getProcessorNonConst();
- proc->designWasClocked.Connect(this, &CacheSim::processorWasClocked);
- proc->designWasReversed.Connect(this, &CacheSim::processorWasReversed);
- proc->designWasReset.Connect(this, &CacheSim::processorReset);
-
- updateConfiguration();
- m_isResetting = false;
+ CacheInterface::reset();
}
void CacheSim::setBlocks(unsigned blocks) {
m_blocks = blocks;
- processorReset();
+ emit configurationChanged();
}
+
void CacheSim::setLines(unsigned lines) {
m_lines = lines;
- processorReset();
+ emit configurationChanged();
}
+
void CacheSim::setWays(unsigned ways) {
m_ways = ways;
- processorReset();
+ emit configurationChanged();
}
void CacheSim::setWritePolicy(WritePolicy policy) {
m_wrPolicy = policy;
- processorReset();
+ emit configurationChanged();
}
void CacheSim::setWriteAllocatePolicy(WriteAllocPolicy policy) {
m_wrAllocPolicy = policy;
- processorReset();
+ emit configurationChanged();
}
void CacheSim::setReplacementPolicy(ReplPolicy policy) {
m_replPolicy = policy;
- processorReset();
+ emit configurationChanged();
}
void CacheSim::setPreset(const CachePreset& preset) {
@@ -573,7 +513,7 @@ void CacheSim::setPreset(const CachePreset& preset) {
m_wrAllocPolicy = preset.wrAllocPolicy;
m_replPolicy = preset.replPolicy;
- processorReset();
+ emit configurationChanged();
}
} // namespace Ripes

MODIFY
src/cachesim/cachesim.h
src/cachesim/cachesim.h
@@ -13,8 +13,41 @@ using RWMemory = vsrtl::core::RVMemory<32, 32>;
using ROMMemory = vsrtl::core::ROM<32, 32>;
namespace Ripes {
+class CacheSim;
-class CacheSim : public QObject {
+class CacheInterface : public QObject {
+ Q_OBJECT
+public:
+ CacheInterface(QObject* parent) : QObject(parent) {}
+ enum class AccessType { Read, Write };
+
+ /**
+ * @brief access
+ * A function called by the logical "child" of this cache, indicating that it desires to access this cache
+ */
+ virtual void access(uint32_t address, AccessType type) = 0;
+
+ void setNextLevelCache(std::shared_ptr<CacheSim>& cache) {
+ Q_ASSERT(!m_nextLevelCache.lock());
+ m_nextLevelCache = cache;
+ }
+
+ /**
+ * @brief reset
+ * Called by the logical child of this cache to propagating cache resetting or reversing up the cache hierarchy.
+ */
+ virtual void reset();
+ virtual void reverse();
+
+protected:
+ /**
+ * @brief m_nextLevelCache
+ * Pointer to the next level (logical parent) cache.
+ */
+ std::weak_ptr<CacheSim> m_nextLevelCache;
+};
+
+class CacheSim : public CacheInterface {
Q_OBJECT
public:
static constexpr unsigned s_invalidIndex = static_cast<unsigned>(-1);
@@ -22,8 +55,6 @@ public:
enum class WriteAllocPolicy { WriteAllocate, NoWriteAllocate };
enum class WritePolicy { WriteThrough, WriteBack };
enum class ReplPolicy { Random, LRU };
- enum class AccessType { Read, Write };
- enum class CacheType { DataCache, InstrCache };
struct CacheSize {
unsigned bits = 0;
@@ -93,14 +124,13 @@ public:
using CacheLine = std::map<unsigned, CacheWay>;
CacheSim(QObject* parent);
- void setType(CacheType type);
void setWritePolicy(WritePolicy policy);
void setWriteAllocatePolicy(WriteAllocPolicy policy);
void setReplacementPolicy(ReplPolicy policy);
- void access(uint32_t address, AccessType type);
+ void access(uint32_t address, AccessType type) override;
void undo();
- void processorReset();
+ void reset() override;
WriteAllocPolicy getWriteAllocPolicy() const { return m_wrAllocPolicy; }
ReplPolicy getReplacementPolicy() const { return m_replPolicy; }
@@ -141,11 +171,10 @@ public slots:
void setPreset(const CacheSim::CachePreset& preset);
/**
- * @brief processorWasClocked/processorWasReversed
- * Slot functions for clocked/Reversed signals emitted by the currently attached processor.
+ * @brief reverse
+ * Slot functions for Reversed signals emitted by the currently attached processor.
*/
- void processorWasClocked();
- void processorWasReversed();
+ void reverse() override;
signals:
void configurationChanged();
@@ -175,7 +204,6 @@ private:
std::pair<unsigned, CacheSim::CacheWay*> locateEvictionWay(const CacheTransaction& transaction);
CacheWay evictAndUpdate(CacheTransaction& transaction);
void analyzeCacheAccess(CacheTransaction& transaction) const;
- void updateConfiguration();
void pushAccessTrace(const CacheTransaction& transaction);
void popAccessTrace();
/**
@@ -205,18 +233,6 @@ private:
int m_lines = 5; // Some power of 2
int m_ways = 0; // Some power of 2
- /**
- * @brief m_memory
- * The cache simulator may be attached to either a ROM or a Read/Write memory element. Accessing the underlying
- * VSRTL component signals are dependent on the given type of the memory.
- */
- CacheType m_type;
- union {
- RWMemory const* rw = nullptr;
- ROMMemory const* rom;
-
- } m_memory;
-
/**
* @brief m_cacheLines
* The datastructure for storing our cache hierachy, as per the current cache configuration.

MODIFY
src/cachesim/cachewidget.cpp
src/cachesim/cachewidget.cpp
@@ -12,7 +12,7 @@ CacheWidget::CacheWidget(QWidget* parent) : QWidget(parent), m_ui(new Ui::CacheW
m_ui->setupUi(this);
auto* scene = new QGraphicsScene(this);
- m_cacheSim = new CacheSim(this);
+ m_cacheSim = std::make_shared<CacheSim>(this);
m_ui->cacheConfig->setCache(m_cacheSim);
auto* cacheGraphic = new CacheGraphic(*m_cacheSim);
@@ -22,11 +22,11 @@ CacheWidget::CacheWidget(QWidget* parent) : QWidget(parent), m_ui(new Ui::CacheW
connect(m_ui->cacheView, &CacheView::cacheAddressSelected,
[=](uint32_t address) { emit cacheAddressSelected(address); });
- connect(m_cacheSim, &CacheSim::configurationChanged, [=] { emit configurationChanged(); });
+ connect(m_cacheSim.get(), &CacheSim::configurationChanged, [=] { emit configurationChanged(); });
}
-void CacheWidget::setType(CacheSim::CacheType type) {
- m_cacheSim->setType(type);
+void CacheWidget::setNextLevelCache(std::shared_ptr<CacheSim>& cache) {
+ m_cacheSim.get()->setNextLevelCache(cache);
}
CacheWidget::~CacheWidget() {

MODIFY
src/cachesim/cachewidget.h
src/cachesim/cachewidget.h
@@ -21,7 +21,9 @@ public:
explicit CacheWidget(QWidget* parent = nullptr);
~CacheWidget();
- void setType(CacheSim::CacheType type);
+ void setNextLevelCache(std::shared_ptr<CacheSim>& cache);
+
+ std::shared_ptr<CacheSim>& getCacheSim() { return m_cacheSim; }
signals:
void cacheAddressSelected(uint32_t);
@@ -29,7 +31,7 @@ signals:
private:
Ui::CacheWidget* m_ui;
- CacheSim* m_cacheSim = nullptr;
+ std::shared_ptr<CacheSim> m_cacheSim;
};
} // namespace Ripes

ADD
src/cachesim/l1cacheshim.cpp
+#include "l1cacheshim.h"
+
+#include "processorhandler.h"
+
+namespace Ripes {
+
+L1CacheShim::L1CacheShim(CacheType type, QObject* parent) : CacheInterface(parent), m_type(type) {
+ reassociateMemory();
+ connect(ProcessorHandler::get(), &ProcessorHandler::reqProcessorReset, this, &L1CacheShim::processorReset);
+}
+
+void L1CacheShim::access(uint32_t, AccessType) {
+ // Should never occur; the shim determines accesses based on investigating the associated memory.
+ Q_ASSERT(false);
+}
+
+void L1CacheShim::processorReset() {
+ auto* proc = ProcessorHandler::getProcessorNonConst();
+ reassociateMemory();
+ proc->designWasClocked.Connect(this, &L1CacheShim::processorWasClocked);
+ proc->designWasReset.Connect(this, &L1CacheShim::processorReset);
+ proc->designWasReversed.Connect(this, &L1CacheShim::processorReversed);
+
+ // Propagate a reset through the cache hierarchy
+ CacheInterface::reset();
+
+ if (m_memory.rw || m_memory.rom) {
+ // Reload the initial (cycle 0) state of the processor. This is necessary to reflect ie. the instruction which
+ // is loaded from the instruction memory in cycle 0.
+ processorWasClocked();
+ }
+}
+
+void L1CacheShim::processorReversed() {
+ // Start propagating a reverse call through the cache hierarchy
+ CacheInterface::reverse();
+}
+
+void L1CacheShim::processorWasClocked() {
+ if (m_type == CacheType::DataCache) {
+ // Determine whether the memory is being accessed in the current cycle, and if so, the access type.
+ switch (m_memory.rw->op.uValue()) {
+ case MemOp::SB:
+ case MemOp::SH:
+ case MemOp::SW:
+ if (m_memory.rw->wr_en.uValue() == 1) {
+ m_nextLevelCache.lock()->access(m_memory.rw->addr.uValue(), AccessType::Write);
+ break;
+ }
+ case MemOp::LB:
+ case MemOp::LBU:
+ case MemOp::LH:
+ case MemOp::LHU:
+ case MemOp::LW:
+ m_nextLevelCache.lock()->access(m_memory.rw->addr.uValue(), AccessType::Read);
+ break;
+ case MemOp::NOP:
+ default:
+ break;
+ }
+ } else {
+ m_nextLevelCache.lock()->access(m_memory.rom->addr.uValue(), AccessType::Read);
+ }
+}
+
+void L1CacheShim::reassociateMemory() {
+ if (m_type == CacheType::DataCache) {
+ m_memory.rw = ProcessorHandler::getDataMemory();
+ Q_ASSERT(m_memory.rw != nullptr);
+ } else if (m_type == CacheType::InstrCache) {
+ m_memory.rom = ProcessorHandler::getInstrMemory();
+ Q_ASSERT(m_memory.rom != nullptr);
+ } else {
+ Q_ASSERT(false);
+ }
+}
+
+} // namespace Ripes

ADD
src/cachesim/l1cacheshim.h
+#pragma once
+
+#include <QObject>
+
+#include "cachesim.h"
+
+namespace Ripes {
+
+/**
+ * @brief The CacheShim class
+ * Provides a wrapper around the current processor models' data- and instruction memories, to be used in the cache
+ * simulator interface.
+ */
+class L1CacheShim : public CacheInterface {
+ Q_OBJECT
+public:
+ enum class CacheType { DataCache, InstrCache };
+ L1CacheShim(CacheType type, QObject* parent);
+ void access(uint32_t address, AccessType type) override;
+
+ void setType(CacheType type);
+ void reassociateMemory();
+
+private:
+ void processorReset();
+ void processorWasClocked();
+ void processorReversed();
+
+ /**
+ * @brief m_memory
+ * The cache simulator may be attached to either a ROM or a Read/Write memory element. Accessing the underlying
+ * VSRTL component signals are dependent on the given type of the memory.
+ */
+ CacheType m_type;
+ union {
+ RWMemory const* rw = nullptr;
+ ROMMemory const* rom;
+
+ } m_memory;
+};
+
+} // namespace Ripes

Add CacheInterface for making CacheSims stackable

The L1CacheShim has been added to wrap around the VSRTL memory elements in the processor, into the cache simulator.