Add user cache preset storing
MODIFY
src/cachesim/cacheconfigwidget.cpp
src/cachesim/cacheconfigwidget.cpp
#include "cacheconfigwidget.h"
#include "ui_cacheconfigwidget.h"
+#include <QInputDialog>
#include <QMessageBox>
#include <QPushButton>
#include <QSpinBox>
#include "cacheplotwidget.h"
#include "enumcombobox.h"
+#include "ripessettings.h"
namespace Ripes {
@@ -36,14 +38,19 @@ void CacheConfigWidget::setCache(std::shared_ptr<CacheSim>& cache) {
connect(m_ui->lines, QOverload<int>::of(&QSpinBox::valueChanged), m_cache.get(), &CacheSim::setLines);
connect(m_ui->replacementPolicy, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) {
- m_cache->setReplacementPolicy(qvariant_cast<CacheSim::ReplPolicy>(m_ui->replacementPolicy->itemData(index)));
- });
- connect(m_ui->wrHit, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) {
- m_cache->setWritePolicy(qvariant_cast<CacheSim::WritePolicy>(m_ui->wrHit->itemData(index)));
+ m_cache->setReplacementPolicy(qvariant_cast<ReplPolicy>(m_ui->replacementPolicy->itemData(index)));
});
+ connect(m_ui->wrHit, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ [=](int index) { m_cache->setWritePolicy(qvariant_cast<WritePolicy>(m_ui->wrHit->itemData(index))); });
connect(m_ui->wrMiss, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) {
- m_cache->setWriteAllocatePolicy(qvariant_cast<CacheSim::WriteAllocPolicy>(m_ui->wrMiss->itemData(index)));
+ m_cache->setWriteAllocatePolicy(qvariant_cast<WriteAllocPolicy>(m_ui->wrMiss->itemData(index)));
});
+ connect(m_ui->savePresetButton, &QPushButton::clicked, this, &CacheConfigWidget::storePreset);
+ m_ui->savePresetButton->setIcon(QIcon(":/icons/save.svg"));
+ m_ui->savePresetButton->setToolTip("Store cache preset");
+ connect(m_ui->removePresetButton, &QPushButton::clicked, this, &CacheConfigWidget::removePreset);
+ m_ui->removePresetButton->setIcon(QIcon(":/icons/delete.svg"));
+ m_ui->removePresetButton->setToolTip("Delete cache preset");
connect(m_cache.get(), &CacheSim::configurationChanged, this, &CacheConfigWidget::handleConfigurationChanged);
connect(m_cache.get(), &CacheSim::configurationChanged, [=] { emit configurationChanged(); });
@@ -52,35 +59,60 @@ void CacheConfigWidget::setCache(std::shared_ptr<CacheSim>& cache) {
handleConfigurationChanged();
}
+void CacheConfigWidget::storePreset() {
+ bool ok;
+ QString text = QInputDialog::getText(this, "Store cache preset", "Preset name:", QLineEdit::Normal, "", &ok);
+ if (ok && !text.isEmpty()) {
+ CachePreset preset;
+ preset.name = text;
+ preset.ways = m_ui->ways->value();
+ preset.lines = m_ui->lines->value();
+ preset.blocks = m_ui->blocks->value();
+ preset.wrPolicy = getEnumValue<WritePolicy>(m_ui->wrHit);
+ preset.wrAllocPolicy = getEnumValue<WriteAllocPolicy>(m_ui->wrMiss);
+ preset.replPolicy = getEnumValue<ReplPolicy>(m_ui->replacementPolicy);
+
+ auto presets = RipesSettings::value(RIPES_SETTING_CACHE_PRESETS).value<QList<Ripes::CachePreset>>();
+ presets.push_back(preset);
+ RipesSettings::setValue(RIPES_SETTING_CACHE_PRESETS, QVariant::fromValue(presets));
+
+ m_ui->presets->addItem(preset.name, QVariant::fromValue<CachePreset>(preset));
+ m_ui->presets->setCurrentIndex(m_ui->presets->count() - 1);
+ }
+}
+
+void CacheConfigWidget::removePreset() {
+ auto presetData = m_ui->presets->currentData();
+ if (presetData.isNull()) {
+ return;
+ }
+
+ auto preset = presetData.value<CachePreset>();
+ const QString prompt = "Are you sure you want to delete preset '" + preset.name + "'?";
+ auto button = QMessageBox::information(this, "Delete cache preset", prompt, QMessageBox::No | QMessageBox::Yes);
+ if (button != QMessageBox::Yes) {
+ return;
+ }
+
+ auto presets = RipesSettings::value(RIPES_SETTING_CACHE_PRESETS).value<QList<Ripes::CachePreset>>();
+ presets.removeOne(preset);
+ RipesSettings::setValue(RIPES_SETTING_CACHE_PRESETS, QVariant::fromValue(presets));
+ // delete preset, but keep preset data by setting an invalid index (avoids loading the next preset in the combobox)
+ const auto idxToDelete = m_ui->presets->currentIndex();
+ m_ui->presets->setCurrentIndex(-1);
+ m_ui->presets->removeItem(idxToDelete);
+}
+
void CacheConfigWidget::setupPresets() {
- std::vector<std::pair<QString, CacheSim::CachePreset>> presets;
-
- CacheSim::CachePreset preset;
- preset.wrPolicy = CacheSim::WritePolicy::WriteBack;
- preset.wrAllocPolicy = CacheSim::WriteAllocPolicy::WriteAllocate;
- preset.replPolicy = CacheSim::ReplPolicy::LRU;
-
- preset.blocks = 2;
- preset.lines = 5;
- preset.ways = 0;
- presets.push_back({"32-entry 4-word direct-mapped", preset});
-
- preset.blocks = 2;
- preset.lines = 0;
- preset.ways = 5;
- presets.push_back({"32-entry 4-word fully associative", preset});
-
- preset.blocks = 2;
- preset.lines = 4;
- preset.ways = 1;
- presets.push_back({"32-entry 4-word 2-way set associative", preset});
-
- for (const auto& it : presets) {
- m_ui->presets->addItem(it.first, QVariant::fromValue<CacheSim::CachePreset>(it.second));
+ for (const auto& preset : RipesSettings::value(RIPES_SETTING_CACHE_PRESETS).value<QList<CachePreset>>()) {
+ m_ui->presets->addItem(preset.name, QVariant::fromValue<CachePreset>(preset));
}
connect(m_ui->presets, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index) {
- const CacheSim::CachePreset _preset = qvariant_cast<CacheSim::CachePreset>(m_ui->presets->itemData(index));
+ if (index == -1) {
+ return;
+ }
+ const CachePreset _preset = qvariant_cast<CachePreset>(m_ui->presets->itemData(index));
m_justSetPreset = true;
m_cache->setPreset(_preset);
});

MODIFY
src/cachesim/cacheconfigwidget.h
src/cachesim/cacheconfigwidget.h
@@ -30,6 +30,8 @@ private:
std::shared_ptr<CacheSim> m_cache;
Ui::CacheConfigWidget* m_ui = nullptr;
std::vector<QObject*> m_configItems;
+ void storePreset();
+ void removePreset();
/**
* @brief m_justSetPreset
@@ -43,7 +45,7 @@ private:
} // namespace Ripes
// Qt Metatypes for enum combo boxes
-Q_DECLARE_METATYPE(Ripes::CacheSim::WritePolicy);
-Q_DECLARE_METATYPE(Ripes::CacheSim::WriteAllocPolicy);
-Q_DECLARE_METATYPE(Ripes::CacheSim::ReplPolicy);
-Q_DECLARE_METATYPE(Ripes::CacheSim::CachePreset);
+Q_DECLARE_METATYPE(Ripes::WritePolicy);
+Q_DECLARE_METATYPE(Ripes::WriteAllocPolicy);
+Q_DECLARE_METATYPE(Ripes::ReplPolicy);
+Q_DECLARE_METATYPE(Ripes::CachePreset);

MODIFY
src/cachesim/cacheconfigwidget.ui
src/cachesim/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>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
</property>
</widget>
</item>
+ <item>
+ <widget class="QToolButton" name="savePresetButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="removePresetButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>

MODIFY
src/cachesim/cachegraphic.cpp
src/cachesim/cachegraphic.cpp
@@ -195,7 +195,7 @@ void CacheGraphic::cacheInvalidated() {
validItem->setToolTip("Valid bit");
width += m_bitWidth;
- if (m_cache.getWritePolicy() == CacheSim::WritePolicy::WriteBack) {
+ if (m_cache.getWritePolicy() == WritePolicy::WriteBack) {
m_widthBeforeDirty = width;
// Draw dirty bit column
@@ -208,7 +208,7 @@ void CacheGraphic::cacheInvalidated() {
m_widthBeforeLRU = width;
- if (m_cache.getReplacementPolicy() == CacheSim::ReplPolicy::LRU && m_cache.getWays() > 1) {
+ if (m_cache.getReplacementPolicy() == 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";
@@ -355,13 +355,13 @@ void CacheGraphic::initializeControlBits() {
x = m_bitWidth / 2 - m_fm.width("0") / 2;
line[setIdx].valid = drawText("0", x, y);
- if (m_cache.getWritePolicy() == CacheSim::WritePolicy::WriteBack) {
+ if (m_cache.getWritePolicy() == WritePolicy::WriteBack) {
// Create dirty bit field
x = m_widthBeforeDirty + m_bitWidth / 2 - m_fm.width("0") / 2;
line[setIdx].dirty = drawText("0", x, y);
}
- if (m_cache.getReplacementPolicy() == CacheSim::ReplPolicy::LRU && m_cache.getWays() > 1) {
+ if (m_cache.getReplacementPolicy() == ReplPolicy::LRU && m_cache.getWays() > 1) {
// Create LRU field
const QString lruText = QString::number(m_cache.getWays() - 1);
x = m_widthBeforeLRU + m_lruWidth / 2 - m_fm.width(lruText) / 2;

MODIFY
src/cachesim/cachesim.h
src/cachesim/cachesim.h
#include <map>
#include <vector>
+#include <QDataStream>
#include <QObject>
#include "../external/VSRTL/core/vsrtl_register.h"
@@ -15,6 +16,45 @@ using ROMMemory = vsrtl::core::ROM<32, 32>;
namespace Ripes {
class CacheSim;
+enum WriteAllocPolicy { WriteAllocate, NoWriteAllocate };
+enum WritePolicy { WriteThrough, WriteBack };
+enum ReplPolicy { Random, LRU };
+
+struct CachePreset {
+ QString name;
+ int blocks;
+ int lines;
+ int ways;
+
+ WritePolicy wrPolicy;
+ WriteAllocPolicy wrAllocPolicy;
+ ReplPolicy replPolicy;
+
+ friend QDataStream& operator<<(QDataStream& arch, const CachePreset& object) {
+ arch << object.name;
+ arch << object.blocks;
+ arch << object.lines;
+ arch << object.ways;
+ arch << object.wrPolicy;
+ arch << object.wrAllocPolicy;
+ arch << object.replPolicy;
+ return arch;
+ }
+
+ friend QDataStream& operator>>(QDataStream& arch, CachePreset& object) {
+ arch >> object.name;
+ arch >> object.blocks;
+ arch >> object.lines;
+ arch >> object.ways;
+ arch >> object.wrPolicy;
+ arch >> object.wrAllocPolicy;
+ arch >> object.replPolicy;
+ return arch;
+ }
+
+ bool operator==(const CachePreset& other) const { return this->name == other.name; }
+};
+
class CacheInterface : public QObject {
Q_OBJECT
public:
@@ -48,25 +88,11 @@ class CacheSim : public CacheInterface {
public:
static constexpr unsigned s_invalidIndex = static_cast<unsigned>(-1);
- enum class WriteAllocPolicy { WriteAllocate, NoWriteAllocate };
- enum class WritePolicy { WriteThrough, WriteBack };
- enum class ReplPolicy { Random, LRU };
-
struct CacheSize {
unsigned bits = 0;
std::vector<QString> components;
};
- struct CachePreset {
- int blocks;
- int lines;
- int ways;
-
- WritePolicy wrPolicy;
- WriteAllocPolicy wrAllocPolicy;
- ReplPolicy replPolicy;
- };
-
struct CacheWay {
uint32_t tag = -1;
std::set<unsigned> dirtyBlocks;
@@ -269,14 +295,13 @@ private:
void pushTrace(const CacheTrace& trace);
};
-const static std::map<CacheSim::ReplPolicy, QString> s_cacheReplPolicyStrings{{CacheSim::ReplPolicy::Random, "Random"},
- {CacheSim::ReplPolicy::LRU, "LRU"}};
-const static std::map<CacheSim::WriteAllocPolicy, QString> s_cacheWriteAllocateStrings{
- {CacheSim::WriteAllocPolicy::WriteAllocate, "Write allocate"},
- {CacheSim::WriteAllocPolicy::NoWriteAllocate, "No write allocate"}};
+const static std::map<ReplPolicy, QString> s_cacheReplPolicyStrings{{ReplPolicy::Random, "Random"},
+ {ReplPolicy::LRU, "LRU"}};
+const static std::map<WriteAllocPolicy, QString> s_cacheWriteAllocateStrings{
+ {WriteAllocPolicy::WriteAllocate, "Write allocate"},
+ {WriteAllocPolicy::NoWriteAllocate, "No write allocate"}};
-const static std::map<CacheSim::WritePolicy, QString> s_cacheWritePolicyStrings{
- {CacheSim::WritePolicy::WriteThrough, "Write-through"},
- {CacheSim::WritePolicy::WriteBack, "Write-back"}};
+const static std::map<WritePolicy, QString> s_cacheWritePolicyStrings{{WritePolicy::WriteThrough, "Write-through"},
+ {WritePolicy::WriteBack, "Write-back"}};
} // namespace Ripes

MODIFY
src/ripessettings.cpp
src/ripessettings.cpp
#include "ripessettings.h"
#include "assembler/program.h"
+#include "cachesim/cachesim.h"
#include <QCoreApplication>
#include <map>
@@ -26,6 +27,14 @@ const std::map<QString, QVariant> s_defaultSettings = {
{RIPES_SETTING_PERIPHERALS_START, static_cast<unsigned>(0xF0000000)},
{RIPES_SETTING_CACHE_MAXPOINTS, 1000},
+ {RIPES_SETTING_CACHE_PRESETS,
+ QVariant::fromValue<QList<CachePreset>>(
+ {CachePreset{"32-entry 4-word direct-mapped", 2, 5, 0, WritePolicy::WriteBack, WriteAllocPolicy::WriteAllocate,
+ ReplPolicy::LRU},
+ CachePreset{"32-entry 4-word fully associative", 2, 0, 5, WritePolicy::WriteBack,
+ WriteAllocPolicy::WriteAllocate, ReplPolicy::LRU},
+ CachePreset{"32-entry 4-word 2-way set associative", 2, 4, 1, WritePolicy::WriteBack,
+ WriteAllocPolicy::WriteAllocate, ReplPolicy::LRU}})},
// Program state preserving settings
{RIPES_GLOBALSIGNAL_QUIT, 0},
@@ -68,6 +77,10 @@ RipesSettings::RipesSettings() {
QCoreApplication::setOrganizationDomain("https://github.com/mortbopet/Ripes");
QCoreApplication::setApplicationName("Ripes");
+ // Serializer registrations
+ qRegisterMetaTypeStreamOperators<CachePreset>("cachePreset");
+ qRegisterMetaTypeStreamOperators<QList<CachePreset>>("cachePresetList");
+
// Populate settings with default values if settings value is not found
QSettings settings;
for (const auto& setting : s_defaultSettings) {
@@ -95,3 +108,4 @@ QVariant RipesSettings::value(const QString& key) {
}
} // namespace Ripes
+Q_DECLARE_METATYPE(QList<Ripes::CachePreset>);

MODIFY
src/ripessettings.h
src/ripessettings.h
@@ -24,7 +24,7 @@ namespace Ripes {
#define RIPES_SETTING_PERIPHERALS_START ("peripheral_start")
#define RIPES_SETTING_CACHE_MAXPOINTS ("cacheplot_maxpoints")
-
+#define RIPES_SETTING_CACHE_PRESETS ("cache_presets")
#define RIPES_SETTING_PERIPHERAL_SETTINGS ("peripheral_settings")
// This is not really a setting, but instead a method to leverage the static observer objects that are generated for a

Add user cache preset storing