summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cache.cc138
-rw-r--r--src/dram.cc55
-rw-r--r--src/storage.cc50
-rw-r--r--src/utils.cc42
4 files changed, 157 insertions, 128 deletions
diff --git a/src/cache.cc b/src/cache.cc
index bbb90b4..90bffd6 100644
--- a/src/cache.cc
+++ b/src/cache.cc
@@ -1,14 +1,38 @@
+// Memory subsystem for the RISC-V[ECTOR] mini-ISA
+// Copyright (C) 2025 Siddarth Suresh
+// Copyright (C) 2025 bdunahu
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
#include "cache.h"
#include "definitions.h"
-#include "utils.h"
-#include <bits/stdc++.h>
+#include <cstdlib>
+#include <iostream>
#include <iterator>
-Cache::Cache(Storage *lower, int delay) : Storage(delay)
+Cache::Cache(Storage *lower, unsigned int size, unsigned int ways, int delay) : Storage(delay)
{
- this->data->resize(L1_CACHE_LINES);
+ int true_size;
+
+ true_size = 1 << size;
+ this->data->resize(true_size);
+ this->meta = std::vector<std::array<signed int, 3>>(true_size, {-1, -1, -1});
this->lower = lower;
- this->meta.fill({-1, -1});
+
+ this->size = size;
+ // store the number of bits which are moved into the tag field
+ this->ways = ways;
}
Cache::~Cache()
@@ -36,7 +60,6 @@ Cache::write_line(void *id, std::array<signed int, LINE_SIZE> data_line, int add
});
}
-// TODO: tests for multi level cache
int
Cache::read_line(void *id, int address, std::array<signed int, LINE_SIZE> &data_line)
{
@@ -56,74 +79,73 @@ Cache::read_word(void *id, int address, signed int &data)
int
Cache::process(void *id, int address, std::function<void(int index, int offset)> request_handler)
{
- int r;
- r = this->is_access_cleared(id, address);
- if (r) {
- int tag, index, offset;
- get_cache_fields(address, &tag, &index, &offset);
- request_handler(index, offset);
- }
- return r;
-}
+ address = WRAP_ADDRESS(address);
+ if (!preprocess(id) || priming_address(address) || !this->is_data_ready())
+ return 0;
-int
-Cache::is_access_cleared(void *id, int address)
-{
- /* Do this first--then process the first cycle immediately. */
- if (id == nullptr)
- throw std::invalid_argument("Accessor cannot be nullptr.");
- if (this->current_request == nullptr)
- this->current_request = id;
- if (this->current_request == id) {
- if (is_address_missing(address))
- return 0;
- else if (this->wait_time == 0) {
- this->current_request = nullptr;
- this->wait_time = delay;
- return 1;
- } else {
- --this->wait_time;
- }
- }
- return 0;
+ int tag, index, offset;
+ GET_FIELDS(address, &tag, &index, &offset);
+ index = this->get_true_index(index);
+ request_handler(index, offset);
+
+ return 1;
}
int
-Cache::is_address_missing(int expected)
+Cache::priming_address(int address)
{
- int r, q, tag, index, offset;
- std::array<signed int, LINE_SIZE> *actual;
- std::array<int, 2> *meta;
+ int tag, index, offset;
+ int r1, r2;
+ std::array<signed int, LINE_SIZE> *evict;
+ std::array<int, 3> *meta;
- get_cache_fields(expected, &tag, &index, &offset);
- r = 0;
- meta = &this->meta.at(index);
- actual = &this->data->at(index);
+ r1 = 0;
+ GET_FIELDS(address, &tag, &index, &offset);
+ index = this->get_true_index(index);
- if (meta->at(0) != tag) {
- r = 1;
+ if (this->is_address_missing(index, tag)) {
+ r1 = 1;
+
+ index = this->get_replacement_index(index);
+ meta = &this->meta.at(index);
+ evict = &this->data->at(index);
+
+ // handle eviction of dirty cache lines
if (meta->at(1) >= 0) {
- q = this->lower->write_line(
- this, *actual,
- ((index << LINE_SPEC) + (meta->at(0) << (L1_CACHE_LINE_SPEC + LINE_SPEC))));
- if (q) {
+ r2 = this->lower->write_line(
+ this, *evict, ((index << LINE_SPEC) + (meta->at(0) << (this->size + LINE_SPEC))));
+ if (r2)
meta->at(1) = -1;
- }
} else {
- q = this->lower->read_line(this, expected, *actual);
- if (q) {
+ r2 = this->lower->read_line(this, address, *evict);
+ if (r2) {
meta->at(0) = tag;
}
}
}
- return r;
+ return r1;
}
-std::array<std::array<int, 2>, L1_CACHE_LINES>
-Cache::get_meta() const
+int
+Cache::is_address_missing(int index, int tag)
+{
+ int i;
+
+ for (i = 0; i < (1 << this->ways); ++i)
+ if (this->meta.at(index + i).at(0) == tag)
+ return i;
+ return -1;
+}
+
+int
+Cache::get_true_index(int index)
+{
+ return index * (1 << this->ways);
+}
+
+int
+Cache::get_replacement_index(int index)
{
- 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;
+ return index + (rand() % (1 << this->ways));
}
diff --git a/src/dram.cc b/src/dram.cc
index d81e2d2..9d94280 100644
--- a/src/dram.cc
+++ b/src/dram.cc
@@ -1,10 +1,26 @@
+// Memory subsystem for the RISC-V[ECTOR] mini-ISA
+// Copyright (C) 2025 Siddarth Suresh
+// Copyright (C) 2025 bdunahu
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
#include "dram.h"
#include "definitions.h"
#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <iterator>
-#include <utils.h>
Dram::Dram(int delay) : Storage(delay) { this->data->resize(MEM_LINES); }
@@ -25,7 +41,6 @@ Dram::write_word(void *id, signed int data, int address)
return process(id, address, [&](int line, int word) { this->data->at(line).at(word) = data; });
}
-// TODO requires testing
int
Dram::read_line(void *id, int address, std::array<signed int, LINE_SIZE> &data_line)
{
@@ -56,32 +71,18 @@ Dram::load(std::vector<signed int> program)
int
Dram::process(void *id, int address, std::function<void(int line, int word)> request_handler)
{
- int r;
- r = this->is_access_cleared(id);
- if (r) {
- int line, word;
- get_memory_index(address, line, word);
- request_handler(line, word);
- }
- return r;
+ if (!preprocess(id) || !this->is_data_ready())
+ return 0;
+
+ int line, word;
+ get_memory_index(address, line, word);
+ request_handler(line, word);
+ return 1;
}
-int
-Dram::is_access_cleared(void *id)
+void
+Dram::get_memory_index(int address, int &line, int &word)
{
- /* Do this first--then process the first cycle immediately. */
- if (id == nullptr)
- throw std::invalid_argument("Accessor cannot be nullptr.");
- if (this->current_request == nullptr)
- this->current_request = id;
- if (this->current_request == id) {
- if (this->wait_time == 0) {
- this->current_request = nullptr;
- this->wait_time = delay;
- return 1;
- } else {
- --this->wait_time;
- }
- }
- return 0;
+ line = WRAP_ADDRESS(address) / LINE_SIZE;
+ word = address % LINE_SIZE;
}
diff --git a/src/storage.cc b/src/storage.cc
index 4ad916b..c13b9db 100644
--- a/src/storage.cc
+++ b/src/storage.cc
@@ -1,8 +1,27 @@
+// Memory subsystem for the RISC-V[ECTOR] mini-ISA
+// Copyright (C) 2025 Siddarth Suresh
+// Copyright (C) 2025 bdunahu
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
#include "storage.h"
#include "definitions.h"
#include <algorithm>
+#include <stdexcept>
-Storage::Storage(int delay) {
+Storage::Storage(int delay)
+{
this->data = new std::vector<std::array<signed int, LINE_SIZE>>;
this->delay = delay;
this->lower = nullptr;
@@ -18,3 +37,32 @@ Storage::view(int base, int lines) const
std::copy(this->data->begin() + base, this->data->begin() + base + lines, ret.begin());
return ret;
}
+
+int
+Storage::preprocess(void *id)
+{
+ if (id == nullptr)
+ throw std::invalid_argument("Accessor cannot be nullptr.");
+
+ if (this->current_request == nullptr)
+ this->current_request = id;
+
+ return this->current_request == id;
+}
+
+int
+Storage::is_data_ready()
+{
+ int r;
+
+ r = 0;
+ if (this->wait_time == 0) {
+ this->current_request = nullptr;
+ this->wait_time = delay;
+ r = 1;
+ } else {
+ --this->wait_time;
+ }
+
+ return r;
+}
diff --git a/src/utils.cc b/src/utils.cc
deleted file mode 100644
index e12a0e0..0000000
--- a/src/utils.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "utils.h"
-#include "definitions.h"
-#include <cstdarg>
-#include <string>
-#include <vector>
-
-void get_cache_fields(int address, int *tag, int *index, int *offset)
-{
- *tag = GET_MID_BITS(address, L1_CACHE_LINE_SPEC + LINE_SPEC, MEM_WORD_SPEC);
- *index = GET_MID_BITS(address, LINE_SPEC, L1_CACHE_LINE_SPEC + LINE_SPEC);
- *offset = GET_LS_BITS(address, LINE_SPEC);
-}
-
-const std::string string_format(const char *const zcFormat, ...)
-{
- va_list vaArgs;
- va_start(vaArgs, zcFormat);
-
- va_list vaArgsCopy;
- va_copy(vaArgsCopy, vaArgs);
- const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy);
- va_end(vaArgsCopy);
-
- std::vector<char> zc(iLen + 1);
- std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
- va_end(vaArgs);
- return std::string(zc.data(), iLen);
-}
-
-int wrap_address(int address)
-{
- if (address < 0) {
- return ((address % MEM_WORDS) + MEM_WORDS) % MEM_WORDS;
- }
- return address % MEM_WORDS;
-}
-
-void get_memory_index(int address, int &line, int &word)
-{
- line = wrap_address(address) / LINE_SIZE;
- word = address % LINE_SIZE;
-}