summaryrefslogtreecommitdiff
path: root/src/cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cache.cc')
-rw-r--r--src/cache.cc180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/cache.cc b/src/cache.cc
new file mode 100644
index 0000000..80f59ef
--- /dev/null
+++ b/src/cache.cc
@@ -0,0 +1,180 @@
+#include "cache.h"
+#include "definitions.h"
+#include "response.h"
+#include "utils.h"
+#include <bits/stdc++.h>
+#include <iostream>
+#include <iterator>
+
+Cache::Cache(Storage *lower, int delay)
+{
+ this->data = new std::vector<std::array<signed int, LINE_SIZE>>;
+ this->data->resize(L1_CACHE_LINES);
+ this->delay = delay;
+ this->is_waiting = false;
+ this->lower = lower;
+ this->meta.fill({-1, -1});
+ this->requester = IDLE;
+ this->wait_time = this->delay;
+}
+
+Cache::~Cache()
+{
+ delete this->lower;
+ delete this->data;
+}
+
+Response Cache::write_word(Accessor accessor, signed int data, int address)
+{
+ return process(accessor, address, [&](int index, int offset) {
+ this->data->at(index).at(offset) = data;
+ this->meta[index].at(1) = 1;
+ });
+}
+
+Response Cache::write_line(
+ Accessor accessor, std::array<signed int, LINE_SIZE> data_line, int address)
+{
+ return process(accessor, address, [&](int index, int offset) {
+ (void)offset;
+ this->data->at(index) = data_line;
+ this->meta[index].at(1) = 1;
+ });
+}
+
+// TODO: tests for multi level cache
+Response Cache::read_line(
+ Accessor accessor,
+ int address,
+ std::array<signed int, LINE_SIZE> &data_line)
+{
+ return process(accessor, address, [&](int index, int offset) {
+ (void)offset;
+ data_line = this->data->at(index);
+ });
+}
+
+Response Cache::read_word(Accessor accessor, int address, signed int &data)
+{
+ return process(accessor, address, [&](int index, int offset) {
+ data = this->data->at(index).at(offset);
+ });
+}
+
+Response Cache::process(
+ Accessor accessor,
+ int address,
+ std::function<void(int index, int offset)> request_handler)
+{
+ Response r = this->is_access_cleared(accessor, address);
+ if (r == OK) {
+ int tag, index, offset;
+ get_cache_fields(address, &tag, &index, &offset);
+ request_handler(index, offset);
+ }
+ return r;
+}
+
+Response Cache::is_access_cleared(Accessor accessor, int address)
+{
+ Response r;
+ r = WAIT;
+ /* Do this first--then process the first cycle immediately. */
+ if (this->requester == IDLE)
+ this->requester = accessor;
+ if (this->requester == accessor) {
+ handle_miss(address);
+ if (this->is_waiting)
+ r = BLOCKED;
+ else if (this->wait_time == 0) {
+ this->requester = IDLE;
+ this->wait_time = delay;
+ r = OK;
+ } else {
+ --this->wait_time;
+ }
+ }
+ return r;
+}
+
+void Cache::handle_miss(int expected)
+{
+ Response r, q;
+ int tag, index, offset;
+ std::array<signed int, LINE_SIZE> *actual;
+ std::array<int, 2> *meta;
+
+ get_cache_fields(expected, &tag, &index, &offset);
+ r = OK;
+ meta = &this->meta.at(index);
+ actual = &this->data->at(index);
+
+ if (meta->at(0) != tag) {
+ r = WAIT;
+ // address not in cache
+ if (meta->at(1) >= 0) {
+ // occupant is dirty
+ // writing line to DRam in case of dirty cache eviction
+ q = this->lower->write_line(
+ L1CACHE, *actual,
+ ((index << LINE_SPEC) +
+ (meta->at(0) << (L1_CACHE_LINE_SPEC + LINE_SPEC))));
+ if (q == OK) {
+ meta->at(1) = -1;
+ }
+ } else {
+ q = this->lower->read_line(L1CACHE, expected, *actual);
+ if (q == OK) {
+ meta->at(0) = tag;
+ }
+ }
+ }
+
+ this->is_waiting = (r == OK) ? false : true;
+}
+
+std::array<std::array<int, 2>, L1_CACHE_LINES> Cache::get_meta() const
+{
+ std::array<std::array<int, 2>, L1_CACHE_LINES> ret;
+ std::copy(std::begin(this->meta), std::end(this->meta), std::begin(ret));
+ return ret;
+}
+
+std::ostream &operator<<(std::ostream &os, const Cache &c)
+{
+ const auto default_flags = std::cout.flags();
+ const auto default_fill = std::cout.fill();
+
+ std::vector<std::array<signed int, LINE_SIZE>> data =
+ c.view(0, L1_CACHE_LINES);
+ std::array<std::array<int, 2>, L1_CACHE_LINES> meta = c.get_meta();
+
+ os << " " << std::setfill(' ') << std::setw(L1_CACHE_LINE_SPEC + 2)
+ << "INDEX"
+ << " | " << std::setfill(' ') << std::setw((8 + 3) * 4 - 1) << "DATA"
+ << " | " << std::setfill(' ')
+ << std::setw(MEM_LINE_SPEC - L1_CACHE_LINE_SPEC + 2) << "TAG"
+ << " | D" << std::endl;
+ for (int i = 0; i < L1_CACHE_LINES; ++i) {
+ os << " 0b" << std::setw(L1_CACHE_LINE_SPEC)
+ << std::bitset<L1_CACHE_LINE_SPEC>(i) << " | ";
+ for (int j = 0; j < LINE_SIZE; ++j) {
+ os << "0x" << std::setfill('0') << std::setw(8) << std::hex
+ << data.at(i).at(j) << " ";
+ }
+ os << "| 0b" << std::setfill(' ');
+
+ if (meta.at(i)[0] < 0)
+ os << std::setfill('?')
+ << std::setw(MEM_LINE_SPEC - L1_CACHE_LINE_SPEC) << "";
+ else
+ os << std::bitset<MEM_LINE_SPEC - L1_CACHE_LINE_SPEC>(
+ meta.at(i)[0]);
+
+ os << " | " << (int)(meta.at(i)[0] >= 0) << std::endl;
+ }
+
+ std::cout.flags(default_flags);
+ std::cout.fill(default_fill);
+ return os;
+}