diff options
author | bd <bdunahu@operationnull.com> | 2025-03-26 12:21:52 -0400 |
---|---|---|
committer | bd <bdunahu@operationnull.com> | 2025-03-26 12:21:52 -0400 |
commit | b81c86b438123457be86af2e7c24375856afa742 (patch) | |
tree | 74f271585bce27de2434d8cd826fee09f6a71738 | |
parent | 9eeea1ab8bf4eb17e5da46d57a6c1d455a0a262e (diff) |
Add fetch stage implementation, tests, program loading, DTO object
-rw-r--r-- | inc/controller.h | 12 | ||||
-rw-r--r-- | inc/dram.h | 5 | ||||
-rw-r--r-- | inc/ex.h | 3 | ||||
-rw-r--r-- | inc/id.h | 3 | ||||
-rw-r--r-- | inc/if.h | 9 | ||||
-rw-r--r-- | inc/instrDTO.h | 39 | ||||
-rw-r--r-- | inc/mm.h | 3 | ||||
-rw-r--r-- | inc/stage.h | 16 | ||||
-rw-r--r-- | inc/wb.h | 3 | ||||
-rw-r--r-- | src/sim/controller.cc | 27 | ||||
-rw-r--r-- | src/sim/ex.cc | 3 | ||||
-rw-r--r-- | src/sim/id.cc | 3 | ||||
-rw-r--r-- | src/sim/if.cc | 22 | ||||
-rw-r--r-- | src/sim/instrDTO.cc | 15 | ||||
-rw-r--r-- | src/sim/mm.cc | 3 | ||||
-rw-r--r-- | src/sim/stage.cc | 2 | ||||
-rw-r--r-- | src/sim/wb.cc | 3 | ||||
-rw-r--r-- | src/storage/dram.cc | 10 | ||||
-rw-r--r-- | tests/controller.cc | 14 | ||||
-rw-r--r-- | tests/if.cc | 99 |
20 files changed, 247 insertions, 47 deletions
diff --git a/inc/controller.h b/inc/controller.h index 56f3836..4b102ce 100644 --- a/inc/controller.h +++ b/inc/controller.h @@ -2,6 +2,7 @@ #define CONTROLLER_H #include "response.h" #include "stage.h" +#include "instrDTO.h" /** * Houses the clock, and acts as the main API to the GUI. @@ -11,11 +12,12 @@ class Controller : public Stage public: /** * Constructor. + * @param The stage(s) to interface with. * @param The storage object to use. * @param Whether or not efficient pipelining will be used. * @return A newly allocated controller object. */ - Controller(Storage *storage, bool is_pipelined); + Controller(Stage *stage, Storage *storage, bool is_pipelined); /** * Direct the simulator to run for `number` clock cycles. @@ -34,13 +36,7 @@ class Controller : public Stage * @return the pc. */ int get_pc(); - Response advance(); - - private: - /** - * The current clock cycle. - */ - int clock_cycle; + Response advance(InstrDTO &i) override; }; #endif /* CONTROLLER_H_INCLUDED */ @@ -29,6 +29,11 @@ class Dram : public Storage 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. @@ -1,5 +1,6 @@ #ifndef EX_H #define EX_H +#include "instrDTO.h" #include "response.h" #include "stage.h" @@ -8,7 +9,7 @@ class EX : public Stage public: using Stage::Stage; - Response advance(); + Response advance(InstrDTO &i) override; }; #endif /* EX_H_INCLUDED */ @@ -1,5 +1,6 @@ #ifndef ID_H #define ID_H +#include "instrDTO.h" #include "response.h" #include "stage.h" @@ -8,7 +9,7 @@ class ID : public Stage public: using Stage::Stage; - Response advance(); + Response advance(InstrDTO &i) override; }; #endif /* ID_D_INCLUDED */ @@ -1,5 +1,6 @@ #ifndef IF_H #define IF_H +#include "instrDTO.h" #include "response.h" #include "stage.h" @@ -8,7 +9,13 @@ class IF : public Stage public: using Stage::Stage; - Response advance(); + Response advance(InstrDTO &i) override; + + private: + /** + * The name this pipeline stages uses to access storage. + */ + const Accessor id = FETCH; }; #endif /* IF_H_INCLUDED */ diff --git a/inc/instrDTO.h b/inc/instrDTO.h new file mode 100644 index 0000000..86cec05 --- /dev/null +++ b/inc/instrDTO.h @@ -0,0 +1,39 @@ +#ifndef INSTRDTO_H +#define INSTRDTO_H + +class InstrDTO +{ + public: + /** + * Constructor. + */ + InstrDTO(); + ~InstrDTO() = default; + + /** + * @return if_cycle + */ + int get_if_cycle(); + /** + * @return instr_bits + */ + signed int get_instr_bits(); + + /** + * @param if_cycle + */ + void set_if_cycle(int); + /** + * @param instr_bits + */ + void set_instr_bits(signed int); + + private: + /** + * The current clock cycle. + */ + int if_cycle; + signed int instr_bits; +}; + +#endif /* INSTRDTO_H_INCLUDED */ @@ -1,5 +1,6 @@ #ifndef MM_H #define MM_H +#include "instrDTO.h" #include "response.h" #include "stage.h" @@ -8,7 +9,7 @@ class MM : public Stage public: using Stage::Stage; - Response advance(); + Response advance(InstrDTO &i) override; }; #endif /* MM_H_INCLUDED */ diff --git a/inc/stage.h b/inc/stage.h index 494f3d3..ac810a9 100644 --- a/inc/stage.h +++ b/inc/stage.h @@ -1,6 +1,7 @@ #ifndef STAGE_H #define STAGE_H #include "definitions.h" +#include "instrDTO.h" #include "response.h" #include "storage.h" #include <array> @@ -8,14 +9,21 @@ class Stage { public: + /** + * Constructor. + * @param The next stage in the pipeline. + * @return A newly allocated stage object. + */ Stage(Stage *next); virtual ~Stage() = default; /** * Advances this stage by a single clock cycle. + * @param a DTO object containing various information about an instruction + * moving through the pipeline. * @return a response, indicating whether this pipeline stage is stalled, * busy, or done. */ - virtual Response advance() = 0; + virtual Response advance(InstrDTO &i) = 0; protected: /** @@ -37,7 +45,11 @@ class Stage /** * A flag indicating whether pipelining should be used. */ - bool is_pipelined; + static bool is_pipelined; + /** + * The current clock cycle. + */ + static int clock_cycle; }; #endif /* STAGE_H_INCLUDED */ @@ -2,13 +2,14 @@ #define WB_H #include "response.h" #include "stage.h" +#include "instrDTO.h" class WB : public Stage { public: using Stage::Stage; - Response advance(); + Response advance(InstrDTO &i) override; }; #endif /* WB_H_INCLUDED */ diff --git a/src/sim/controller.cc b/src/sim/controller.cc index 93fd0e0..2813905 100644 --- a/src/sim/controller.cc +++ b/src/sim/controller.cc @@ -1,34 +1,23 @@ #include "controller.h" -#include "ex.h" -#include "id.h" -#include "if.h" -#include "mm.h" #include "response.h" #include "storage.h" -#include "wb.h" -Controller::Controller(Storage *storage, bool is_pipelined) - : Stage(nullptr) +Controller::Controller(Stage *stage, Storage *storage, bool is_pipelined) + : Stage(stage) { this->clock_cycle = 0; this->storage = storage; this->is_pipelined = is_pipelined; this->pc = 0x0; this->gprs = {0}; - - IF *f = new IF(nullptr); - ID *d = new ID(f); - EX *e = new EX(d); - MM *m = new MM(e); - WB *w = new WB(m); - this->next = w; } void Controller::run_for(int number) { + InstrDTO instr; int i; for (i = 0; i < number; ++i) { - this->advance(); + this->advance(instr); } } @@ -38,9 +27,11 @@ std::array<int, GPR_NUM> Controller::get_gprs() { return this->gprs; } int Controller::get_pc() { return this->pc; } -Response Controller::advance() +Response Controller::advance(InstrDTO &i) { - this->next->advance(); + Response r; + + r = this->next->advance(i); ++this->clock_cycle; - return OK; + return r; } diff --git a/src/sim/ex.cc b/src/sim/ex.cc index f286713..1de61d0 100644 --- a/src/sim/ex.cc +++ b/src/sim/ex.cc @@ -1,10 +1,11 @@ #include "ex.h" +#include "instrDTO.h" #include "logger.h" #include "response.h" static Logger *global_log = Logger::getInstance(); -Response EX::advance() +Response EX::advance(InstrDTO &i) { global_log->log(INFO, "hello from execute!"); return OK; diff --git a/src/sim/id.cc b/src/sim/id.cc index 56d9549..df55fe2 100644 --- a/src/sim/id.cc +++ b/src/sim/id.cc @@ -1,10 +1,11 @@ #include "id.h" +#include "instrDTO.h" #include "logger.h" #include "response.h" static Logger *global_log = Logger::getInstance(); -Response ID::advance() +Response ID::advance(InstrDTO &i) { global_log->log(INFO, "hello from decode!"); return OK; diff --git a/src/sim/if.cc b/src/sim/if.cc index 1026072..deed8e1 100644 --- a/src/sim/if.cc +++ b/src/sim/if.cc @@ -1,15 +1,19 @@ #include "if.h" -#include "logger.h" +#include "accessor.h" +#include "instrDTO.h" #include "response.h" -static Logger *global_log = Logger::getInstance(); - -Response IF::advance() +Response IF::advance(InstrDTO &i) { - global_log->log(INFO, "hello from fetch!"); - return OK; -} - - + Response r; + signed int bits; + r = this->storage->read_word(this->id, this->pc, bits); + if (r == OK) { + ++this->pc; + i.set_if_cycle(this->clock_cycle); + i.set_instr_bits(bits); + } + return r; +} diff --git a/src/sim/instrDTO.cc b/src/sim/instrDTO.cc new file mode 100644 index 0000000..6427b1a --- /dev/null +++ b/src/sim/instrDTO.cc @@ -0,0 +1,15 @@ +#include "instrDTO.h" + +InstrDTO::InstrDTO() +{ + this->if_cycle = 0; + this->instr_bits = 0; +} + +int InstrDTO::get_if_cycle() { return this->if_cycle; } + +signed int InstrDTO::get_instr_bits() { return this->instr_bits; } + +void InstrDTO::set_if_cycle(int cycle) { this->if_cycle = cycle; } + +void InstrDTO::set_instr_bits(signed int instr) { this->instr_bits = instr; } diff --git a/src/sim/mm.cc b/src/sim/mm.cc index be774ad..28243e7 100644 --- a/src/sim/mm.cc +++ b/src/sim/mm.cc @@ -1,10 +1,11 @@ #include "mm.h" #include "logger.h" #include "response.h" +#include "instrDTO.h" static Logger *global_log = Logger::getInstance(); -Response MM::advance() +Response MM::advance(InstrDTO &i) { global_log->log(INFO, "hello from memory!"); return OK; diff --git a/src/sim/stage.cc b/src/sim/stage.cc index 399743a..0d48774 100644 --- a/src/sim/stage.cc +++ b/src/sim/stage.cc @@ -7,3 +7,5 @@ Stage::Stage(Stage *next) { std::array<int, GPR_NUM> Stage::gprs; int Stage::pc; Storage *Stage::storage; +bool Stage::is_pipelined; +int Stage::clock_cycle; diff --git a/src/sim/wb.cc b/src/sim/wb.cc index 83b1c3c..9585fd3 100644 --- a/src/sim/wb.cc +++ b/src/sim/wb.cc @@ -1,10 +1,11 @@ #include "wb.h" +#include "instrDTO.h" #include "logger.h" #include "response.h" static Logger *global_log = Logger::getInstance(); -Response WB::advance() +Response WB::advance(InstrDTO &i) { global_log->log(INFO, "hello from write back!"); return OK; diff --git a/src/storage/dram.cc b/src/storage/dram.cc index 371503d..f90f8db 100644 --- a/src/storage/dram.cc +++ b/src/storage/dram.cc @@ -56,6 +56,16 @@ Response Dram::read_word(Accessor accessor, int address, signed int &data) }); } +// 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, diff --git a/tests/controller.cc b/tests/controller.cc index a1b8123..a2f8e7d 100644 --- a/tests/controller.cc +++ b/tests/controller.cc @@ -1,6 +1,11 @@ #include "controller.h" #include "cache.h" #include "dram.h" +#include "ex.h" +#include "id.h" +#include "if.h" +#include "mm.h" +#include "wb.h" #include <algorithm> #include <catch2/catch_test_macros.hpp> @@ -10,7 +15,14 @@ class ControllerPipeFixture ControllerPipeFixture() { this->c = new Cache(new Dram(3), 1); - this->ct = new Controller(this->c, true); + + IF *f = new IF(nullptr); + ID *d = new ID(f); + EX *e = new EX(d); + MM *m = new MM(e); + WB *w = new WB(m); + + this->ct = new Controller(w, this->c, true); } ~ControllerPipeFixture() { diff --git a/tests/if.cc b/tests/if.cc new file mode 100644 index 0000000..6ed6f58 --- /dev/null +++ b/tests/if.cc @@ -0,0 +1,99 @@ +#include "if.h" +#include "cache.h" +#include "controller.h" +#include "dram.h" +#include "instrDTO.h" +#include <catch2/catch_test_macros.hpp> + +class IFPipeFixture +{ + public: + IFPipeFixture() + { + Dram *d; + + d = new Dram(3); + // 0xC00 is a nop + p = {0xC000, 0xC001, 0xC002, 0xC003}; + d->load(p); + + this->c = new Cache(d, 1); + this->f = new IF(nullptr); + this->ct = new Controller(this->f, this->c, true); + } + ~IFPipeFixture() + { + delete this->ct; + delete this->c; + }; + + /** + * Fetch a clean line not in cache. + */ + void fetch_through(InstrDTO &instr) + { + int i; + Response r; + + for (i = 0; i <= MEM_DELAY; ++i) { + r = this->ct->advance(instr); + // check response + CHECK(r == BLOCKED); + } + this->fetch_cache(instr); + } + + /** + * Fetch a line in cache. + */ + void fetch_cache(InstrDTO &instr) + { + int i; + Response r; + + for (i = 0; i <= L1_CACHE_DELAY; ++i) { + r = this->ct->advance(instr); + // check response + CHECK(r == WAIT); + } + r = this->ct->advance(instr); + // check response + CHECK(r == OK); + } + + std::vector<signed int> p; + Cache *c; + IF *f; + Controller *ct; +}; + +TEST_CASE_METHOD(IFPipeFixture, "fetch returns single instuction", "[if_pipe]") +{ + InstrDTO instr; + int expected_cycles; + + expected_cycles = MEM_DELAY + L1_CACHE_DELAY + 2; + this->fetch_through(instr); + + CHECK(instr.get_if_cycle() == expected_cycles); + REQUIRE(instr.get_instr_bits() == this->p[0]); +} + +TEST_CASE_METHOD(IFPipeFixture, "fetch returns two instuctions", "[if_pipe]") +{ + InstrDTO instr; + int expected_cycles; + + expected_cycles = MEM_DELAY + L1_CACHE_DELAY + 2; + this->fetch_through(instr); + + CHECK(instr.get_if_cycle() == expected_cycles); + REQUIRE(instr.get_instr_bits() == this->p[0]); + + // is this right??? + expected_cycles += L1_CACHE_DELAY + 2; + this->fetch_cache(instr); + + CHECK(instr.get_if_cycle() == expected_cycles); + REQUIRE(instr.get_instr_bits() == this->p[1]); +} |