From a56b25212865c57251719a1d4a5d9d6a79b339c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 6 Mar 2018 21:57:07 +0100 Subject: Implement Cache configuration This commit implements both cache configuration for machine and for gui. --- qtmips_cli/qtmips_cli.pro | 3 +- qtmips_gui/NewDialog.ui | 18 ++++- qtmips_gui/NewDialogCache.ui | 54 +++++-------- qtmips_gui/newdialog.cpp | 159 ++++++++++++++++++++++++++++----------- qtmips_gui/newdialog.h | 32 +++++++- qtmips_machine/machineconfig.cpp | 99 ++++++++++++++++++++++-- qtmips_machine/machineconfig.h | 32 +++++++- 7 files changed, 299 insertions(+), 98 deletions(-) diff --git a/qtmips_cli/qtmips_cli.pro b/qtmips_cli/qtmips_cli.pro index 32952b7..fdf4a24 100644 --- a/qtmips_cli/qtmips_cli.pro +++ b/qtmips_cli/qtmips_cli.pro @@ -1,5 +1,4 @@ -QT += core -QT -= gui +QT += core gui widgets TARGET = qtmips_cli CONFIG += console diff --git a/qtmips_gui/NewDialog.ui b/qtmips_gui/NewDialog.ui index 0490ca3..3c1eaba 100644 --- a/qtmips_gui/NewDialog.ui +++ b/qtmips_gui/NewDialog.ui @@ -7,7 +7,7 @@ 0 0 558 - 254 + 316 @@ -49,10 +49,24 @@ + + + + Pipelined without hazard unit and without cache + + + + + + + Pipelined with hazard unit and without cache + + + - Pipelined and cache + Pipelined with hazard unit and cache diff --git a/qtmips_gui/NewDialogCache.ui b/qtmips_gui/NewDialogCache.ui index 072251c..5c09de6 100644 --- a/qtmips_gui/NewDialogCache.ui +++ b/qtmips_gui/NewDialogCache.ui @@ -7,7 +7,7 @@ 0 0 435 - 272 + 204 @@ -24,70 +24,43 @@ - - - Capacity: - - - - - - - Number of sets: - + - + Block size: - + - - - - Number of blocks: - - - - - - - + Degree of associativity: - - + + - + Replacement policy: - - - - Writeback policy: - - - - + @@ -111,7 +84,14 @@ - + + + + Writeback policy: + + + + diff --git a/qtmips_gui/newdialog.cpp b/qtmips_gui/newdialog.cpp index b760626..ee957cb 100644 --- a/qtmips_gui/newdialog.cpp +++ b/qtmips_gui/newdialog.cpp @@ -20,8 +20,9 @@ NewDialog::NewDialog(QWidget *parent, QSettings *settings) : QDialog(parent) { connect(ui->pushButton_load, SIGNAL(clicked(bool)), this, SLOT(create())); connect(ui->pushButton_cancel, SIGNAL(clicked(bool)), this, SLOT(cancel())); connect(ui->pushButton_browse, SIGNAL(clicked(bool)), this, SLOT(browse_elf())); - //connect(ui->preset_box, SIGNAL(clicked(bool)), this, SLOT(set_preset())); connect(ui->preset_no_pipeline, SIGNAL(toggled(bool)), this, SLOT(set_preset())); + connect(ui->preset_pipelined_bare, SIGNAL(toggled(bool)), this, SLOT(set_preset())); + connect(ui->preset_pipelined_hazard, SIGNAL(toggled(bool)), this, SLOT(set_preset())); connect(ui->preset_pipelined, SIGNAL(toggled(bool)), this, SLOT(set_preset())); connect(ui->pipelined, SIGNAL(clicked(bool)), this, SLOT(pipelined_change(bool))); @@ -32,8 +33,8 @@ NewDialog::NewDialog(QWidget *parent, QSettings *settings) : QDialog(parent) { connect(ui->mem_protec_exec, SIGNAL(clicked(bool)), this, SLOT(mem_protec_exec_change(bool))); connect(ui->mem_protec_write, SIGNAL(clicked(bool)), this, SLOT(mem_protec_write_change(bool))); - connect(ui_cache_p->enabled, SIGNAL(clicked(bool)), this, SLOT(cache_program_change(bool))); - connect(ui_cache_d->enabled, SIGNAL(clicked(bool)), this, SLOT(cache_data_change(bool))); + cache_handler_d = new NewDialogCacheHandler(this, ui_cache_d); + cache_handler_p = new NewDialogCacheHandler(this, ui_cache_p); load_settings(); // Also configures gui } @@ -46,6 +47,11 @@ NewDialog::~NewDialog() { delete config; } +void NewDialog::switch2custom() { + ui->preset_custom->setChecked(true); + config_gui(); +} + void NewDialog::closeEvent(QCloseEvent *) { load_settings(); // Reset from settings // Close main window if not already configured @@ -90,101 +96,111 @@ void NewDialog::browse_elf() { } void NewDialog::set_preset() { - if (ui->preset_no_pipeline->isChecked()) - config->preset(machine::CP_SINGLE); - else if (ui->preset_pipelined->isChecked()) - config->preset(machine::CP_PIPE_WITH_CACHE); - else - // Skip apply configuration as we changed nothing. - return; - config_gui(); + unsigned pres_n = preset_number(); + if (pres_n > 0) { + config->preset((enum machine::ConfigPresets)(pres_n - 1)); + config_gui(); + } } -// Common end section of *_change slots -#define CHANGE_COMMON do { \ - ui->preset_custom->setChecked(true); \ - config_gui(); \ - } while(false) - void NewDialog::pipelined_change(bool val) { config->set_pipelined(val); - CHANGE_COMMON; + switch2custom(); } void NewDialog::delay_slot_change(bool val) { config->set_delay_slot(val); - CHANGE_COMMON; + switch2custom(); } void NewDialog::hazard_unit_change() { - if (ui->hazard_unit->isChecked()) + if (ui->hazard_unit->isChecked()) { config->set_hazard_unit(ui->hazard_stall->isChecked() ? machine::MachineConfig::HU_STALL : machine::MachineConfig::HU_STALL_FORWARD); - else + } else { config->set_hazard_unit(machine::MachineConfig::HU_NONE); - CHANGE_COMMON; + } + switch2custom(); } void NewDialog::mem_protec_exec_change(bool v) { config->set_memory_execute_protection(v); - CHANGE_COMMON; + switch2custom(); } void NewDialog::mem_protec_write_change(bool v) { config->set_memory_write_protection(v); - CHANGE_COMMON; -} - -void NewDialog::cache_data_change(bool v) { - config->access_cache_data()->set_enabled(v); - CHANGE_COMMON; -} - -void NewDialog::cache_program_change(bool v) { - config->access_cache_program()->set_enabled(v); - CHANGE_COMMON; + switch2custom(); } void NewDialog::config_gui() { - // Set values + // Basic ui->elf_file->setText(config->elf()); + // Core ui->pipelined->setChecked(config->pipelined()); ui->delay_slot->setChecked(config->delay_slot()); ui->hazard_unit->setChecked(config->hazard_unit() != machine::MachineConfig::HU_NONE); ui->hazard_stall->setChecked(config->hazard_unit() == machine::MachineConfig::HU_STALL); ui->hazard_stall_forward->setChecked(config->hazard_unit() == machine::MachineConfig::HU_STALL_FORWARD); + // Memory ui->mem_protec_exec->setChecked(config->memory_execute_protection()); ui->mem_protec_write->setChecked(config->memory_write_protection()); ui->mem_time_read->setValue(config->memory_access_time_read()); ui->mem_time_write->setValue(config->memory_access_time_write()); - ui_cache_p->enabled->setChecked(config->cache_program().enabled()); - ui_cache_d->enabled->setChecked(config->cache_data().enabled()); + // Cache + cache_handler_d->config_gui(); + cache_handler_p->config_gui(); + // Disable various sections according to configuration ui->delay_slot->setEnabled(!config->pipelined()); ui->hazard_unit->setEnabled(config->pipelined()); } +unsigned NewDialog::preset_number() { + enum machine::ConfigPresets preset; + if (ui->preset_no_pipeline->isChecked()) + preset = machine::CP_SINGLE; + else if (ui->preset_pipelined_bare->isChecked()) + preset = machine::CP_PIPE_NO_HAZARD; + else if (ui->preset_pipelined_hazard->isChecked()) + preset = machine::CP_PIPE_NO_CACHE; + else if (ui->preset_pipelined->isChecked()) + preset = machine::CP_PIPE_CACHE; + else + return 0; + return (unsigned)preset + 1; +} + void NewDialog::load_settings() { if (config != nullptr) delete config; // Load config config = new machine::MachineConfig(settings); + cache_handler_d->set_config(config->access_cache_data()); + cache_handler_p->set_config(config->access_cache_program()); // Load preset unsigned preset = settings->value("Preset", 1).toUInt(); if (preset != 0) { - enum machine::ConfigPresets p = (enum machine::ConfigPresets)(preset - 1); + auto p = (enum machine::ConfigPresets)(preset - 1); config->preset(p); switch (p) { case machine::CP_SINGLE: ui->preset_no_pipeline->setChecked(true); break; - case machine::CP_PIPE_WITH_CACHE: + case machine::CP_PIPE_NO_HAZARD: + ui->preset_pipelined_bare->setChecked(true); + break; + case machine::CP_PIPE_NO_CACHE: + ui->preset_pipelined_hazard->setChecked(true); + break; + case machine::CP_PIPE_CACHE: ui->preset_pipelined->setChecked(true); break; } - } else + } else { ui->preset_custom->setChecked(true); + } config_gui(); } @@ -192,8 +208,65 @@ void NewDialog::load_settings() { void NewDialog::store_settings() { config->store(settings); - if (ui->preset_custom->isChecked()) + // Presets are not stored in settings so we have to store them explicitly + if (ui->preset_custom->isChecked()) { settings->setValue("Preset", 0); - else - settings->setValue("Preset", ui->preset_no_pipeline->isChecked() ? machine::CP_SINGLE + 1 : machine::CP_PIPE_WITH_CACHE + 1); + } else { + settings->setValue("Preset", preset_number()); + } +} + +NewDialogCacheHandler::NewDialogCacheHandler(NewDialog *nd, Ui::NewDialogCache *cui) { + this->nd = nd; + this->ui = cui; + this->config = nullptr; + connect(ui->enabled, SIGNAL(clicked(bool)), this, SLOT(enabled(bool))); + connect(ui->number_of_sets, SIGNAL(editingFinished()), this, SLOT(numsets())); + connect(ui->block_size, SIGNAL(editingFinished()), this, SLOT(blocksize())); + connect(ui->degree_of_associativity, SIGNAL(editingFinished()), this, SLOT(degreeassociativity())); + connect(ui->replacement_policy, SIGNAL(activated(int)), this, SLOT(replacement(int))); + connect(ui->writeback_policy, SIGNAL(activated(int)), this, SLOT(writeback(int))); +} + +void NewDialogCacheHandler::set_config(machine::MachineConfigCache *config) { + this->config = config; +} + +void NewDialogCacheHandler::config_gui() { + ui->enabled->setChecked(config->enabled()); + ui->number_of_sets->setValue(config->sets()); + ui->block_size->setValue(config->blocks()); + ui->degree_of_associativity->setValue(config->associativity()); + ui->replacement_policy->setCurrentIndex((int)config->replacement_policy()); + ui->writeback_policy->setCurrentIndex((int)config->write_policy()); +} + +void NewDialogCacheHandler::enabled(bool val) { + config->set_enabled(val); + nd->switch2custom(); +} + +void NewDialogCacheHandler::numsets() { + config->set_sets(ui->number_of_sets->value()); + nd->switch2custom(); +} + +void NewDialogCacheHandler::blocksize() { + config->set_blocks(ui->block_size->value()); + nd->switch2custom(); +} + +void NewDialogCacheHandler::degreeassociativity() { + config->set_associativity(ui->degree_of_associativity->value()); + nd->switch2custom(); +} + +void NewDialogCacheHandler::replacement(int val) { + config->set_replacement_policy((enum machine::MachineConfigCache::ReplacementPolicy)val); + nd->switch2custom(); +} + +void NewDialogCacheHandler::writeback(int val) { + config->set_write_policy((enum machine::MachineConfigCache::WritePolicy)val); + nd->switch2custom(); } diff --git a/qtmips_gui/newdialog.h b/qtmips_gui/newdialog.h index 5b50a41..79616a2 100644 --- a/qtmips_gui/newdialog.h +++ b/qtmips_gui/newdialog.h @@ -9,12 +9,16 @@ #include "ui_NewDialogCache.h" #include "machineconfig.h" +class NewDialogCacheHandler; + class NewDialog : public QDialog { Q_OBJECT public: NewDialog(QWidget *parent, QSettings *settings); ~NewDialog(); + void switch2custom(); + protected: void closeEvent(QCloseEvent *); @@ -29,9 +33,6 @@ private slots: void mem_protec_exec_change(bool); void mem_protec_write_change(bool); - void cache_data_change(bool); - void cache_program_change(bool); - private: Ui::NewDialog *ui; Ui::NewDialogCache *ui_cache_p, *ui_cache_d; @@ -40,8 +41,33 @@ private: machine::MachineConfig *config; void config_gui(); // Apply configuration to gui + unsigned preset_number(); void load_settings(); void store_settings(); + NewDialogCacheHandler *cache_handler_p, *cache_handler_d; +}; + +class NewDialogCacheHandler : QObject { + Q_OBJECT +public: + NewDialogCacheHandler(NewDialog *nd, Ui::NewDialogCache *ui); + + void set_config(machine::MachineConfigCache *config); + + void config_gui(); + +private slots: + void enabled(bool); + void numsets(); + void blocksize(); + void degreeassociativity(); + void replacement(int); + void writeback(int); + +private: + NewDialog *nd; + Ui::NewDialogCache *ui; + machine::MachineConfigCache *config; }; #endif // NEWDIALOG_H diff --git a/qtmips_machine/machineconfig.cpp b/qtmips_machine/machineconfig.cpp index ab6f2a5..ea9dc9d 100644 --- a/qtmips_machine/machineconfig.cpp +++ b/qtmips_machine/machineconfig.cpp @@ -15,36 +15,67 @@ using namespace machine; ////////////////////////////////////////////////////////////////////////////// /// Default config of MachineConfigCache #define DFC_EN false +#define DFC_SETS 1 +#define DFC_BLOCKS 1 +#define DFC_ASSOC 1 +#define DFC_REPLAC RP_RAND +#define DFC_WRITE WP_TROUGH ////////////////////////////////////////////////////////////////////////////// MachineConfigCache::MachineConfigCache() { en = DFC_EN; + n_sets = DFC_SETS; + n_blocks = DFC_BLOCKS; + d_associativity = DFC_ASSOC; + replac_pol = DFC_REPLAC; + write_pol = DFC_WRITE; } MachineConfigCache::MachineConfigCache(const MachineConfigCache *cc) { en = cc->enabled(); + n_sets = cc->sets(); + n_blocks = cc->blocks(); + d_associativity = cc->associativity(); + replac_pol = cc->replacement_policy(); + write_pol = cc->write_policy(); } #define N(STR) (prefix + QString(STR)) MachineConfigCache::MachineConfigCache(const QSettings *sts, const QString &prefix) { en = sts->value(N("Enabled"), DFC_EN).toBool(); + n_sets = sts->value(N("Sets"), DFC_SETS).toUInt(); + n_blocks = sts->value(N("Blocks"), DFC_BLOCKS).toUInt(); + d_associativity = sts->value(N("Associativity"), DFC_ASSOC).toUInt(); + replac_pol = (enum ReplacementPolicy)sts->value(N("Replacement"), DFC_REPLAC).toUInt(); + write_pol = (enum WritePolicy)sts->value(N("Write"), DFC_WRITE).toUInt(); } void MachineConfigCache::store(QSettings *sts, const QString &prefix) { - sts->setValue(N("Enabled"), en); + sts->setValue(N("Enabled"), enabled()); + sts->setValue(N("Sets"), sets()); + sts->setValue(N("Blocks"), blocks()); + sts->setValue(N("Associativity"), associativity()); + sts->setValue(N("Replacement"), (unsigned)replacement_policy()); + sts->setValue(N("Write"), (unsigned)write_policy()); } #undef N void MachineConfigCache::preset(enum ConfigPresets p) { switch (p) { - case CP_SINGLE: - set_enabled(false); + case CP_PIPE_CACHE: + set_enabled(true); + set_sets(3); + set_blocks(1); + set_associativity(1); + set_replacement_policy(RP_RAND); + set_write_policy(WP_TROUGH); break; - case CP_PIPE_WITH_CACHE: + case CP_SINGLE: + case CP_PIPE_NO_HAZARD: + case CP_PIPE_NO_CACHE: set_enabled(false); - break; } } @@ -52,13 +83,60 @@ void MachineConfigCache::set_enabled(bool v) { en = v; } +void MachineConfigCache::set_sets(unsigned v) { + // TODO verify that this is 2^N + n_sets = v; +} + +void MachineConfigCache::set_blocks(unsigned v) { + // TODO even more verifications for 2^N + n_blocks = v; +} + +void MachineConfigCache::set_associativity(unsigned v) { + d_associativity = v; +} + +void MachineConfigCache::set_replacement_policy(enum ReplacementPolicy v) { + replac_pol = v; +} + +void MachineConfigCache::set_write_policy(enum WritePolicy v) { + write_pol = v; +} + bool MachineConfigCache::enabled() const { return en; } +unsigned MachineConfigCache::sets() const { + return n_sets; +} + +unsigned MachineConfigCache::blocks() const { + return n_blocks; +} + +unsigned MachineConfigCache::associativity() const { + return d_associativity; +} + +enum MachineConfigCache::ReplacementPolicy MachineConfigCache::replacement_policy() const { + return replac_pol; +} + +enum MachineConfigCache::WritePolicy MachineConfigCache::write_policy() const { + return write_pol; +} + bool MachineConfigCache::operator==(const MachineConfigCache &c) const { #define CMP(GETTER) (GETTER)() == (c.GETTER)() - return CMP(enabled); + return CMP(enabled) && \ + CMP(sets) && \ + CMP(blocks) && \ + CMP(associativity) && \ + CMP(replacement_policy) && \ + CMP(write_policy); #undef CMP } @@ -97,7 +175,7 @@ MachineConfig::MachineConfig(const MachineConfig *cc) { MachineConfig::MachineConfig(const QSettings *sts, const QString &prefix) { pipeline = sts->value(N("Pipelined"), DF_PIPELINE).toBool(); delayslot = sts->value(N("DelaySlot"), DF_DELAYSLOT).toBool(); - hunit = (enum HazardUnit)sts->value(N("HazardUnit"), DF_HUNIT).toUInt(); // TODO probably rather save as string + hunit = (enum HazardUnit)sts->value(N("HazardUnit"), DF_HUNIT).toUInt(); exec_protect = sts->value(N("MemoryExecuteProtection"), DF_EXEC_PROTEC).toBool(); write_protect = sts->value(N("MemoryWriteProtection"), DF_WRITE_PROTEC).toBool(); mem_acc_read = sts->value(N("MemoryRead"), DF_MEM_ACC_READ).toUInt(); @@ -125,7 +203,12 @@ void MachineConfig::preset(enum ConfigPresets p) { set_pipelined(false); set_delay_slot(true); break; - case CP_PIPE_WITH_CACHE: + case CP_PIPE_NO_HAZARD: + set_pipelined(true); + set_hazard_unit(MachineConfig::HU_NONE); + break; + case CP_PIPE_CACHE: + case CP_PIPE_NO_CACHE: set_pipelined(true); set_hazard_unit(MachineConfig::HU_STALL_FORWARD); break; diff --git a/qtmips_machine/machineconfig.h b/qtmips_machine/machineconfig.h index 90c9b75..a713a4c 100644 --- a/qtmips_machine/machineconfig.h +++ b/qtmips_machine/machineconfig.h @@ -7,8 +7,10 @@ namespace machine { enum ConfigPresets { - CP_SINGLE, - CP_PIPE_WITH_CACHE + CP_SINGLE, // No pipeline cpu without cache + CP_PIPE_NO_HAZARD, // Pipelined cpu without hazard unit + CP_PIPE_NO_CACHE, // Pipelined cpu without cache + CP_PIPE_CACHE // Full pipelined cpu }; class MachineConfigCache { @@ -21,17 +23,41 @@ public: void preset(enum ConfigPresets); + enum ReplacementPolicy { + RP_RAND, // Random + RP_LRU, // Least recently used + RP_LFU, // Least frequently used + RP_ARC // Adaptive replacement cache + }; + + enum WritePolicy { + WP_TROUGH, // Write trough + WP_BACK // Write back + }; + // If cache should be used or not void set_enabled(bool); + void set_sets(unsigned); // Number of sets bits used in cache + void set_blocks(unsigned); // Number of blocks + void set_associativity(unsigned); // Degree of associativity + void set_replacement_policy(enum ReplacementPolicy); + void set_write_policy(enum WritePolicy); bool enabled() const; + unsigned sets() const; + unsigned blocks() const; + unsigned associativity() const; + enum ReplacementPolicy replacement_policy() const; + enum WritePolicy write_policy() const; bool operator ==(const MachineConfigCache &c) const; bool operator !=(const MachineConfigCache &c) const; private: bool en; - // TODO + unsigned n_sets, n_blocks, d_associativity; + enum ReplacementPolicy replac_pol; + enum WritePolicy write_pol; }; class MachineConfig { -- cgit v1.2.3