diff options
-rw-r--r-- | inc/accessor.h | 18 | ||||
-rw-r--r-- | inc/cache.h | 55 | ||||
-rw-r--r-- | inc/cli.h | 97 | ||||
-rw-r--r-- | inc/definitions.h | 1 | ||||
-rw-r--r-- | inc/dram.h | 47 | ||||
-rw-r--r-- | inc/logger.h | 42 | ||||
-rw-r--r-- | inc/response.h | 14 | ||||
-rw-r--r-- | inc/storage.h | 58 | ||||
-rw-r--r-- | src/accessor.cc | 10 | ||||
-rw-r--r-- | src/cache.cc | 139 | ||||
-rw-r--r-- | src/dram.cc | 113 | ||||
-rw-r--r-- | src/logger.cc | 71 | ||||
-rw-r--r-- | src/response.cc | 8 | ||||
-rw-r--r-- | src/storage.cc | 14 | ||||
-rw-r--r-- | tests/cache.cc | 116 | ||||
-rw-r--r-- | tests/dram.cc | 223 |
16 files changed, 296 insertions, 730 deletions
diff --git a/inc/accessor.h b/inc/accessor.h deleted file mode 100644 index eb56785..0000000 --- a/inc/accessor.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ACCESSOR_H -#define ACCESSOR_H -#include <iostream> - -enum Accessor { - IDLE, - WRITE, - MEM, - EXEC, - DCDE, - FETCH, - L1CACHE, - SIDE, -}; - -std::ostream &operator<<(std::ostream &os, Accessor a); - -#endif /* ACCESSOR_H_INCLUDED */ diff --git a/inc/cache.h b/inc/cache.h index 88fd352..0f15536 100644 --- a/inc/cache.h +++ b/inc/cache.h @@ -3,8 +3,8 @@ #include "definitions.h" #include "storage.h" #include <array> -#include <ostream> #include <functional> +#include <ostream> class Cache : public Storage { @@ -21,55 +21,52 @@ class Cache : public Storage Cache(Storage *lower, int delay); ~Cache(); - Response - write_word(Accessor accessor, signed int data, int address) override; - Response write_line( - Accessor accessor, - std::array<signed int, LINE_SIZE> data_line, - int address) override; - Response read_line( - Accessor accessor, - int address, - std::array<signed int, LINE_SIZE> &data_line) override; - Response - read_word(Accessor accessor, int address, signed int &data) override; + int + write_word(void *, signed int, int) override; + int + write_line(void *, std::array<signed int, LINE_SIZE>, int) override; + int + read_line(void *, int, std::array<signed int, LINE_SIZE> &) override; + int + read_word(void *, int, signed int &) override; /** * Getter for the meta attribute. * TODO this doesn't seem like good object-oriented practice. * @return this->meta */ - std::array<std::array<int, 2>, L1_CACHE_LINES> get_meta() const; + std::array<std::array<int, 2>, L1_CACHE_LINES> + get_meta() const; private: /** * Helper for all access methods. - * Calls `request_handler` when `accessor` is allowed to complete its + * Calls `request_handler` when `id` is allowed to complete its * request cycle. * @param the source making the request * @param the address to write to * @param the function to call when an access should be completed */ - Response process( - Accessor accessor, - int address, - std::function<void(int index, int offset)> request_handler); + int + process(void *id, int address, std::function<void(int index, int offset)> request_handler); /** - * Returns OK if `accessor` is allowed to complete its request this cycle. - * Handles cache misses, wait times, and setting the current accessor this + * Returns OK if `id` is allowed to complete its request this cycle. + * Handles cache misses, wait times, and setting the current id this * storage is serving. - * @param the accessor asking for a resource - * @return whether or not the access can be carried out this function call. + * @param the id asking for a resource + * @return 1 if the access can be carried out this function call, 0 otherwise. */ - Response is_access_cleared(Accessor accessor, int address); + int + is_access_cleared(void *id, int address); /** - * Helper for access_cleared. + * Helper for is_access_cleared. * Fetches `address` from a lower level of storage if it is not already - * present. If it is not, temporarily sets the is_blocked attribute of this - * cache level to true, and the victim line is chosen/written back. + * present. The victim line is chosen/written back. * @param the address that must be present in cache. + * @param 0 if the address is currently in cache, 1 if it is being fetched. */ - void handle_miss(int address); + int + is_address_missing(int address); /** * An array of metadata about elements in `data`. * If the first value of an element is negative, the corresponding @@ -79,6 +76,4 @@ class Cache : public Storage std::array<std::array<int, 2>, L1_CACHE_LINES> meta; }; -std::ostream &operator<<(std::ostream &os, const Cache &c); - #endif /* CACHE_H_INCLUDED */ diff --git a/inc/cli.h b/inc/cli.h deleted file mode 100644 index a0c698a..0000000 --- a/inc/cli.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef CLI_H -#define CLI_H -#include "cache.h" -#include <functional> -#include <string> -#include <unordered_map> - -class Cli -{ - public: - /** - * Constructor. - * @return A newly allocated CLI object. - */ - Cli(); - ~Cli(); - - /** - * Prints all available commands to the console. - */ - void help(); - - /** - * Loads data from memory from the specified memory address. - * @param memory_address address of the memory where data needs to be loaded - * from - */ - void load(Accessor accessor, int memory_address); - - /** - * Stores data into memory at the specified address. - * @param accessor the pipline stage that is making this request - * @param data data value to be written to the memory - * @param address address of the memory where data needs to be stored - * @return the response from the storage device - */ - void store(Accessor accessor, int data, int address); - - /** - * Resets the memory configuration and cycles to their initial state. - * This function provides a side door reset interface to the memory system, - * allowing the user to reset the memory configuration directly. - */ - void reset(); - - /** - * Advance the clock one cycle, refreshing the storage devices. - */ - void clock(); - - /** - * Displays `lines` lines of the data in `level`, starting from `base`. - * - * - * This function provides a side door view into the storage system, showing - * its current state and configuration. - * @param level the level specifying the storage device. The first level - * one cache is level zero, with descending levels incrementing by a factor - * of one. - */ - void peek(int level); - - /** - * Runs the command line interface - * This function is the main entry point for the command line interface. - */ - void run(); - - private: - /** - * Initializes the cache object. - */ - void initialize(); - /** - * Attempts to match string to either fetch or mem, or throws - * std::invalid_argument otherwise. - * @param the string to be converted accessor - * @return the corresponding accessor - * @throws invalid_argument if the string is not fetch or mem - */ - Accessor match_accessor_or_die(std::string s); - /** Map of commands and their corresponding functions. - * This map is used to store the commands and their corresponding functions. - */ - std::unordered_map<char, std::function<void(std::vector<std::string>)>> - commands; - /** - * The cache object to interface with. - */ - Cache *cache; - /** - * The current cycle. - */ - int cycle; -}; - -#endif /* CLI_H_INCLUDED */ diff --git a/inc/definitions.h b/inc/definitions.h index c81c4e3..6fa29ee 100644 --- a/inc/definitions.h +++ b/inc/definitions.h @@ -1,6 +1,5 @@ #ifndef DEFINITIONS_H #define DEFINITIONS_H -#include "logger.h" #include <cmath> /** @@ -2,8 +2,8 @@ #define DRAM_H #include "definitions.h" #include "storage.h" -#include <ostream> #include <functional> +#include <ostream> class Dram : public Storage { @@ -16,47 +16,42 @@ class Dram : public Storage Dram(int delay); ~Dram(); - Response - write_word(Accessor accessor, signed int data, int address) override; - Response read_line( - Accessor accessor, - int address, - std::array<signed int, LINE_SIZE> &data_line) override; - Response write_line( - Accessor accessor, - std::array<signed int, LINE_SIZE> data_line, - int address) override; - Response - read_word(Accessor accessor, int address, signed int &data) override; + int + write_word(void *, signed int, int) override; + int + write_line(void *, std::array<signed int, LINE_SIZE>, int) override; + int + read_word(void *, int, signed int &) override; + int + read_line(void *, int, std::array<signed int, LINE_SIZE> &) override; /** * TODO This will accept a file at a later date. */ - void load(std::vector<signed int> program); + void + load(std::vector<signed int> program); private: /** * Helper for all access methods. - * Calls `request_handler` when `accessor` is allowed to complete its + * Calls `request_handler` when `id` is allowed to complete its * request cycle. * @param the source making the request * @param the address to write to * @param the function to call when an access should be completed + * @return 1 if the access completed successfully, 0 otherwise */ - Response process( - Accessor accessor, - int address, - std::function<void(int line, int word)> request_handler); + int + process(void *id, int address, std::function<void(int line, int word)> request_handler); /** - * Returns OK if `accessor` is allowed to complete its request this cycle. - * Handles wait times, side door, and setting the current accessor this + * Returns OK if `id` is allowed to complete its request this cycle. + * Handles wait times, side door, and setting the current id this * storage is serving. - * @param the accessor asking for a resource - * @return whether or not the access can be carried out this function call. + * @param the source making the request + * @return 1 if the access can be completed this function call, 0 otherwise */ - Response is_access_cleared(Accessor accessor); + int + is_access_cleared(void *id); }; -std::ostream &operator<<(std::ostream &os, const Dram &d); - #endif /* DRAM_H_INCLUDED */ diff --git a/inc/logger.h b/inc/logger.h deleted file mode 100644 index 88f9e30..0000000 --- a/inc/logger.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef LOGGER_H -#define LOGGER_H -#include <fstream> -#include <sstream> -using namespace std; - -enum LogLevel { DEBUG, INFO, WARNING, ERROR, CRITICAL }; - -class Logger -{ - public: - static Logger* getInstance(); - - ~Logger() = default; - - /** - * Do not allow copies. - */ - Logger(const Logger& obj) = delete; - - /** - * Set the log level. - * @param the log level to set to. - */ - void setLevel(LogLevel); - /** - * Log a message at a certain log level. - * @param The level to log this message. If the level is lower than the - * level set by `setLevel`, then the message is not logged. - * @param The message to log. - */ - void log(LogLevel, const string &); - - private: - Logger() = default; - static Logger* logger_instance; - static LogLevel level; - static string level_to_string(LogLevel); - static int level_to_int(LogLevel); -}; - -#endif /* LOGGER_H_INCLUDED */ diff --git a/inc/response.h b/inc/response.h deleted file mode 100644 index 05e9352..0000000 --- a/inc/response.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef RESPONSE_H -#define RESPONSE_H -#include <iostream> - -enum Response { - OK, - WAIT, - BLOCKED, - STALLED, -}; - -std::ostream &operator<<(std::ostream &os, Response r); - -#endif /* RESPONSE_H_INCLUDED */ diff --git a/inc/storage.h b/inc/storage.h index d6fa094..81194da 100644 --- a/inc/storage.h +++ b/inc/storage.h @@ -1,8 +1,6 @@ #ifndef STORAGE_H #define STORAGE_H -#include "accessor.h" #include "definitions.h" -#include "response.h" #include <algorithm> #include <array> #include <map> @@ -11,6 +9,12 @@ class Storage { public: + /** + * Constructor. + * @param The time an access to this storage device takes. + * @return A newly allocated storage object. + */ + Storage(int delay); virtual ~Storage() = default; /** @@ -18,34 +22,26 @@ class Storage * @param the source making the request. * @param the data (hexadecimal) to write. * @param the address to write to. - * @return a status code reflecting the state of the request. - */ - virtual Response write_word(Accessor accessor, signed int data, int address) = 0; - - /** - * Write a data line to given address in this level of storage + * @return 1 if the request was completed, 0 otherwise. */ - virtual Response write_line(Accessor accessor, std::array<signed int, LINE_SIZE> data_line, int address) = 0; + virtual int + write_word(void *id, signed int data, int address) = 0; + virtual int + write_line(void *id, std::array<signed int, LINE_SIZE> data_line, int address) = 0; - /** * Get the data line at `address`. * @param the source making the request. * @param the address being accessed. - * @return a status code reflecting the state of the request, and the - * data being returned. + * @param the data being returned + * @return 1 if the request was completed, 0 otherwise */ - virtual Response read_line( - Accessor accessor, - int address, - std::array<signed int, LINE_SIZE> &data) = 0; + virtual int + read_line(void *id, int address, std::array<signed int, LINE_SIZE> &data) = 0; + virtual int + read_word(void *id, int address, signed int &data) = 0; /** - * Read a word from given address in this level of storage - */ - virtual Response read_word(Accessor accessor, int address, signed int &data) = 0; - - /** * Sidedoor view of `lines` of memory starting at `base`. * @param The base line to start getting memory from. * @param The amount of lines to fetch. @@ -55,13 +51,6 @@ class Storage std::vector<std::array<signed int, LINE_SIZE>> view(int base, int lines) const; - /** - * Getter for lower attribute. - * TODO this doesn't seem like good object-oriented practice. - * @return this->lower - */ - Storage *get_lower(); - protected: /** * The data currently stored in this level of storage. @@ -73,23 +62,18 @@ class Storage */ Storage *lower; /** + * The id currently being serviced. + */ + void *current_request; + /** * The number of clock cycles this level of storage takes to complete * requests. */ int delay; /** - * The accessor currently being serviced. - */ - Accessor requester; - /** * The number of cycles until the current request is completed. */ int wait_time; - /** - * A flag indicating whether this level of storage is currently waiting for - * a lower level. - */ - int is_waiting; }; #endif /* STORAGE_H_INCLUDED */ diff --git a/src/accessor.cc b/src/accessor.cc deleted file mode 100644 index 99347ed..0000000 --- a/src/accessor.cc +++ /dev/null @@ -1,10 +0,0 @@ -#include "accessor.h" -#include <iostream> - -std::ostream &operator<<(std::ostream &os, Accessor a) -{ - const std::string nameA[] = { - "IDLE", "WRITE", "MEM", "EXEC", "DCDE", "FETCH", "L1CACHE", "SIDE", - }; - return os << nameA[a]; -} diff --git a/src/cache.cc b/src/cache.cc index 80f59ef..bbb90b4 100644 --- a/src/cache.cc +++ b/src/cache.cc @@ -1,21 +1,14 @@ #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) +Cache::Cache(Storage *lower, int delay) : Storage(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() @@ -24,18 +17,19 @@ Cache::~Cache() delete this->data; } -Response Cache::write_word(Accessor accessor, signed int data, int address) +int +Cache::write_word(void *id, signed int data, int address) { - return process(accessor, address, [&](int index, int offset) { + return process(id, 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) +int +Cache::write_line(void *id, std::array<signed int, LINE_SIZE> data_line, int address) { - return process(accessor, address, [&](int index, int offset) { + return process(id, address, [&](int index, int offset) { (void)offset; this->data->at(index) = data_line; this->meta[index].at(1) = 1; @@ -43,31 +37,28 @@ Response Cache::write_line( } // TODO: tests for multi level cache -Response Cache::read_line( - Accessor accessor, - int address, - std::array<signed int, LINE_SIZE> &data_line) +int +Cache::read_line(void *id, int address, std::array<signed int, LINE_SIZE> &data_line) { - return process(accessor, address, [&](int index, int offset) { + return process(id, address, [&](int index, int offset) { (void)offset; data_line = this->data->at(index); }); } -Response Cache::read_word(Accessor accessor, int address, signed int &data) +int +Cache::read_word(void *id, int address, signed int &data) { - return process(accessor, address, [&](int index, int offset) { - data = this->data->at(index).at(offset); - }); + return process( + id, 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) +int +Cache::process(void *id, int address, std::function<void(int index, int offset)> request_handler) { - Response r = this->is_access_cleared(accessor, address); - if (r == OK) { + 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); @@ -75,106 +66,64 @@ Response Cache::process( return r; } -Response Cache::is_access_cleared(Accessor accessor, int address) +int +Cache::is_access_cleared(void *id, 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; + 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->requester = IDLE; + this->current_request = nullptr; this->wait_time = delay; - r = OK; + return 1; } else { --this->wait_time; } } - return r; + return 0; } -void Cache::handle_miss(int expected) +int +Cache::is_address_missing(int expected) { - Response r, q; - int tag, index, offset; + int r, q, tag, index, offset; std::array<signed int, LINE_SIZE> *actual; std::array<int, 2> *meta; get_cache_fields(expected, &tag, &index, &offset); - r = OK; + r = 0; meta = &this->meta.at(index); actual = &this->data->at(index); if (meta->at(0) != tag) { - r = WAIT; - // address not in cache + r = 1; 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) { + this, *actual, + ((index << LINE_SPEC) + (meta->at(0) << (L1_CACHE_LINE_SPEC + LINE_SPEC)))); + if (q) { meta->at(1) = -1; } } else { - q = this->lower->read_line(L1CACHE, expected, *actual); - if (q == OK) { + q = this->lower->read_line(this, expected, *actual); + if (q) { meta->at(0) = tag; } } } - this->is_waiting = (r == OK) ? false : true; + return r; } -std::array<std::array<int, 2>, L1_CACHE_LINES> Cache::get_meta() const +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; -} diff --git a/src/dram.cc b/src/dram.cc index f90f8db..d81e2d2 100644 --- a/src/dram.cc +++ b/src/dram.cc @@ -1,63 +1,50 @@ #include "dram.h" #include "definitions.h" -#include "response.h" #include <algorithm> #include <bits/stdc++.h> #include <bitset> -#include <iostream> #include <iterator> #include <utils.h> -Dram::Dram(int delay) -{ - this->data = new std::vector<std::array<signed int, LINE_SIZE>>; - this->data->resize(MEM_LINES); - this->delay = delay; - this->is_waiting = false; - this->lower = nullptr; - this->requester = IDLE; - this->wait_time = this->delay; -} +Dram::Dram(int delay) : Storage(delay) { this->data->resize(MEM_LINES); } Dram::~Dram() { delete this->data; } -Response Dram::write_line( - Accessor accessor, std::array<signed int, LINE_SIZE> data_line, int address) +int +Dram::write_line(void *id, std::array<signed int, LINE_SIZE> data_line, int address) { - return process(accessor, address, [&](int line, int word) { + return process(id, address, [&](int line, int word) { (void)word; this->data->at(line) = data_line; }); } -Response Dram::write_word(Accessor accessor, signed int data, int address) +int +Dram::write_word(void *id, signed int data, int address) { - return process(accessor, address, [&](int line, int word) { - this->data->at(line).at(word) = data; - }); + return process(id, address, [&](int line, int word) { this->data->at(line).at(word) = data; }); } // TODO requires testing -Response Dram::read_line( - Accessor accessor, - int address, - std::array<signed int, LINE_SIZE> &data_line) +int +Dram::read_line(void *id, int address, std::array<signed int, LINE_SIZE> &data_line) { - return process(accessor, address, [&](int line, int word) { + return process(id, address, [&](int line, int word) { (void)word; data_line = this->data->at(line); }); } -Response Dram::read_word(Accessor accessor, int address, signed int &data) +int +Dram::read_word(void *id, int address, signed int &data) { - return process(accessor, address, [&](int line, int word) { - data = this->data->at(line).at(word); - }); + return process(id, address, [&](int line, int word) { data = this->data->at(line).at(word); }); } // TODO load a file instead and test this method -void Dram::load(std::vector<signed int> program) { +void +Dram::load(std::vector<signed int> program) +{ unsigned long i; for (i = 0; i < program.size(); ++i) { int line, word; @@ -66,13 +53,12 @@ void Dram::load(std::vector<signed int> program) { } } -Response Dram::process( - Accessor accessor, - int address, - std::function<void(int line, int word)> request_handler) +int +Dram::process(void *id, int address, std::function<void(int line, int word)> request_handler) { - Response r = this->is_access_cleared(accessor); - if (r == OK) { + int r; + r = this->is_access_cleared(id); + if (r) { int line, word; get_memory_index(address, line, word); request_handler(line, word); @@ -80,51 +66,22 @@ Response Dram::process( return r; } -Response Dram::is_access_cleared(Accessor accessor) +int +Dram::is_access_cleared(void *id) { - Response r; - r = WAIT; /* Do this first--then process the first cycle immediately. */ - if (accessor == SIDE) - r = OK; - else { - if (this->requester == IDLE) - this->requester = accessor; - if (this->requester == accessor) { - if (this->wait_time == 0) { - this->requester = IDLE; - this->wait_time = delay; - r = OK; - } else { - --this->wait_time; - } - } - } - return r; -} - -std::ostream &operator<<(std::ostream &os, const Dram &d) -{ - const auto default_flags = std::cout.flags(); - const auto default_fill = std::cout.fill(); - - std::vector<std::array<signed int, LINE_SIZE>> data = d.view(0, MEM_LINES); - - os << " " << std::setfill(' ') << std::setw(MEM_LINE_SPEC + 2 + LINE_SPEC) - << "ADDRESS" - << " | " << std::setfill(' ') << std::setw((8 + 3) * 4 - 1) << "DATA" - << std::endl; - for (int i = 0; i < MEM_LINES; ++i) { - os << " 0b" << std::setw(MEM_LINE_SPEC + LINE_SPEC) << left - << std::bitset<MEM_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) << ' '; + 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; } - os << std::endl; } - - std::cout.flags(default_flags); - std::cout.fill(default_fill); - return os; + return 0; } diff --git a/src/logger.cc b/src/logger.cc deleted file mode 100644 index b07e66f..0000000 --- a/src/logger.cc +++ /dev/null @@ -1,71 +0,0 @@ -#include "logger.h" -#include <ctime> -#include <fstream> -#include <iostream> -#include <sstream> -using namespace std; - -LogLevel Logger::level = INFO; -Logger *Logger::logger_instance; - -void Logger::setLevel(LogLevel level) { this->level = level; } - -void Logger::log(LogLevel level, const string &message) -{ - if (level_to_int(level) > level_to_int(this->level)) { - return; - } - - time_t now = time(0); - tm *timeinfo = localtime(&now); - char timestamp[20]; - strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", timeinfo); - - ostringstream logEntry; - logEntry << "[" << timestamp << "] " << level_to_string(level) << ": " - << message << endl; - - cout << logEntry.str(); -} - -Logger *Logger::getInstance() -{ - if (logger_instance == nullptr) { - logger_instance = new Logger(); - } - return logger_instance; -} - -string Logger::level_to_string(LogLevel level) -{ - switch (level) { - case DEBUG: - return "DEBUG"; - case INFO: - return "INFO"; - case WARNING: - return "WARNING"; - case ERROR: - return "ERROR"; - case CRITICAL: - return "CRITICAL"; - default: - return "UNKNOWN"; - } -} - -int Logger::level_to_int(LogLevel level) -{ - switch (level) { - case DEBUG: - return 5; - case INFO: - return 4; - case WARNING: - return 3; - case ERROR: - return 2; - default: - return 1; - } -} diff --git a/src/response.cc b/src/response.cc deleted file mode 100644 index 3d6e439..0000000 --- a/src/response.cc +++ /dev/null @@ -1,8 +0,0 @@ -#include "response.h" -#include <iostream> - -std::ostream &operator<<(std::ostream &os, Response r) -{ - const std::string nameR[] = {"OK", "WAIT", "BLOCKED", "STALLED"}; - return os << nameR[r]; -} diff --git a/src/storage.cc b/src/storage.cc index fed607b..4ad916b 100644 --- a/src/storage.cc +++ b/src/storage.cc @@ -2,15 +2,19 @@ #include "definitions.h" #include <algorithm> +Storage::Storage(int delay) { + this->data = new std::vector<std::array<signed int, LINE_SIZE>>; + this->delay = delay; + this->lower = nullptr; + this->current_request = nullptr; + this->wait_time = this->delay; +} + std::vector<std::array<signed int, LINE_SIZE>> Storage::view(int base, int lines) const { base = (base / LINE_SIZE) * LINE_SIZE; std::vector<std::array<signed int, LINE_SIZE>> ret(lines + 1); - std::copy( - this->data->begin() + base, this->data->begin() + base + lines, - ret.begin()); + std::copy(this->data->begin() + base, this->data->begin() + base + lines, ret.begin()); return ret; } - -Storage *Storage::get_lower() { return this->lower; } diff --git a/tests/cache.cc b/tests/cache.cc index 0b04bce..313f93f 100644 --- a/tests/cache.cc +++ b/tests/cache.cc @@ -11,21 +11,28 @@ class CacheFixture this->c_delay = 2; this->d = new Dram(this->m_delay); this->c = new Cache(this->d, this->c_delay); + this->mem = new int; + this->fetch = new int; this->expected = {0, 0, 0, 0}; this->actual = this->c->view(0, 1)[0]; } - ~CacheFixture() { delete this->c; } + ~CacheFixture() + { + delete this->c; + delete this->mem; + delete this->fetch; + } /** * An operation that is done a lot. */ void - wait_for_storage(int delay, Response expected, std::function<Response()> f) + wait_for_storage(int delay, int expected, std::function<int()> f) { for (int i = 0; i < delay; ++i) { - Response r = f(); - + int r = f(); + // check response CHECK(r == expected); // check for early modifications @@ -38,29 +45,27 @@ class CacheFixture int c_delay; Cache *c; Dram *d; + int *mem; + int *fetch; std::array<signed int, LINE_SIZE> expected; std::array<signed int, LINE_SIZE> actual; }; TEST_CASE_METHOD(CacheFixture, "store 0th element in DELAY cycles", "[dram]") { - Response r; + int r; signed int w; CHECK(expected == actual); w = 0x11223344; // delay + 1 due to internal logic, when mem // finishes handle_miss still returns 'blocked' - this->wait_for_storage(this->m_delay + 1, BLOCKED, [this, w]() { - return this->c->write_word(MEM, w, 0b0); - }); - - this->wait_for_storage(this->c_delay, WAIT, [this, w]() { - return this->c->write_word(MEM, w, 0b0); + this->wait_for_storage(this->m_delay + this->c_delay + 1, 0, [this, w]() { + return this->c->write_word(this->mem, w, 0b0); }); - r = c->write_word(MEM, w, 0b0); - CHECK(r == OK); + r = c->write_word(this->mem, w, 0b0); + CHECK(r); actual = this->d->view(0, 1)[0]; // we do NOT write back now! @@ -71,43 +76,28 @@ TEST_CASE_METHOD(CacheFixture, "store 0th element in DELAY cycles", "[dram]") REQUIRE(expected == actual); } -TEST_CASE_METHOD( - CacheFixture, - "store 0th, 1st element in DELAY cycles, with conflict", - "[cache]") +TEST_CASE_METHOD(CacheFixture, "store 0th, 1st element in DELAY cycles, with conflict", "[cache]") { - Response r; signed int w; - int i; + int r, i; CHECK(expected == actual); w = 0x11223344; // delay + 1 due to internal logic, when mem // finishes handle_miss still returns 'blocked' - for (i = 0; i < this->m_delay + 1; ++i) { - r = c->write_word(MEM, w, 0b0); - CHECK(r == BLOCKED); - r = c->write_word(FETCH, w, 0b1); - CHECK(r == WAIT); - - // check for early modifications - actual = c->view(0, 1)[0]; - REQUIRE(this->expected == this->actual); - } + for (i = 0; i < this->m_delay + this->c_delay + 1; ++i) { + r = c->write_word(this->mem, w, 0b0); + CHECK(!r); + r = c->write_word(this->fetch, w, 0b1); + CHECK(!r); - for (i = 0; i < this->c_delay; ++i) { - r = c->write_word(MEM, w, 0b0); - CHECK(r == WAIT); - r = c->write_word(FETCH, w, 0b1); - CHECK(r == WAIT); - // check for early modifications actual = c->view(0, 1)[0]; REQUIRE(this->expected == this->actual); } - r = c->write_word(MEM, w, 0b0); - CHECK(r == OK); + r = c->write_word(this->mem, w, 0b0); + CHECK(r); actual = d->view(0, 1)[0]; // we do NOT write back now! @@ -118,69 +108,57 @@ TEST_CASE_METHOD( REQUIRE(expected == actual); // this should have been loaded already! - this->wait_for_storage(this->c_delay, WAIT, [this, w]() { - return this->c->write_word(FETCH, w, 0b1); - }); + this->wait_for_storage( + this->c_delay, 0, [this, w]() { return this->c->write_word(this->fetch, w, 0b1); }); + + r = c->write_word(this->fetch, w, 0b1); + CHECK(r); - r = c->write_word(FETCH, w, 0b1); - CHECK(r == OK); - expected.at(1) = w; actual = c->view(0, 1)[0]; REQUIRE(expected == actual); } TEST_CASE_METHOD( - CacheFixture, - "store 0th, 1st element different tags, in DELAY cycles, no conflict", - "[cache]") + CacheFixture, "store 0th, 1st element different tags, in DELAY cycles, no conflict", "[cache]") { - Response r; + int r; signed int w; CHECK(expected == actual); w = 0x11223344; // delay + 1 due to internal logic, when mem // finishes handle_miss still returns 'blocked' - this->wait_for_storage(this->m_delay + 1, BLOCKED, [this, w]() { - return this->c->write_word(MEM, w, 0b0); + this->wait_for_storage(this->m_delay + this->c_delay + 1, 0, [this, w]() { + return this->c->write_word(this->mem, w, 0b0); }); - this->wait_for_storage(this->c_delay, WAIT, [this, w]() { - return this->c->write_word(MEM, w, 0b0); - }); + r = c->write_word(this->mem, w, 0b0); + CHECK(r); - r = c->write_word(MEM, w, 0b0); - CHECK(r == OK); - expected.at(0) = w; actual = c->view(0, 1)[0]; REQUIRE(expected == actual); // write back to memory - this->wait_for_storage(this->m_delay + 1, BLOCKED, [this, w]() { - return this->c->write_word(FETCH, w, 0b10000001); - }); - // fetch new address (don't run the completion cycle yet) - this->wait_for_storage(this->m_delay, BLOCKED, [this, w]() { - return this->c->write_word(FETCH, w, 0b10000001); + this->wait_for_storage(this->m_delay + this->m_delay + 1, 0, [this, w]() { + return this->c->write_word(this->fetch, w, 0b10000001); }); // after the fetch, this cache line should be empty - this->c->write_word(FETCH, w, 0b10000001); - CHECK(r == OK); - + this->c->write_word(this->fetch, w, 0b10000001); + CHECK(r); + expected.at(0) = 0; actual = c->view(0, 1)[0]; CHECK(expected == actual); - this->wait_for_storage(this->c_delay, WAIT, [this, w]() { - return this->c->write_word(FETCH, w, 0b10000001); - }); + this->wait_for_storage( + this->c_delay, 0, [this, w]() { return this->c->write_word(this->fetch, w, 0b10000001); }); - r = c->write_word(FETCH, w, 0b10000001); - CHECK(r == OK); + r = c->write_word(this->fetch, w, 0b10000001); + CHECK(r); expected.at(0) = 0; expected.at(1) = w; diff --git a/tests/dram.cc b/tests/dram.cc index 0e97e81..086ca4a 100644 --- a/tests/dram.cc +++ b/tests/dram.cc @@ -9,23 +9,27 @@ class DramFixture { this->delay = 3; this->d = new Dram(this->delay); + this->mem = new int; + this->fetch = new int; this->expected = {0, 0, 0, 0}; this->actual = this->d->view(0, 1)[0]; } - ~DramFixture() { delete this->d; } + ~DramFixture() + { + delete this->d; + delete this->mem; + delete this->fetch; + } - /** - * An operation that is done a lot. - */ void - wait_for_storage(int delay, Response expected, std::function<Response()> f) + wait_for_storage(int delay, std::function<int()> f) { for (int i = 0; i < delay; ++i) { - Response r = f(); + int r = f(); // check response - CHECK(r == expected); + CHECK(!r); // check for early modifications actual = d->view(0, 1)[0]; REQUIRE(this->expected == this->actual); @@ -34,95 +38,84 @@ class DramFixture int delay; Dram *d; + int *mem; + int *fetch; std::array<signed int, LINE_SIZE> expected; std::array<signed int, LINE_SIZE> actual; }; TEST_CASE_METHOD(DramFixture, "store 0th element in DELAY cycles", "[dram]") { - Response r; + int r; signed int w; CHECK(expected == actual); w = 0x11223344; - this->wait_for_storage(this->delay, WAIT, [this, w]() { - return this->d->write_word(MEM, w, 0x0); - }); + this->wait_for_storage(this->delay, [this, w]() { return this->d->write_word(this->mem, w, 0x0); }); - r = this->d->write_word(MEM, w, 0x0); + r = this->d->write_word(this->mem, w, 0x0); - CHECK(r == OK); + CHECK(r); expected.at(0) = w; actual = this->d->view(0, 1)[0]; REQUIRE(expected == actual); } -TEST_CASE_METHOD( - DramFixture, - "store 0th, 1st element in DELAY cycles, no conflict", - "[dram]") +TEST_CASE_METHOD(DramFixture, "store 0th, 1st element in DELAY cycles, no conflict", "[dram]") { - Response r; + int r; signed int w; CHECK(expected == actual); w = 0x11223344; - this->wait_for_storage(this->delay, WAIT, [this, w]() { - return this->d->write_word(MEM, w, 0x0); - }); + this->wait_for_storage(this->delay, [this, w]() { return this->d->write_word(this->mem, w, 0x0); }); - r = d->write_word(MEM, w, 0x0); - REQUIRE(r == OK); + r = d->write_word(this->mem, w, 0x0); + REQUIRE(r); expected.at(0) = w; actual = d->view(0, 1)[0]; REQUIRE(expected == actual); - this->wait_for_storage(this->delay, WAIT, [this, w]() { - return this->d->write_word(FETCH, w, 0x1); - }); + this->wait_for_storage(this->delay, [this, w]() { return this->d->write_word(this->fetch, w, 0x1); }); - r = d->write_word(FETCH, w, 0x1); - CHECK(r == OK); + r = d->write_word(this->fetch, w, 0x1); + CHECK(r); actual = d->view(0, 1)[0]; expected.at(1) = w; REQUIRE(expected == actual); } -TEST_CASE_METHOD( - DramFixture, "store 0th element in DELAY cycles with conflict", "[dram]") +TEST_CASE_METHOD(DramFixture, "store 0th element in DELAY cycles with conflict", "[dram]") { - Response r; + int r, i; signed int w; - int i; CHECK(expected == actual); w = 0x11223344; for (i = 0; i < this->delay; ++i) { - r = this->d->write_word(MEM, w, 0x0); - CHECK(r == WAIT); - r = this->d->write_word(FETCH, w, 0x1); - CHECK(r == WAIT); + r = this->d->write_word(this->mem, w, 0x0); + CHECK(!r); + r = this->d->write_word(this->fetch, w, 0x1); + CHECK(!r); // check for early modifications actual = d->view(0, 1)[0]; REQUIRE(expected == actual); } - r = d->write_word(MEM, w, 0x0); - REQUIRE(r == OK); + r = d->write_word(this->mem, w, 0x0); + REQUIRE(r); expected.at(0) = w; actual = d->view(0, 1)[0]; REQUIRE(expected == actual); - this->wait_for_storage(this->delay, WAIT, [this, w]() { - return this->d->write_word(FETCH, w, 0x1); - }); + this->wait_for_storage(this->delay, [this, w]() { return this->d->write_word(this->fetch, w, 0x1); }); - r = d->write_word(FETCH, w, 0x1); - CHECK(r == OK); + r = d->write_word(this->fetch, w, 0x1); + CHECK(r); actual = d->view(0, 1)[0]; expected.at(1) = w; @@ -131,95 +124,88 @@ TEST_CASE_METHOD( TEST_CASE_METHOD(DramFixture, "store line in DELAY cycles", "[dram]") { - Response r; + int r; signed int w; std::array<signed int, LINE_SIZE> buffer; CHECK(expected == actual); w = 0x11223344; buffer = {w, w + 1, w + 2, w + 3}; - this->wait_for_storage(this->delay, WAIT, [this, w, buffer]() { - return this->d->write_line(MEM, buffer, 0x0); - }); + this->wait_for_storage( + this->delay, [this, w, buffer]() { return this->d->write_line(this->mem, buffer, 0x0); }); - r = d->write_line(MEM, buffer, 0x0); - CHECK(r == OK); + r = d->write_line(this->mem, buffer, 0x0); + CHECK(r); actual = d->view(0, 1)[0]; expected = buffer; REQUIRE(expected == actual); } -TEST_CASE_METHOD( - DramFixture, "store line in DELAY cycles no conflict", "[dram]") +TEST_CASE_METHOD(DramFixture, "store line in DELAY cycles no conflict", "[dram]") { - Response r; + int r; signed int w; std::array<signed int, LINE_SIZE> buffer; CHECK(expected == actual); w = 0x11223344; buffer = {w, w + 1, w + 2, w + 3}; - this->wait_for_storage(this->delay, WAIT, [this, w, buffer]() { - return this->d->write_line(MEM, buffer, 0x0); - }); + this->wait_for_storage( + this->delay, [this, w, buffer]() { return this->d->write_line(this->mem, buffer, 0x0); }); - r = this->d->write_line(MEM, buffer, 0x0); - REQUIRE(r == OK); + r = this->d->write_line(this->mem, buffer, 0x0); + REQUIRE(r); expected = buffer; actual = d->view(0, 1)[0]; REQUIRE(expected == actual); buffer = {w + 4, w + 5, w + 6, w + 7}; - this->wait_for_storage(this->delay, WAIT, [this, w, buffer]() { - return this->d->write_line(FETCH, buffer, 0x1); - }); + this->wait_for_storage( + this->delay, [this, w, buffer]() { return this->d->write_line(this->fetch, buffer, 0x1); }); - r = this->d->write_line(FETCH, buffer, 0x1); - CHECK(r == OK); + r = this->d->write_line(this->fetch, buffer, 0x1); + CHECK(r); expected = buffer; actual = d->view(0, 1)[0]; REQUIRE(expected == actual); } -TEST_CASE_METHOD( - DramFixture, "store line in DELAY cycles with conflict", "[dram]") +TEST_CASE_METHOD(DramFixture, "store line in DELAY cycles with conflict", "[dram]") { - Response r; + int r, i; signed int w; - int i; std::array<signed int, LINE_SIZE> buffer; CHECK(expected == actual); w = 0x11223344; buffer = {w, w + 1, w + 2, w + 3}; for (i = 0; i < this->delay; ++i) { - r = this->d->write_line(MEM, buffer, 0x0); - CHECK(r == WAIT); - r = d->write_line(FETCH, buffer, 0x1); - CHECK(r == WAIT); + r = this->d->write_line(this->mem, buffer, 0x0); + CHECK(!r); + r = d->write_line(this->fetch, buffer, 0x1); + CHECK(!r); // check for early modifications actual = d->view(0, 1)[0]; REQUIRE(expected == actual); } - r = d->write_line(MEM, buffer, 0x0); - CHECK(r == OK); + r = d->write_line(this->mem, buffer, 0x0); + CHECK(r); actual = d->view(0, 1)[0]; expected = buffer; REQUIRE(expected == actual); buffer = {w + 4, w + 5, w + 6, w + 7}; - this->wait_for_storage(this->delay, WAIT, [this, w, buffer]() { - return this->d->write_line(FETCH, buffer, 0x1); - }); + this->wait_for_storage( + this->delay, [this, w, buffer]() { return this->d->write_line(this->fetch, buffer, 0x1); }); - r = this->d->write_line(FETCH, buffer, 0x1); - CHECK(r == OK); + r = this->d->write_line(this->fetch, buffer, 0x1); + CHECK(r); expected = buffer; actual = d->view(0, 1)[0]; @@ -227,71 +213,65 @@ TEST_CASE_METHOD( } TEST_CASE_METHOD( - DramFixture, - "store line in DELAY cycles, read in DELAY cycles, no conflict", - "[dram]") + DramFixture, "store line in DELAY cycles, read in DELAY cycles, no conflict", "[dram]") { - Response r; + int r, i, addr; signed int w; - int i, addr; CHECK(expected == actual); w = 0x11223311; addr = 0x0; expected = {w, w + 1, w + 2, w + 3}; for (i = 0; i < this->delay; ++i) { - r = d->write_line(MEM, expected, addr); - CHECK(r == WAIT); + r = d->write_line(this->mem, expected, addr); + CHECK(!r); } - r = d->write_line(MEM, expected, addr); - CHECK(r == OK); + r = d->write_line(this->mem, expected, addr); + CHECK(r); for (i = 0; i < this->delay; ++i) { - r = d->read_line(MEM, addr, actual); + r = d->read_line(this->mem, addr, actual); - CHECK(r == WAIT); + CHECK(!r); REQUIRE(expected != actual); } - r = d->read_line(MEM, addr, actual); + r = d->read_line(this->mem, addr, actual); - CHECK(r == OK); + CHECK(r); REQUIRE(expected == actual); } TEST_CASE_METHOD( - DramFixture, - "store line in DELAY cycles, read in DELAY cycles with conflict", - "[dram]") + DramFixture, "store line in DELAY cycles, read in DELAY cycles with conflict", "[dram]") { - Response r; + int r, i, addr; signed int w; - int i, addr; CHECK(expected == actual); w = 0x11223311; addr = 0x0; expected = {w, w + 1, w + 2, w + 3}; for (i = 0; i < delay; ++i) { - r = d->write_line(MEM, expected, addr); - CHECK(r == WAIT); + r = d->write_line(this->mem, expected, addr); + CHECK(!r); - r = d->read_line(FETCH, addr, actual); - CHECK(r == WAIT); + r = d->read_line(this->fetch, addr, actual); + CHECK(!r); } - r = d->write_line(MEM, expected, addr); - CHECK(r == OK); + r = d->write_line(this->mem, expected, addr); + CHECK(r); for (i = 0; i < this->delay; ++i) { - r = d->read_line(MEM, addr, actual); + r = d->read_line(this->mem, addr, actual); - CHECK(r == WAIT); + CHECK(!r); REQUIRE(expected != actual); } - r = d->read_line(MEM, addr, actual); + r = d->read_line(this->mem, addr, actual); - CHECK(r == OK); + CHECK(r); REQUIRE(expected == actual); } @@ -301,7 +281,7 @@ TEST_CASE_METHOD( "with conflict", "[dram]") { - Response r; + int r; signed int w, a; int i, j, addr; CHECK(expected == actual); @@ -311,41 +291,26 @@ TEST_CASE_METHOD( addr = 0x0; expected = {w, w + 1, w + 2, w + 3}; for (i = 0; i < this->delay; ++i) { - r = d->write_line(MEM, expected, addr); - CHECK(r == WAIT); + r = d->write_line(this->mem, expected, addr); + CHECK(!r); } - r = d->write_line(MEM, expected, addr); - CHECK(r == OK); + r = d->write_line(this->mem, expected, addr); + CHECK(r); actual = d->view(0, 1)[0]; REQUIRE(expected == actual); for (i = 0; i < LINE_SIZE; ++i) { for (j = 0; j < this->delay; ++j) { - r = d->read_word(MEM, addr, a); + r = d->read_word(this->mem, addr, a); - CHECK(r == WAIT); + CHECK(!r); REQUIRE(0x0 == a); } - r = d->read_word(MEM, addr++, a); - CHECK(r == OK); + r = d->read_word(this->mem, addr++, a); + CHECK(r); REQUIRE(w++ == a); a = 0; } } - -TEST_CASE_METHOD(DramFixture, "Sidedoor bypasses delay", "[dram]") -{ - Response r; - signed int w; - CHECK(expected == actual); - - w = 0x11223344; - r = this->d->write_word(SIDE, w, 0x0); - CHECK(r == OK); - - expected.at(0) = w; - actual = d->view(0, 1)[0]; - REQUIRE(expected == actual); -} |