Wrap "raw" VSRTL processor model signals through ProcessorHandler
In doing so, only the processor handler has to reconnect to the processor model whenever it changes.
MODIFY
src/cachesim/cacheconfigwidget.cpp
src/cachesim/cacheconfigwidget.cpp
@@ -91,8 +91,6 @@ void CacheConfigWidget::setupPresets() {
});
}
-void CacheConfigWidget::updateCacheSize() {}
-
void CacheConfigWidget::handleConfigurationChanged() {
std::for_each(m_configItems.begin(), m_configItems.end(), [](QObject* o) { o->blockSignals(true); });

MODIFY
src/cachesim/cacheconfigwidget.h
src/cachesim/cacheconfigwidget.h
@@ -26,7 +26,6 @@ public slots:
void handleConfigurationChanged();
private:
- void updateCacheSize();
void setupPresets();
void showSizeBreakdown();
std::shared_ptr<CacheSim> m_cache;

MODIFY
src/cachesim/cacheplotwidget.cpp
src/cachesim/cacheplotwidget.cpp
@@ -247,7 +247,8 @@ std::map<CachePlotWidget::Variable, QList<QPoint>> CachePlotWidget::gatherData(u
std::map<Variable, QList<QPoint>> cacheData;
const auto& trace = m_cache->getAccessTrace();
// Sanity check to ensure that the trace is keyed with a sequence of [0:N-1] cycles
- Q_ASSERT(trace.size() == 0 || (trace.size() - 1) == trace.rbegin()->first && "Non-sequential access access trace?");
+ Q_ASSERT(((trace.size() == 0) || (trace.size() - 1) == trace.rbegin()->first) &&
+ "Non-sequential access access trace?");
for (int i = 0; i < N_Variables; i++) {
cacheData[static_cast<Variable>(i)].reserve(trace.size());

MODIFY
src/cachesim/cachesim.cpp
src/cachesim/cachesim.cpp
namespace Ripes {
void CacheInterface::reset() {
- auto nlc = m_nextLevelCache.lock();
- if (nlc) {
- static_cast<CacheInterface*>(nlc.get())->reset();
+ if (m_nextLevelCache) {
+ static_cast<CacheInterface*>(m_nextLevelCache.get())->reset();
}
}
void CacheInterface::reverse() {
- auto nlc = m_nextLevelCache.lock();
- if (nlc) {
- static_cast<CacheInterface*>(nlc.get())->reverse();
+ if (m_nextLevelCache) {
+ static_cast<CacheInterface*>(m_nextLevelCache.get())->reverse();
}
}
@@ -245,7 +243,7 @@ void CacheSim::pushAccessTrace(const CacheTransaction& transaction) {
m_accessTrace[currentCycle] = CacheAccessTrace(mostRecentTrace, transaction);
- if (!isAsynchronouslyAccessed()) {
+ if (!ProcessorHandler::isRunning()) {
emit hitrateChanged();
}
}
@@ -331,15 +329,9 @@ void CacheSim::access(uint32_t address, AccessType type) {
return;
}
- if (isAsynchronouslyAccessed()) {
- return;
- }
-
+ if (!ProcessorHandler::isRunning()) {
emit dataChanged(&transaction);
}
-
-bool CacheSim::isAsynchronouslyAccessed() const {
- return QThread::currentThread() != QApplication::instance()->thread();
}
void CacheSim::undo() {

MODIFY
src/cachesim/cachesim.h
src/cachesim/cachesim.h
@@ -26,11 +26,7 @@ public:
* 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;
- }
+ void setNextLevelCache(std::shared_ptr<CacheSim>& cache) { m_nextLevelCache = cache; }
/**
* @brief reset
@@ -44,7 +40,7 @@ protected:
* @brief m_nextLevelCache
* Pointer to the next level (logical parent) cache.
*/
- std::weak_ptr<CacheSim> m_nextLevelCache;
+ std::shared_ptr<CacheSim> m_nextLevelCache;
};
class CacheSim : public CacheInterface {
@@ -213,15 +209,6 @@ private:
*/
void updateConfiguration();
- /**
- * @brief isAsynchronouslyAccessed
- * If the processor is in its 'running' state, it is currently being executed in a separate thread. In this case,
- * cache accessing is also performed asynchronously, and we do not want to perform any signalling to the GUI (the
- * entirety of the graphical representation of the cache is invalidated and redrawn upon asynchronous running
- * finishing).
- */
- bool isAsynchronouslyAccessed() const;
-
/**
* @brief reassociateMemory
* Binds to a memory component exposed by the processor handler, based on the current cache type.

MODIFY
src/cachesim/l1cacheshim.cpp
src/cachesim/l1cacheshim.cpp
@@ -6,7 +6,11 @@ namespace Ripes {
L1CacheShim::L1CacheShim(CacheType type, QObject* parent) : CacheInterface(parent), m_type(type) {
reassociateMemory();
- connect(ProcessorHandler::get(), &ProcessorHandler::reqProcessorReset, this, &L1CacheShim::processorReset);
+ connect(ProcessorHandler::get(), &ProcessorHandler::processorChanged, this, &L1CacheShim::reassociateMemory);
+ connect(ProcessorHandler::get(), &ProcessorHandler::processorReset, this, &L1CacheShim::processorReset);
+ connect(ProcessorHandler::get(), &ProcessorHandler::processorClocked, this, &L1CacheShim::processorWasClocked);
+ connect(ProcessorHandler::get(), &ProcessorHandler::processorReversed, this, &L1CacheShim::processorReversed);
+
processorReset();
}
@@ -16,16 +20,10 @@ void L1CacheShim::access(uint32_t, AccessType) {
}
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) && m_nextLevelCache.lock()) {
+ if ((m_memory.rw || m_memory.rom) && m_nextLevelCache) {
// 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();
@@ -45,7 +43,7 @@ void L1CacheShim::processorWasClocked() {
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);
+ m_nextLevelCache->access(m_memory.rw->addr.uValue(), AccessType::Write);
}
break;
case MemOp::LB:
@@ -53,14 +51,14 @@ void L1CacheShim::processorWasClocked() {
case MemOp::LH:
case MemOp::LHU:
case MemOp::LW:
- m_nextLevelCache.lock()->access(m_memory.rw->addr.uValue(), AccessType::Read);
+ m_nextLevelCache->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);
+ m_nextLevelCache->access(m_memory.rom->addr.uValue(), AccessType::Read);
}
}

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -202,9 +202,24 @@ void ProcessorHandler::_selectProcessor(const ProcessorID& id, const QStringList
m_program = nullptr;
}
+ // Reconnect the wrappers for processor signal emission
+ m_currentProcessor->designWasClocked.Connect(this, &ProcessorHandler::processorWasClockedWrapper);
+ m_currentProcessor->designWasReset.Connect(this, &ProcessorHandler::processorResetWrapper);
+ m_currentProcessor->designWasReversed.Connect(this, &ProcessorHandler::processorReversedWrapper);
+
emit processorChanged();
}
+void ProcessorHandler::processorWasClockedWrapper() {
+ emit processorClocked();
+}
+void ProcessorHandler::processorResetWrapper() {
+ emit processorReset();
+}
+void ProcessorHandler::processorReversedWrapper() {
+ emit processorReversed();
+}
+
int ProcessorHandler::_getCurrentProgramSize() const {
if (m_program) {
const auto* textSection = m_program->getSection(TEXT_SECTION_NAME);

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -176,6 +176,14 @@ signals:
void runStarted();
void runFinished();
+ /**
+ * @brief Various signals wrapping around the direct VSRTL model emission signals. This is done to avoid relying
+ * component to having to reconnect to the VSRTL model whenever the processor changes.
+ */
+ void processorReset();
+ void processorClocked();
+ void processorReversed();
+
public slots:
void loadProgram(std::shared_ptr<Program> p);
@@ -220,6 +228,14 @@ private:
void _run();
void _stopRun();
+ /**
+ * @brief Wrapper functions for processor signal emissions. VSRTL's signal/slot library does not accept lambdas,
+ * which is why we have to make these explicit member functions.
+ */
+ void processorWasClockedWrapper();
+ void processorResetWrapper();
+ void processorReversedWrapper();
+
void createAssemblerForCurrentISA();
void setStopRunFlag();
ProcessorHandler();

Wrap "raw" VSRTL processor model signals through ProcessorHandler

In doing so, only the processor handler has to reconnect to the processor model whenever it changes.