summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-04-11 23:09:49 -0400
committerbd <bdunahu@operationnull.com>2025-04-11 23:09:49 -0400
commitdf580c5352528a4837b996a838f486d3838050a4 (patch)
tree72671b34d6baf1ea2ec4cd02f73fe51338ce0b6d
parent3eeb345d673bee6d62b04fc8a8a95ab822dc1e45 (diff)
Move storage to a separate git repository.
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt31
-rw-r--r--README.md14
-rw-r--r--gui/CMakeLists.txt4
-rw-r--r--gui/main.cc40
-rw-r--r--inc/cache.h84
-rw-r--r--inc/cli.h97
-rw-r--r--inc/dram.h62
-rw-r--r--inc/storage.h95
m---------ram0
-rw-r--r--src/cli/cli.cc214
-rw-r--r--src/sim/if.cc4
-rw-r--r--src/sim/mm.cc10
-rw-r--r--src/storage/cache.cc180
-rw-r--r--src/storage/dram.cc130
-rw-r--r--src/storage/storage.cc16
-rw-r--r--tests/cache.cc189
-rw-r--r--tests/dram.cc351
18 files changed, 59 insertions, 1465 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..ef77032
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "storage"]
+ path = ram
+ url = git@github.com:bdunahu/ram.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9daac12..c7918b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,12 +1,27 @@
cmake_minimum_required(VERSION 3.5)
-set(CMAKE_CXX_COMPILER "g++")
project(risc_vector)
+find_package(Git QUIET)
+if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
+ execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --remote --recursive
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ RESULT_VARIABLE GIT_SUBMOD_RESULT)
+ if(NOT GIT_SUBMOD_RESULT EQUAL "0")
+ message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
+ endif()
+endif()
+
+if(NOT EXISTS "${PROJECT_SOURCE_DIR}/ram/CMakeLists.txt")
+ message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.")
+endif()
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_compile_options(-Wall -lstdc++ -g -O0)
add_compile_options(-Wextra -Wpedantic)
+set(RAM ram)
+
# cpp standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -16,7 +31,11 @@ include_directories(
${PROJECT_SOURCE_DIR}/inc
)
-# add gui
+# don't build RAM's tests
+set(RAM_TESTS OF CACHE BOOL "" FORCE)
+
+# add submodules
+add_subdirectory(${RAM})
add_subdirectory(gui)
# gather source files
@@ -28,7 +47,7 @@ qt_standard_project_setup()
# binary executable
add_library(${PROJECT_NAME}_lib ${SRCS})
-target_link_libraries(${PROJECT_NAME}_lib)
+target_link_libraries(${PROJECT_NAME}_lib ${RAM}_lib)
find_package(Catch2 REQUIRED)
@@ -36,10 +55,10 @@ find_package(Catch2 REQUIRED)
file(GLOB_RECURSE TESTS "tests/*.cc")
# test executable
-add_executable(tests ${SRCS} ${TESTS})
-target_link_libraries(tests PRIVATE Catch2::Catch2WithMain PRIVATE)
+add_executable(test_rv ${SRCS} ${TESTS})
+target_link_libraries(test_rv PRIVATE Catch2::Catch2WithMain PRIVATE ${RAM}_lib)
# test discovery
include(CTest)
include(Catch)
-catch_discover_tests(tests)
+catch_discover_tests(test_rv)
diff --git a/README.md b/README.md
index a6ce662..1a87057 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
-# Risc V[ECTOR]
+# RISC V[ECTOR]
+
+## Dependencies
-## dependencies
- cmake
- g++ (GCC) 11.4.0
- catch2 version 3.5.3
- Qt version 6.8.2
+- RAM (a custom memory submodule)
## to compile
Generate the build directory with
@@ -15,8 +17,12 @@ then compile both the simulator and tests with
`cmake --build build`
+To develop, the following git option is useful to keep modules updated.:
+
+`git config submodule.recurse true`
+
# about
-University of Massachusetts, Amherst
-CS535 -- Computer Architecture and ISA Design
+Created at the University of Massachusetts, Amherst
+CS535 -- Computer Architecture and ISA Design
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 6b5eb22..5b177d2 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -1,5 +1,4 @@
cmake_minimum_required(VERSION 3.5)
-set(CMAKE_CXX_COMPILER "g++")
add_compile_options(-Wall -lstdc++)
add_compile_options(-Wextra -Wpedantic)
@@ -22,9 +21,8 @@ file(GLOB SRCS
qt_add_resources(GUI_RESOURCES "resources.qrc")
add_executable(risc_vector ${SRCS} ${GUI_RESOURCES})
-target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_lib Qt6::Widgets)
+target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_lib ram_lib Qt6::Widgets)
set_target_properties(risc_vector PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
)
-
diff --git a/gui/main.cc b/gui/main.cc
index ce47d10..e873d1c 100644
--- a/gui/main.cc
+++ b/gui/main.cc
@@ -1,4 +1,3 @@
-#include "cli.h"
#include "definitions.h"
#include "gui.h"
#include "logger.h"
@@ -34,31 +33,24 @@ static void print_version_number()
static void err()
{
std::cerr << "Usage:\n\trisc_vector [OPTIONS]\nOptions:\n\t--debug,\t-d: "
- "turn on verbose output\n\t--memory-only,\t-m: run the memory "
- "simulator only, without a GUI.\n\t--version,\t-v: print the "
- "version information and exit\n"
+ "turn on verbose output\n\t--version,\t-v: print the version "
+ "information and exit\n"
<< std::endl;
}
-static void parseArguments(int argc, char **argv, bool &memory_only)
+static void parseArguments(int argc, char **argv)
{
struct option long_options[] = {
- {"debug", no_argument, 0, 'd'},
- {"memory-only", no_argument, 0, 'm'},
- {0, 0, 0, 0}};
+ {"debug", no_argument, 0, 'd'}, {0, 0, 0, 0}};
int opt;
- while ((opt = getopt_long(argc, argv, "d:m", long_options, NULL)) != -1) {
+ while ((opt = getopt_long(argc, argv, "d", long_options, NULL)) != -1) {
switch (opt) {
case 'd':
global_log->setLevel(DEBUG);
global_log->log(DEBUG, "DEBUG output enabled.");
break;
- case 'm':
- global_log->log(INFO, "Starting the storage CLI interface...");
- memory_only = true;
- break;
default:
err();
exit(EXIT_FAILURE);
@@ -71,21 +63,11 @@ int main(int argc, char **argv)
print_version_number();
global_log->log(INFO, "Initializing...");
- bool memory_only = false;
- parseArguments(argc, argv, memory_only);
-
- if (memory_only) {
- Cli cli;
- cli.run();
- } else {
- global_log->log(INFO, "Starting QT...");
- QApplication a(argc, argv);
- GUI w;
- w.show();
- return a.exec();
- }
+ parseArguments(argc, argv);
- global_log->log(INFO, "Cleaning up...");
- global_log->log(INFO, "Goodbye!");
- return EXIT_SUCCESS;
+ global_log->log(INFO, "Starting QT...");
+ QApplication a(argc, argv);
+ GUI w;
+ w.show();
+ return a.exec();
}
diff --git a/inc/cache.h b/inc/cache.h
deleted file mode 100644
index 88fd352..0000000
--- a/inc/cache.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef CACHE_H
-#define CACHE_H
-#include "definitions.h"
-#include "storage.h"
-#include <array>
-#include <ostream>
-#include <functional>
-
-class Cache : public Storage
-{
- public:
- /**
- * Constructor.
- * @param The number of `lines` contained in memory. The total number of
- * words is this number multiplied by LINE_SIZE.
- * @param The next lowest level in storage. Methods from this object are
- * called in case of a cache miss.
- * @param The number of clock cycles each access takes.
- * @return A new cache object.
- */
- 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;
-
- /**
- * 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;
-
- private:
- /**
- * Helper for all access methods.
- * Calls `request_handler` when `accessor` 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);
- /**
- * Returns OK if `accessor` is allowed to complete its request this cycle.
- * Handles cache misses, wait times, and setting the current accessor this
- * storage is serving.
- * @param the accessor asking for a resource
- * @return whether or not the access can be carried out this function call.
- */
- Response is_access_cleared(Accessor accessor, int address);
- /**
- * Helper for 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.
- * @param the address that must be present in cache.
- */
- void handle_miss(int address);
- /**
- * An array of metadata about elements in `data`.
- * If the first value of an element is negative, the corresponding
- * element in `data` is invalid. If the most second value of an element
- * is nonzero, the corresponding element in `data` is dirty.
- */
- 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/dram.h b/inc/dram.h
deleted file mode 100644
index 102ec0f..0000000
--- a/inc/dram.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef DRAM_H
-#define DRAM_H
-#include "definitions.h"
-#include "storage.h"
-#include <ostream>
-#include <functional>
-
-class Dram : public Storage
-{
- public:
- /**
- * Constructor.
- * @param The number of clock cycles each access takes.
- * @return A new memory object.
- */
- 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;
-
- /**
- * TODO This will accept a file at a later date.
- */
- void load(std::vector<signed int> program);
-
- private:
- /**
- * Helper for all access methods.
- * Calls `request_handler` when `accessor` 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 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
- * storage is serving.
- * @param the accessor asking for a resource
- * @return whether or not the access can be carried out this function call.
- */
- Response is_access_cleared(Accessor accessor);
-};
-
-std::ostream &operator<<(std::ostream &os, const Dram &d);
-
-#endif /* DRAM_H_INCLUDED */
diff --git a/inc/storage.h b/inc/storage.h
deleted file mode 100644
index d6fa094..0000000
--- a/inc/storage.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef STORAGE_H
-#define STORAGE_H
-#include "accessor.h"
-#include "definitions.h"
-#include "response.h"
-#include <algorithm>
-#include <array>
-#include <map>
-#include <vector>
-
-class Storage
-{
- public:
- virtual ~Storage() = default;
-
- /**
- * Write `data` word into `address`.
- * @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
- */
- virtual Response write_line(Accessor accessor, 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.
- */
- virtual Response read_line(
- Accessor accessor,
- int address,
- std::array<signed int, LINE_SIZE> &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.
- * @return A matrix of data values, where each row is a line and each column
- * is a word.
- */
- 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.
- */
- std::vector<std::array<signed int, LINE_SIZE>> *data;
- /**
- * A pointer to the next lowest level of storage.
- * Used in case of cache misses.
- */
- Storage *lower;
- /**
- * 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/ram b/ram
new file mode 160000
+Subproject be2bc108dc112ae7e21d4a77f7bcbfac88d6fcd
diff --git a/src/cli/cli.cc b/src/cli/cli.cc
deleted file mode 100644
index 58575cb..0000000
--- a/src/cli/cli.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-#include "cli.h"
-#include "cache.h"
-#include "definitions.h"
-#include "dram.h"
-#include "response.h"
-#include "accessor.h"
-#include "utils.h"
-#include <iostream>
-
-Cli::Cli()
-{
- this->cache = nullptr;
- this->cycle = 0;
- this->initialize();
-
- commands['l'] = [this](std::vector<std::string> args) {
- Accessor a;
- if (args.size() >= 2) {
- try {
- a = match_accessor_or_die(args[0]);
- load(a, std::stoi(args[1]));
- } catch (const std::invalid_argument &e) {
- std::cerr << "Invalid input: " << e.what() << std::endl;
- }
- } else {
- std::cout << "Usage: l <memory-address>\n";
- }
- return;
- };
-
- commands['s'] = [this](std::vector<std::string> args) {
- Accessor a;
- if (args.size() >= 3) {
- try {
- a = match_accessor_or_die(args[0]);
- store(a, std::stoi(args[1]), std::stoi(args[2]));
- } catch (const std::invalid_argument &e) {
- std::cerr << "Invalid input: " << e.what() << std::endl;
- }
- } else {
- std::cout << "Usage: s <memory-address> <data>\n";
- }
- return;
- };
-
- commands['r'] = [this](std::vector<std::string> args) {
- (void)args;
- reset();
- return;
- };
-
- commands['p'] = [this](std::vector<std::string> args) {
- if (args.size() >= 1) {
- try {
- peek(std::stoi(args[0]));
- } catch (const std::invalid_argument &e) {
- std::cerr << "Invalid input: " << e.what() << std::endl;
- }
- } else {
- std::cout << "Usage: v <storage-level> <base> <lines>\n";
- }
- return;
- };
-
- commands['h'] = [this](std::vector<std::string> args) {
- (void)args;
- help();
- return;
- };
-}
-
-Cli::~Cli() { delete this->cache; }
-
-void Cli::help()
-{
- std::cout
- << "Available commands:" << std::endl
- << " [l]oad <address> - Load data from memory at the specified "
- "address"
- << std::endl
- << " [s]tore <accessor> <data> <address> - Stores data into memory at "
- "specified address. Acessor must be one of: [f]etch, [m]em"
- << " [p]eek <storage-level> <base> <lines> - side door function that "
- "peeks the current status of the entire memory subsystem"
- << std::endl
- << " [r]eset - side door function that resets the memory "
- "configuration and "
- "cycles"
- << std::endl
- << " [h]elp - prints this help text" << std::endl
- << " [q]uit - quits the program" << std::endl;
-}
-
-void Cli::load(Accessor accessor, int address)
-{
- address = wrap_address(address);
- const auto default_flags = std::cout.flags();
- const auto default_fill = std::cout.fill();
-
- signed int data;
- Response r = this->cache->read_word(accessor, address, data);
- std::cout << r << " to " << accessor << " reading " << address << std::endl;
- if (r == OK)
- std::cout << " Got: " << std::hex << data << std::endl;
-
- std::cout.flags(default_flags);
- std::cout.fill(default_fill);
-}
-
-void Cli::store(Accessor accessor, int data, int address)
-{
- address = wrap_address(address);
- Response r = this->cache->write_word(accessor, data, address);
- std::cout << r << " to " << accessor << " storing " << data << " in "
- << address << std::endl;
-}
-
-void Cli::reset()
-{
- this->initialize();
- std::cout << "Done." << std::endl;
-}
-
-void Cli::peek(int level)
-{
- Storage *curr = this->cache;
- for (int i = 0; i < level; ++i) {
- if (!curr) {
- std::cerr << "Level " << level << " of storage does not exist."
- << std::endl;
- return;
- }
- curr = curr->get_lower();
- }
-
- Cache *c = dynamic_cast<Cache *>(curr);
- if (c) {
- std::cout << *c << std::endl;
- } else {
- std::cout << *dynamic_cast<Dram *>(curr) << std::endl;
- ;
- }
-}
-
-void Cli::run()
-{
- std::cout << "Memory Command Processor Started. Type 'h' for a list of "
- "commands."
- << std::endl;
- std::string input;
-
- bool run = true;
- while (run) {
- std::cout << this->cycle << "> ";
- std::getline(std::cin, input);
-
- std::istringstream iss1(input);
- std::vector<std::string> words;
- std::string sentence;
- std::string word;
-
- while (std::getline(iss1, sentence, ';')) {
- words.clear();
- std::istringstream iss2(sentence);
-
- while (iss2 >> word) {
- words.push_back(word);
- }
- if (words.empty())
- continue;
-
- std::string command = words[0];
- words.erase(words.begin());
-
- if (command == "q") {
- run = false;
- break;
- }
-
- auto it = commands.find(tolower(command[0]));
- if (it != commands.end()) {
- it->second(words);
- } else {
- std::cout << "Unknown command: '" << command
- << "'. Type 'help' for available commands."
- << std::endl;
- }
- }
- }
-}
-
-void Cli::initialize()
-{
- Logger *global_log = Logger::getInstance();
-
- global_log->log(INFO, "Resetting memory configuration and cycle.");
-
- if (this->cache != nullptr)
- delete this->cache;
-
- Dram *d = new Dram(MEM_DELAY);
- this->cache = new Cache(d, L1_CACHE_DELAY);
- this->cycle = 1;
-}
-
-Accessor Cli::match_accessor_or_die(std::string s)
-{
- if (tolower(s[0]) == 'f')
- return FETCH;
- else if (tolower(s[0]) == 'm')
- return MEM;
- else
- throw std::invalid_argument(s);
-}
diff --git a/src/sim/if.cc b/src/sim/if.cc
index 85fb27f..4ab7f3e 100644
--- a/src/sim/if.cc
+++ b/src/sim/if.cc
@@ -26,10 +26,12 @@ InstrDTO *IF::advance(Response p)
void IF::advance_helper()
{
Response r;
+ int i;
signed int bits;
if (this->curr_instr == nullptr) {
- r = this->storage->read_word(this->id, this->pc, bits);
+ i = this->storage->read_word(this, this->pc, bits);
+ r = i ? OK : STALLED;
if (r == OK) {
this->curr_instr = new InstrDTO();
this->curr_instr->set_instr_bits(bits);
diff --git a/src/sim/mm.cc b/src/sim/mm.cc
index 07a362b..a9a60c2 100644
--- a/src/sim/mm.cc
+++ b/src/sim/mm.cc
@@ -9,11 +9,12 @@ MM::MM(Stage *stage) : Stage(stage) { this->id = MEM; }
void MM::advance_helper()
{
signed int data;
+ int i;
switch (this->curr_instr->get_mnemonic()) {
case LOAD:
- this->status = this->storage->read_word(
- this->id, this->curr_instr->get_s1(), data);
+ i = this->storage->read_word(this, this->curr_instr->get_s1(), data);
+ this->status = i ? OK : STALLED;
if (this->status == OK) {
this->curr_instr->set_s1(data);
} else
@@ -22,8 +23,9 @@ void MM::advance_helper()
case STORE:
// TODO signed issues, we aren't wrapping addresses
- this->status = this->storage->write_word(
- this->id, this->curr_instr->get_s2(), this->curr_instr->get_s1());
+ i = this->storage->write_word(
+ this, this->curr_instr->get_s2(), this->curr_instr->get_s1());
+ this->status = i ? OK : STALLED;
if (this->status != OK) {
this->status = STALLED;
}
diff --git a/src/storage/cache.cc b/src/storage/cache.cc
deleted file mode 100644
index 80f59ef..0000000
--- a/src/storage/cache.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-#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;
-}
diff --git a/src/storage/dram.cc b/src/storage/dram.cc
deleted file mode 100644
index f90f8db..0000000
--- a/src/storage/dram.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-#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() { delete this->data; }
-
-Response Dram::write_line(
- Accessor accessor, std::array<signed int, LINE_SIZE> data_line, int address)
-{
- return process(accessor, address, [&](int line, int word) {
- (void)word;
- this->data->at(line) = data_line;
- });
-}
-
-Response Dram::write_word(Accessor accessor, signed int data, int address)
-{
- return process(accessor, 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)
-{
- return process(accessor, address, [&](int line, int word) {
- (void)word;
- data_line = this->data->at(line);
- });
-}
-
-Response Dram::read_word(Accessor accessor, int address, signed int &data)
-{
- return process(accessor, 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) {
- unsigned long i;
- for (i = 0; i < program.size(); ++i) {
- int line, word;
- get_memory_index(i, line, word);
- this->data->at(line).at(word) = program[i];
- }
-}
-
-Response Dram::process(
- Accessor accessor,
- int address,
- std::function<void(int line, int word)> request_handler)
-{
- Response r = this->is_access_cleared(accessor);
- if (r == OK) {
- int line, word;
- get_memory_index(address, line, word);
- request_handler(line, word);
- }
- return r;
-}
-
-Response Dram::is_access_cleared(Accessor accessor)
-{
- 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) << ' ';
- }
- os << std::endl;
- }
-
- std::cout.flags(default_flags);
- std::cout.fill(default_fill);
- return os;
-}
diff --git a/src/storage/storage.cc b/src/storage/storage.cc
deleted file mode 100644
index fed607b..0000000
--- a/src/storage/storage.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "storage.h"
-#include "definitions.h"
-#include <algorithm>
-
-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());
- return ret;
-}
-
-Storage *Storage::get_lower() { return this->lower; }
diff --git a/tests/cache.cc b/tests/cache.cc
deleted file mode 100644
index 0b04bce..0000000
--- a/tests/cache.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "cache.h"
-#include "dram.h"
-#include <catch2/catch_test_macros.hpp>
-
-class CacheFixture
-{
- public:
- CacheFixture()
- {
- this->m_delay = 4;
- this->c_delay = 2;
- this->d = new Dram(this->m_delay);
- this->c = new Cache(this->d, this->c_delay);
- this->expected = {0, 0, 0, 0};
- this->actual = this->c->view(0, 1)[0];
- }
-
- ~CacheFixture() { delete this->c; }
-
- /**
- * An operation that is done a lot.
- */
- void
- wait_for_storage(int delay, Response expected, std::function<Response()> f)
- {
- for (int i = 0; i < delay; ++i) {
- Response r = f();
-
- // check response
- CHECK(r == expected);
- // check for early modifications
- actual = c->view(0, 1)[0];
- REQUIRE(this->expected == this->actual);
- }
- }
-
- int m_delay;
- int c_delay;
- Cache *c;
- Dram *d;
- 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;
- 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);
- });
-
- r = c->write_word(MEM, w, 0b0);
- CHECK(r == OK);
-
- actual = this->d->view(0, 1)[0];
- // we do NOT write back now!
- REQUIRE(expected == actual);
-
- expected.at(0) = w;
- actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
-}
-
-TEST_CASE_METHOD(
- CacheFixture,
- "store 0th, 1st element in DELAY cycles, with conflict",
- "[cache]")
-{
- Response r;
- signed int w;
- int 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->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);
-
- actual = d->view(0, 1)[0];
- // we do NOT write back now!
- REQUIRE(expected == actual);
-
- expected.at(0) = w;
- actual = c->view(0, 1)[0];
- 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);
- });
-
- 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]")
-{
- Response 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);
- });
-
- 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);
- });
-
- // after the fetch, this cache line should be empty
- this->c->write_word(FETCH, w, 0b10000001);
- CHECK(r == OK);
-
- 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);
- });
-
- r = c->write_word(FETCH, w, 0b10000001);
- CHECK(r == OK);
-
- expected.at(0) = 0;
- expected.at(1) = w;
- actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
-}
diff --git a/tests/dram.cc b/tests/dram.cc
deleted file mode 100644
index 0e97e81..0000000
--- a/tests/dram.cc
+++ /dev/null
@@ -1,351 +0,0 @@
-#include "dram.h"
-#include <array>
-#include <catch2/catch_test_macros.hpp>
-
-class DramFixture
-{
- public:
- DramFixture()
- {
- this->delay = 3;
- this->d = new Dram(this->delay);
- this->expected = {0, 0, 0, 0};
- this->actual = this->d->view(0, 1)[0];
- }
-
- ~DramFixture() { delete this->d; }
-
- /**
- * An operation that is done a lot.
- */
- void
- wait_for_storage(int delay, Response expected, std::function<Response()> f)
- {
- for (int i = 0; i < delay; ++i) {
- Response r = f();
-
- // check response
- CHECK(r == expected);
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(this->expected == this->actual);
- }
- }
-
- int delay;
- Dram *d;
- 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;
- 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);
- });
-
- r = this->d->write_word(MEM, w, 0x0);
-
- CHECK(r == OK);
- 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]")
-{
- Response 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);
- });
-
- r = d->write_word(MEM, w, 0x0);
- REQUIRE(r == OK);
-
- 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);
- });
-
- r = d->write_word(FETCH, w, 0x1);
- CHECK(r == OK);
-
- 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]")
-{
- Response r;
- 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);
-
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
-
- r = d->write_word(MEM, w, 0x0);
- REQUIRE(r == OK);
-
- 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);
- });
-
- r = d->write_word(FETCH, w, 0x1);
- CHECK(r == OK);
-
- actual = d->view(0, 1)[0];
- expected.at(1) = w;
- REQUIRE(expected == actual);
-}
-
-TEST_CASE_METHOD(DramFixture, "store line in DELAY cycles", "[dram]")
-{
- Response 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);
- });
-
- r = d->write_line(MEM, buffer, 0x0);
- CHECK(r == OK);
-
- actual = d->view(0, 1)[0];
- expected = buffer;
- REQUIRE(expected == actual);
-}
-
-TEST_CASE_METHOD(
- DramFixture, "store line in DELAY cycles no conflict", "[dram]")
-{
- Response 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);
- });
-
- r = this->d->write_line(MEM, buffer, 0x0);
- REQUIRE(r == OK);
-
- 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);
- });
-
- r = this->d->write_line(FETCH, buffer, 0x1);
- CHECK(r == OK);
-
- expected = buffer;
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
-}
-
-TEST_CASE_METHOD(
- DramFixture, "store line in DELAY cycles with conflict", "[dram]")
-{
- Response r;
- 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);
-
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
-
- r = d->write_line(MEM, buffer, 0x0);
- CHECK(r == OK);
-
- 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);
- });
-
- r = this->d->write_line(FETCH, buffer, 0x1);
- CHECK(r == OK);
-
- expected = buffer;
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
-}
-
-TEST_CASE_METHOD(
- DramFixture,
- "store line in DELAY cycles, read in DELAY cycles, no conflict",
- "[dram]")
-{
- Response r;
- 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(MEM, expected, addr);
- CHECK(r == OK);
-
- for (i = 0; i < this->delay; ++i) {
- r = d->read_line(MEM, addr, actual);
-
- CHECK(r == WAIT);
- REQUIRE(expected != actual);
- }
-
- r = d->read_line(MEM, addr, actual);
-
- CHECK(r == OK);
- REQUIRE(expected == actual);
-}
-
-TEST_CASE_METHOD(
- DramFixture,
- "store line in DELAY cycles, read in DELAY cycles with conflict",
- "[dram]")
-{
- Response r;
- 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->read_line(FETCH, addr, actual);
- CHECK(r == WAIT);
- }
- r = d->write_line(MEM, expected, addr);
- CHECK(r == OK);
-
- for (i = 0; i < this->delay; ++i) {
- r = d->read_line(MEM, addr, actual);
-
- CHECK(r == WAIT);
- REQUIRE(expected != actual);
- }
-
- r = d->read_line(MEM, addr, actual);
-
- CHECK(r == OK);
- REQUIRE(expected == actual);
-}
-
-TEST_CASE_METHOD(
- DramFixture,
- "store line in DELAY cycles, read one element at a time in DELAY cycles "
- "with conflict",
- "[dram]")
-{
- Response r;
- signed int w, a;
- int i, j, addr;
- CHECK(expected == actual);
-
- w = 0x11223311;
- a = 0x0;
- 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(MEM, expected, addr);
- CHECK(r == OK);
-
- 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);
-
- CHECK(r == WAIT);
- REQUIRE(0x0 == a);
- }
- r = d->read_word(MEM, addr++, a);
- CHECK(r == OK);
- 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);
-}