aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine/cache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_machine/cache.cpp')
-rw-r--r--qtmips_machine/cache.cpp91
1 files changed, 91 insertions, 0 deletions
diff --git a/qtmips_machine/cache.cpp b/qtmips_machine/cache.cpp
index 152b1c7..0f8bd1a 100644
--- a/qtmips_machine/cache.cpp
+++ b/qtmips_machine/cache.cpp
@@ -1,3 +1,94 @@
#include "cache.h"
using namespace machine;
+
+Cache::Cache(Memory *m, MachineConfigCache *cc) : cnf(cc) {
+ mem = m;
+ // Allocate cache data structure
+ dt = new struct cache_data*[cc->associativity()];
+ for (unsigned i = 0; i < cc->associativity(); i++) {
+ dt[i] = new cache_data[cc->sets()];
+ for (unsigned y = 0; y < cc->sets(); y++) {
+ dt[i][y].valid = false;
+ dt[i][y].data = new std::uint32_t[cc->blocks()];
+ }
+ }
+ // Zero hit and miss rate
+ hitc = 0;
+ missc = 0;
+}
+
+void Cache::wword(std::uint32_t address, std::uint32_t value) {
+ std::uint32_t *data;
+ access(address, &data, false);
+ *data = value;
+
+ if (cnf.write_policy() == MachineConfigCache::WP_TROUGH)
+ mem->wword(address, value);
+}
+
+std::uint32_t Cache::rword(std::uint32_t address) const {
+ std::uint32_t *data;
+ access(address, &data, true);
+ return *data;
+}
+
+void Cache::flush() {
+ for (unsigned as = 0; as < cnf.associativity(); as++) {
+ for (unsigned st = 0; st < cnf.sets(); st++) {
+ struct cache_data &cd = dt[as][st];
+ if (cnf.write_policy() == MachineConfigCache::WP_BACK && cd.valid && cd.dirty) {
+ std::uint32_t base_address = cd.tag * cnf.blocks() * cnf.sets();
+ for (unsigned i = 0; i < cnf.blocks(); i++)
+ mem->wword(base_address + (4*i), cd.data[i]);
+ }
+ cd.dirty = false;
+ cd.valid = false;
+ }
+ }
+}
+
+unsigned Cache::hit() {
+ return hitc;
+}
+
+unsigned Cache::miss() {
+ return missc;
+}
+
+void Cache::access(std::uint32_t address, std::uint32_t **data, bool read) const {
+ // TODO associativity
+ address = address >> 2;
+ unsigned ssize = cnf.blocks() * cnf.sets();
+ std::uint32_t tag = address / ssize;
+ std::uint32_t base_address = ((address / cnf.blocks()) * cnf.blocks()) << 2;
+ std::uint32_t index = address % ssize;
+ std::uint32_t row = index / cnf.blocks();
+ std::uint32_t col = index % cnf.blocks();
+
+ struct cache_data &cd = dt[0][row];
+
+ // Verify if we are not replacing
+ if (cd.tag != tag && cd.valid) {
+ if (cd.dirty && cnf.write_policy() == MachineConfigCache::WP_BACK)
+ for (unsigned i = 0; i < cnf.blocks(); i++)
+ mem->wword(base_address + (4*i), cd.data[i]);
+ cd.valid = false;
+ cd.dirty = false;
+ }
+
+ if (cd.valid) {
+ hitc++;
+ } else {
+ missc++;
+ if (read) { // If this is read and we don't have valid content then read it from memory
+ for (unsigned i = 0; i < cnf.blocks(); i++)
+ cd.data[i] = mem->rword(base_address + (4*i));
+ }
+ }
+
+ cd.valid = true; // We either write to it or we read from memory. Either way it's valid when we leave Cache class
+ cd.dirty = cd.dirty || !read;
+ cd.tag = tag;
+ *data = &cd.data[col];
+}