aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_machine')
-rw-r--r--qtmips_machine/cache.cpp72
-rw-r--r--qtmips_machine/cache.h9
-rw-r--r--qtmips_machine/machineconfig.cpp4
-rw-r--r--qtmips_machine/machineconfig.h3
-rw-r--r--qtmips_machine/tests/testcache.cpp2
-rw-r--r--qtmips_machine/tests/testcore.cpp29
-rw-r--r--qtmips_machine/tests/tst_machine.h6
7 files changed, 98 insertions, 27 deletions
diff --git a/qtmips_machine/cache.cpp b/qtmips_machine/cache.cpp
index f32e0e5..c1e4e7b 100644
--- a/qtmips_machine/cache.cpp
+++ b/qtmips_machine/cache.cpp
@@ -48,6 +48,8 @@ Cache::Cache(MemoryAccess *m, const MachineConfigCache *cc, unsigned memory_acc
hit_write = 0;
miss_read = 0;
miss_write = 0;
+ mem_reads = 0;
+ mem_writes = 0;
dt = nullptr;
replc.lfu = nullptr;
replc.lru = nullptr;
@@ -128,20 +130,27 @@ bool Cache::wword(std::uint32_t address, std::uint32_t value) {
if (!cnf.enabled() ||
(address >= uncached_start && address <= uncached_last)) {
+ mem_writes++;
+ emit memory_writes_update(mem_writes);
return mem->write_word(address, value);
}
std::uint32_t data;
changed = access(address, &data, true, value);
- if (cnf.write_policy() == MachineConfigCache::WP_TROUGH)
+ if (cnf.write_policy() != MachineConfigCache::WP_BACK) {
+ mem_writes++;
+ emit memory_writes_update(mem_writes);
return mem->write_word(address, value);
+ }
return changed;
}
std::uint32_t Cache::rword(std::uint32_t address, bool debug_access) const {
if (!cnf.enabled() ||
(address >= uncached_start && address <= uncached_last)) {
+ mem_reads++;
+ emit memory_reads_update(mem_reads);
return mem->read_word(address, debug_access);
}
@@ -177,20 +186,32 @@ unsigned Cache::miss() const {
return miss_read + miss_write;
}
+unsigned Cache::memory_reads() const {
+ return mem_reads;
+}
+
+unsigned Cache::memory_writes() const {
+ return mem_writes;
+}
+
unsigned Cache::stalled_cycles() const {
return miss_read * (access_pen_r - 1) + miss_write * (access_pen_w - 1);
}
double Cache::speed_improvement() const {
+ unsigned lookup_time;
unsigned comp = hit_read + hit_write + miss_read + miss_write;
if (comp == 0)
return 100.0;
+ lookup_time = hit_read + miss_read;
+ if (cnf.write_policy() == MachineConfigCache::WP_BACK)
+ lookup_time += hit_write + miss_write;
return (double)((miss_read + hit_read) * access_pen_r + (miss_write + hit_write) * access_pen_w) \
- / (double)(hit_write + hit_read + miss_read * access_pen_r + miss_write * access_pen_w) \
+ / (double)(lookup_time + mem_reads * access_pen_r + mem_writes * access_pen_w) \
* 100;
}
-double Cache::usage_efficiency() const {
+double Cache::hit_rate() const {
unsigned comp = hit_read + hit_write + miss_read + miss_write;
if (comp == 0)
return 0.0;
@@ -198,26 +219,31 @@ double Cache::usage_efficiency() const {
}
void Cache::reset() {
- if (!cnf.enabled())
- return;
-
- // Set all cells to ne invalid
- for (unsigned as = 0; as < cnf.associativity(); as++)
- for (unsigned st = 0; st < cnf.sets(); st++)
- dt[as][st].valid = false;
+ // Set all cells to invalid
+ if (cnf.enabled()) {
+ for (unsigned as = 0; as < cnf.associativity(); as++)
+ for (unsigned st = 0; st < cnf.sets(); st++)
+ dt[as][st].valid = false;
+ }
// Note: we don't have to zero replacement policy data as those are zeroed when first used on invalid cell
// Zero hit and miss rate
hit_read = 0;
hit_write = 0;
miss_read = 0;
miss_write = 0;
+ mem_reads = 0;
+ mem_writes = 0;
// Trigger signals
emit hit_update(hit());
emit miss_update(miss());
+ emit memory_reads_update(memory_reads());
+ emit memory_writes_update(memory_writes());
update_statistics();
- for (unsigned as = 0; as < cnf.associativity(); as++)
- for (unsigned st = 0; st < cnf.sets(); st++)
- emit cache_update(as, st, false, false, 0, 0);
+ if (cnf.enabled()) {
+ for (unsigned as = 0; as < cnf.associativity(); as++)
+ for (unsigned st = 0; st < cnf.sets(); st++)
+ emit cache_update(as, st, false, false, 0, 0);
+ }
}
const MachineConfigCache &Cache::config() const {
@@ -262,6 +288,12 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std::
indx++;
// Need to find new block
if (indx >= cnf.associativity()) {
+ // if write through we do not need to alloecate cache line does not allocate
+ if (write && cnf.write_policy() == MachineConfigCache::WP_TROUGH_NOALLOC) {
+ miss_write++;
+ emit miss_update(miss());
+ return false;
+ }
// We have to kick something
switch (cnf.replacement_policy()) {
case MachineConfigCache::RP_RAND:
@@ -319,6 +351,8 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std::
cd.data[i] = mem->read_word(base_address(tag, row) + (4*i));
change_counter++;
}
+ mem_reads += cnf.blocks();
+ emit memory_reads_update(mem_reads);
}
// Update replcement data
@@ -338,7 +372,10 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std::
break;
}
case MachineConfigCache::RP_LFU:
- replc.lfu[row][indx]++;
+ if (cd.valid)
+ replc.lfu[row][indx]++;
+ else
+ replc.lfu[row][indx] = 0;
break;
default:
break;
@@ -362,9 +399,12 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std::
void Cache::kick(unsigned associat_indx, unsigned row) const {
struct cache_data &cd = dt[associat_indx][row];
- if (cd.dirty && cnf.write_policy() == MachineConfigCache::WP_BACK)
+ if (cd.dirty && cnf.write_policy() == MachineConfigCache::WP_BACK) {
for (unsigned i = 0; i < cnf.blocks(); i++)
mem->write_word(base_address(cd.tag, row) + (4*i), cd.data[i]);
+ mem_writes += cnf.blocks();
+ emit memory_writes_update(mem_writes);
+ }
cd.valid = false;
cd.dirty = false;
@@ -396,5 +436,5 @@ std::uint32_t Cache::base_address(std::uint32_t tag, unsigned row) const {
}
void Cache::update_statistics() const {
- emit statistics_update(stalled_cycles(), speed_improvement(), usage_efficiency());
+ emit statistics_update(stalled_cycles(), speed_improvement(), hit_rate());
}
diff --git a/qtmips_machine/cache.h b/qtmips_machine/cache.h
index 827631b..1500aae 100644
--- a/qtmips_machine/cache.h
+++ b/qtmips_machine/cache.h
@@ -57,9 +57,11 @@ public:
unsigned hit() const; // Number of recorded hits
unsigned miss() const; // Number of recorded misses
+ unsigned memory_reads() const; // Number backing/main memory reads
+ unsigned memory_writes() const; // Number backing/main memory writes
unsigned stalled_cycles() const; // Number of wasted cycles in memory waitin statistic
double speed_improvement() const; // Speed improvement in percents in comare with no used cache
- double usage_efficiency() const; // Usage efficiency in percents
+ double hit_rate() const; // Usage efficiency in percents
void reset(); // Reset whole state of cache
@@ -72,8 +74,10 @@ public:
signals:
void hit_update(unsigned) const;
void miss_update(unsigned) const;
- void statistics_update(unsigned stalled_cycles, double speed_improv, double usage_effic) const;
+ void statistics_update(unsigned stalled_cycles, double speed_improv, double hit_rate) const;
void cache_update(unsigned associat, unsigned set, bool valid, bool dirty, std::uint32_t tag, const std::uint32_t *data) const;
+ void memory_writes_update(unsigned) const;
+ void memory_reads_update(unsigned) const;
private:
MachineConfigCache cnf;
@@ -95,6 +99,7 @@ private:
} replc; // Data used for replacement policy
mutable unsigned hit_read, miss_read, hit_write, miss_write; // Hit and miss counters
+ mutable unsigned mem_reads, mem_writes; // Dirrect access to memory
mutable std::uint32_t change_counter;
std::uint32_t debug_rword(std::uint32_t address) const;
diff --git a/qtmips_machine/machineconfig.cpp b/qtmips_machine/machineconfig.cpp
index 9cd6465..8a48ce1 100644
--- a/qtmips_machine/machineconfig.cpp
+++ b/qtmips_machine/machineconfig.cpp
@@ -54,7 +54,7 @@ using namespace machine;
#define DFC_BLOCKS 1
#define DFC_ASSOC 1
#define DFC_REPLAC RP_RAND
-#define DFC_WRITE WP_TROUGH
+#define DFC_WRITE WP_TROUGH_NOALLOC
//////////////////////////////////////////////////////////////////////////////
MachineConfigCache::MachineConfigCache() {
@@ -106,7 +106,7 @@ void MachineConfigCache::preset(enum ConfigPresets p) {
set_blocks(2);
set_associativity(2);
set_replacement_policy(RP_RAND);
- set_write_policy(WP_TROUGH);
+ set_write_policy(WP_TROUGH_NOALLOC);
break;
case CP_SINGLE:
case CP_PIPE_NO_HAZARD:
diff --git a/qtmips_machine/machineconfig.h b/qtmips_machine/machineconfig.h
index 1858a25..14676ff 100644
--- a/qtmips_machine/machineconfig.h
+++ b/qtmips_machine/machineconfig.h
@@ -65,7 +65,8 @@ public:
};
enum WritePolicy {
- WP_TROUGH, // Write trough
+ WP_TROUGH_NOALLOC, // Write trough
+ WP_TROUGH_ALLOC, // Write trough
WP_BACK // Write back
};
diff --git a/qtmips_machine/tests/testcache.cpp b/qtmips_machine/tests/testcache.cpp
index bbe1e62..92af45f 100644
--- a/qtmips_machine/tests/testcache.cpp
+++ b/qtmips_machine/tests/testcache.cpp
@@ -44,7 +44,7 @@ void MachineTests::cache_data() {
QTest::addColumn<unsigned>("miss");
MachineConfigCache cache_c;
- cache_c.set_write_policy(MachineConfigCache::WP_TROUGH);
+ cache_c.set_write_policy(MachineConfigCache::WP_TROUGH_ALLOC);
cache_c.set_enabled(true);
cache_c.set_sets(8);
cache_c.set_blocks(1);
diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp
index 65b529a..01307a5 100644
--- a/qtmips_machine/tests/testcore.cpp
+++ b/qtmips_machine/tests/testcore.cpp
@@ -835,7 +835,11 @@ void MachineTests::pipecore_nc_memory_tests_data() {
core_memory_tests_data();
}
-void MachineTests::pipecore_wt_memory_tests_data() {
+void MachineTests::pipecore_wt_na_memory_tests_data() {
+ core_memory_tests_data();
+}
+
+void MachineTests::pipecore_wt_a_memory_tests_data() {
core_memory_tests_data();
}
@@ -863,7 +867,26 @@ void MachineTests::pipecore_nc_memory_tests() {
run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code);
}
-void MachineTests::pipecore_wt_memory_tests() {
+void MachineTests::pipecore_wt_na_memory_tests() {
+ QFETCH(QVector<uint32_t>, code);
+ QFETCH(Registers, reg_init);
+ QFETCH(Registers, reg_res);
+ QFETCH(Memory, mem_init);
+ QFETCH(Memory, mem_res);
+ MachineConfigCache cache_conf;
+ cache_conf.set_enabled(true);
+ cache_conf.set_sets(2); // Number of sets
+ cache_conf.set_blocks(1); // Number of blocks
+ cache_conf.set_associativity(2); // Degree of associativity
+ cache_conf.set_replacement_policy(MachineConfigCache::RP_LRU);
+ cache_conf.set_write_policy(MachineConfigCache::WP_TROUGH_NOALLOC);
+ Cache i_cache(&mem_init, &cache_conf);
+ Cache d_cache(&mem_init, &cache_conf);
+ CorePipelined core(&reg_init, &i_cache, &d_cache, MachineConfig::HU_STALL_FORWARD);
+ run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code);
+}
+
+void MachineTests::pipecore_wt_a_memory_tests() {
QFETCH(QVector<uint32_t>, code);
QFETCH(Registers, reg_init);
QFETCH(Registers, reg_res);
@@ -875,7 +898,7 @@ void MachineTests::pipecore_wt_memory_tests() {
cache_conf.set_blocks(1); // Number of blocks
cache_conf.set_associativity(2); // Degree of associativity
cache_conf.set_replacement_policy(MachineConfigCache::RP_LRU);
- cache_conf.set_write_policy(MachineConfigCache::WP_TROUGH);
+ cache_conf.set_write_policy(MachineConfigCache::WP_TROUGH_ALLOC);
Cache i_cache(&mem_init, &cache_conf);
Cache d_cache(&mem_init, &cache_conf);
CorePipelined core(&reg_init, &i_cache, &d_cache, MachineConfig::HU_STALL_FORWARD);
diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h
index 0f9d753..938a9a8 100644
--- a/qtmips_machine/tests/tst_machine.h
+++ b/qtmips_machine/tests/tst_machine.h
@@ -91,11 +91,13 @@ private Q_SLOTS:
void pipecorestall_alu_forward_data();
void singlecore_memory_tests_data();
void pipecore_nc_memory_tests_data();
- void pipecore_wt_memory_tests_data();
+ void pipecore_wt_na_memory_tests_data();
+ void pipecore_wt_a_memory_tests_data();
void pipecore_wb_memory_tests_data();
void singlecore_memory_tests();
void pipecore_nc_memory_tests();
- void pipecore_wt_memory_tests();
+ void pipecore_wt_na_memory_tests();
+ void pipecore_wt_a_memory_tests();
void pipecore_wb_memory_tests();
// Cache
void cache_data();