// 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 . #include "cache.h" #include "definitions.h" #include #include #include Cache::Cache(Storage *lower, unsigned int size, unsigned int ways, int delay) : Storage(delay) { int true_size; true_size = 1 << size; this->data->resize(true_size); this->meta = std::vector>(true_size, {-1, -1, -1}); this->lower = lower; this->size = size; // store the number of bits which are moved into the tag field this->ways = ways; } Cache::~Cache() { delete this->lower; delete this->data; } int Cache::write_word(void *id, signed int data, int address) { return process(id, address, [&](int index, int offset) { this->data->at(index).at(offset) = data; this->meta[index].at(1) = 1; }); } int Cache::write_line(void *id, std::array data_line, int address) { return process(id, address, [&](int index, int offset) { (void)offset; this->data->at(index) = data_line; this->meta[index].at(1) = 1; }); } int Cache::read_line(void *id, int address, std::array &data_line) { return process(id, address, [&](int index, int offset) { (void)offset; data_line = this->data->at(index); }); } int Cache::read_word(void *id, int address, signed int &data) { return process( id, address, [&](int index, int offset) { data = this->data->at(index).at(offset); }); } int Cache::process(void *id, int address, std::function request_handler) { address = WRAP_ADDRESS(address); if (!preprocess(id) || priming_address(address) || !this->is_data_ready()) 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::priming_address(int address) { int tag, index, offset; int r1, r2; std::array *evict; std::array *meta; r1 = 0; GET_FIELDS(address, &tag, &index, &offset); index = this->get_true_index(index); 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) { r2 = this->lower->write_line( this, *evict, ((index << LINE_SPEC) + (meta->at(0) << (this->size + LINE_SPEC)))); if (r2) meta->at(1) = -1; } else { r2 = this->lower->read_line(this, address, *evict); if (r2) { meta->at(0) = tag; } } } return r1; } 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) { return index + (rand() % (1 << this->ways)); }