summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-03-30 14:28:45 -0400
committerbd <bdunahu@operationnull.com>2025-03-30 14:28:45 -0400
commit8c46ba4f216aec9f512cd398317f891be9b07e84 (patch)
treecb502366f721c6bca60becc309fd9de288769d87
parent916949133a5797772dcd6966e469c12230ffc3fa (diff)
Add mock stage, proper decode tests
-rw-r--r--inc/controller.h9
-rw-r--r--inc/dum.h28
-rw-r--r--inc/ex.h4
-rw-r--r--inc/id.h8
-rw-r--r--inc/if.h9
-rw-r--r--inc/mm.h4
-rw-r--r--inc/stage.h12
-rw-r--r--inc/wb.h6
-rw-r--r--src/logger/logger.cc8
-rw-r--r--src/sim/controller.cc2
-rw-r--r--src/sim/dum.cc41
-rw-r--r--src/sim/ex.cc2
-rw-r--r--src/sim/id.cc25
-rw-r--r--src/sim/if.cc4
-rw-r--r--src/sim/mm.cc5
-rw-r--r--src/sim/stage.cc23
-rw-r--r--src/sim/wb.cc2
-rw-r--r--tests/id.cc149
-rw-r--r--tests/if.cc6
19 files changed, 228 insertions, 119 deletions
diff --git a/inc/controller.h b/inc/controller.h
index 1c7b2d6..17aba37 100644
--- a/inc/controller.h
+++ b/inc/controller.h
@@ -1,8 +1,8 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H
+#include "instrDTO.h"
#include "response.h"
#include "stage.h"
-#include "instrDTO.h"
/**
* Houses the clock, and acts as the main API to the GUI.
@@ -18,7 +18,8 @@ class Controller : public Stage
* @return A newly allocated controller object.
*/
Controller(Stage *stage, Storage *storage, bool is_pipelined);
-
+ InstrDTO *advance(Response p) override;
+
/**
* Direct the simulator to run for `number` clock cycles.
* @param the number of clock cycles to run for.
@@ -36,7 +37,9 @@ class Controller : public Stage
* @return the pc.
*/
int get_pc();
- InstrDTO *advance(Response p) override;
+
+ private:
+ void advance_helper() override;
};
#endif /* CONTROLLER_H_INCLUDED */
diff --git a/inc/dum.h b/inc/dum.h
new file mode 100644
index 0000000..da64b9d
--- /dev/null
+++ b/inc/dum.h
@@ -0,0 +1,28 @@
+#ifndef DUM_H
+#define DUM_H
+#include "instrDTO.h"
+#include "response.h"
+#include "stage.h"
+
+/**
+ * Don't underestimate mocks (the DUM pipe stage).
+ */
+class DUM : public Stage
+{
+ public:
+ /**
+ * Constructor.
+ * @param The next stage in the pipeline.
+ * @return A newly allocated DUM object.
+ */
+ DUM(Stage *next);
+
+ InstrDTO *advance(Response p) override;
+
+ void set_curr_instr(InstrDTO *);
+
+ private:
+ void advance_helper() override;
+};
+
+#endif /* DUM_H_INCLUDED */
diff --git a/inc/ex.h b/inc/ex.h
index 19c3ac9..cc8062b 100644
--- a/inc/ex.h
+++ b/inc/ex.h
@@ -14,10 +14,10 @@ class EX : public Stage
* @return A newly allocated EX object.
*/
EX(Stage *next);
-
- InstrDTO *advance(Response p) override;
+ using Stage::advance;
private:
+ void advance_helper();
/**
* Maps each mnemonic to a function which carries out the instruction's base
* logic.
diff --git a/inc/id.h b/inc/id.h
index c5c1f1d..9911440 100644
--- a/inc/id.h
+++ b/inc/id.h
@@ -14,8 +14,7 @@ class ID : public Stage
* @return A newly allocated ID object.
*/
ID(Stage *next);
-
- InstrDTO *advance(Response p) override;
+ using Stage::advance;
/* The following methods are made public so that they may be tested, and are
* not to be called from outside classes during standard execution.
@@ -56,10 +55,7 @@ class ID : public Stage
void write_guard(signed int &r);
private:
- /**
- * Decodes `curr_instr` and sets status to BLOCKED if a data hazard occurs.
- */
- void advance_helper();
+ void advance_helper() override;
/**
* Helper for `get_instr_fields`
* Attempts to parse and dereference instruction arguments. Uses read and
diff --git a/inc/if.h b/inc/if.h
index d58b06a..63ca90e 100644
--- a/inc/if.h
+++ b/inc/if.h
@@ -18,14 +18,7 @@ class IF : public Stage
InstrDTO *advance(Response p) override;
private:
- /**
- * Performs a fetch only if a current fetch is not pending. Pending means
- * that a fetch has completed successfully, but the caller stage in the
- * pipeline is not ready to receive it. In this case, `curr_instr` is not
- * the nullptr.
- * @return STALLED if we are waiting on the storage devices, OK otherwise.
- */
- void advance_helper();
+ void advance_helper() override;
};
#endif /* IF_H_INCLUDED */
diff --git a/inc/mm.h b/inc/mm.h
index 6081802..cee3f17 100644
--- a/inc/mm.h
+++ b/inc/mm.h
@@ -13,8 +13,10 @@ class MM : public Stage
* @return A newly allocated MM object.
*/
MM(Stage *next);
+ using Stage::advance;
- InstrDTO *advance(Response p) override;
+ private:
+ void advance_helper() override;
};
#endif /* MM_H_INCLUDED */
diff --git a/inc/stage.h b/inc/stage.h
index c0dc6a8..56a3589 100644
--- a/inc/stage.h
+++ b/inc/stage.h
@@ -28,16 +28,26 @@ class Stage
virtual ~Stage();
/**
* Advances this stage by a single clock cycle.
+ * A boilerplate version is provided in stage.cc.
+ *
* @param a DTO object containing the next instruction to be processed.
* @param a response, indicating whether or not the parent pipe stage is
* ready to accept a new instruction object next cycle.
* @return a response, indicating whether this pipeline stage is stalling,
* busy, or done.
+ *
+ * Must set the status to STALLED when an operation completes.
*/
- virtual InstrDTO *advance(Response p) = 0;
+ virtual InstrDTO *advance(Response p);
protected:
/**
+ * The function expected to do the majority of the work.
+ *
+ * Must set the status to OK when an operation is ready.
+ */
+ virtual void advance_helper() = 0;
+ /**
* Sets the bit in the condition code register corresponding to `c`.
* @param the condition code to set.
* @param the truthy value to set it to.
diff --git a/inc/wb.h b/inc/wb.h
index 7c796ab..62cef17 100644
--- a/inc/wb.h
+++ b/inc/wb.h
@@ -13,8 +13,10 @@ class WB : public Stage
* @return A newly allocated WB object.
*/
WB(Stage *next);
-
- InstrDTO *advance(Response p) override;
+ using Stage::advance;
+
+ private:
+ void advance_helper() override;
};
#endif /* WB_H_INCLUDED */
diff --git a/src/logger/logger.cc b/src/logger/logger.cc
index 6dfaef1..b07e66f 100644
--- a/src/logger/logger.cc
+++ b/src/logger/logger.cc
@@ -8,11 +8,11 @@ using namespace std;
LogLevel Logger::level = INFO;
Logger *Logger::logger_instance;
-void Logger::setLevel(LogLevel level) { level = level; }
+void Logger::setLevel(LogLevel level) { this->level = level; }
void Logger::log(LogLevel level, const string &message)
{
- if (level_to_int(level) > level_to_int(level)) {
+ if (level_to_int(level) > level_to_int(this->level)) {
return;
}
@@ -65,9 +65,7 @@ int Logger::level_to_int(LogLevel level)
return 3;
case ERROR:
return 2;
- case CRITICAL:
- return 1;
default:
- return 0;
+ return 1;
}
}
diff --git a/src/sim/controller.cc b/src/sim/controller.cc
index 622f1dc..06591af 100644
--- a/src/sim/controller.cc
+++ b/src/sim/controller.cc
@@ -36,3 +36,5 @@ InstrDTO *Controller::advance(Response p)
++this->clock_cycle;
return r;
}
+
+void Controller::advance_helper() {}
diff --git a/src/sim/dum.cc b/src/sim/dum.cc
new file mode 100644
index 0000000..f14c89a
--- /dev/null
+++ b/src/sim/dum.cc
@@ -0,0 +1,41 @@
+#include "dum.h"
+#include "accessor.h"
+#include "instrDTO.h"
+#include "response.h"
+#include "stage.h"
+#include "utils.h"
+
+static Logger *global_log = Logger::getInstance();
+
+DUM::DUM(Stage *stage) : Stage(stage) { this->id = IDLE; }
+
+InstrDTO *DUM::advance(Response p)
+{
+ InstrDTO *r = curr_instr;
+
+ this->advance_helper();
+ if (this->status == OK && p == OK) {
+ this->curr_instr->set_time_of(this->id, this->clock_cycle);
+ r = new InstrDTO(*this->curr_instr);
+ delete curr_instr;
+ curr_instr = nullptr;
+ }
+
+ return r;
+}
+
+void DUM::advance_helper()
+{
+ if (this->curr_instr)
+ global_log->log(
+ DEBUG, string_format(
+ "Using bits: %i ", this->curr_instr->get_instr_bits()));
+ else
+ global_log->log(DEBUG, "curr_instr is null");
+}
+
+void DUM::set_curr_instr(InstrDTO *d)
+{
+ this->curr_instr = d;
+ this->status = OK;
+}
diff --git a/src/sim/ex.cc b/src/sim/ex.cc
index 292337b..50882d2 100644
--- a/src/sim/ex.cc
+++ b/src/sim/ex.cc
@@ -199,4 +199,4 @@ EX::EX(Stage *stage) : Stage(stage)
};
}
-InstrDTO *EX::advance(Response p) { return nullptr; }
+void EX::advance_helper() {}
diff --git a/src/sim/id.cc b/src/sim/id.cc
index 969cb9d..36addbb 100644
--- a/src/sim/id.cc
+++ b/src/sim/id.cc
@@ -8,26 +8,6 @@
ID::ID(Stage *stage) : Stage(stage) { this->id = DCDE; }
-InstrDTO *ID::advance(Response p)
-{
- InstrDTO *r = nullptr;
- Response n;
-
- this->advance_helper();
- if (this->status == OK && p == OK) {
- // mutual consent
- this->curr_instr->set_time_of(this->id, this->clock_cycle);
- r = new InstrDTO(*this->curr_instr);
- delete curr_instr;
- curr_instr = nullptr;
- }
-
- n = (p != OK || this->status != OK) ? BLOCKED : OK;
- // the power of consent
- this->curr_instr = this->next->advance(n);
- return r;
-}
-
void ID::get_instr_fields(
signed int &s1, signed int &s2, signed int &s3, Mnemonic &m)
{
@@ -67,7 +47,7 @@ Response ID::read_guard(signed int &v)
{
Response r;
if (this->is_checked_out(v))
- r = BLOCKED;
+ r = STALLED;
else {
r = OK;
v = this->dereference_register(v);
@@ -116,8 +96,9 @@ void ID::decode_R_type(signed int &s1, signed int &s2, signed int &s3)
r2 = this->read_guard(s2);
this->write_guard(s3);
- this->status = (r1 == BLOCKED || r2 == BLOCKED) ? BLOCKED : OK;
+ this->status = (r1 == OK && r2 == OK) ? OK : STALLED;
}
+
void ID::decode_I_type(signed int &s1, signed int &s2, signed int &s3)
{
unsigned int s0b, s1b, s2b;
diff --git a/src/sim/if.cc b/src/sim/if.cc
index 43132ed..77a2704 100644
--- a/src/sim/if.cc
+++ b/src/sim/if.cc
@@ -18,6 +18,7 @@ InstrDTO *IF::advance(Response p)
r = new InstrDTO(*this->curr_instr);
delete curr_instr;
curr_instr = nullptr;
+ this->status = STALLED;
}
return r;
@@ -34,7 +35,6 @@ void IF::advance_helper()
this->status = r;
this->curr_instr = new InstrDTO();
this->curr_instr->set_instr_bits(bits);
- } else
- this->status = STALLED;
+ }
}
}
diff --git a/src/sim/mm.cc b/src/sim/mm.cc
index 5bc5836..2b73207 100644
--- a/src/sim/mm.cc
+++ b/src/sim/mm.cc
@@ -6,7 +6,4 @@
MM::MM(Stage *stage) : Stage(stage) { this->id = MEM; }
-InstrDTO *MM::advance(Response p)
-{
- return nullptr;
-}
+void MM::advance_helper() {}
diff --git a/src/sim/stage.cc b/src/sim/stage.cc
index d8c882a..929a4b9 100644
--- a/src/sim/stage.cc
+++ b/src/sim/stage.cc
@@ -7,7 +7,7 @@ Stage::Stage(Stage *next)
{
this->next = next;
this->curr_instr = nullptr;
- this->status = OK;
+ this->status = STALLED;
this->checked_out = {};
}
@@ -21,6 +21,27 @@ Storage *Stage::storage;
bool Stage::is_pipelined;
int Stage::clock_cycle;
+InstrDTO *Stage::advance(Response p)
+{
+ InstrDTO *r = nullptr;
+ Response n;
+
+ this->advance_helper();
+ if (this->status == OK && p == OK) {
+ // mutual consent
+ this->curr_instr->set_time_of(this->id, this->clock_cycle);
+ r = new InstrDTO(*this->curr_instr);
+ delete curr_instr;
+ curr_instr = nullptr;
+ this->status = STALLED;
+ }
+
+ n = (p != OK || this->status != OK) ? STALLED : OK;
+ // the power of consent
+ this->curr_instr = this->next->advance(n);
+ return r;
+}
+
void Stage::set_condition(CC c, bool v)
{
if (v)
diff --git a/src/sim/wb.cc b/src/sim/wb.cc
index 7a8d64c..9337aa0 100644
--- a/src/sim/wb.cc
+++ b/src/sim/wb.cc
@@ -6,4 +6,4 @@
WB::WB(Stage *stage) : Stage(stage) { this->id = WRITE; }
-InstrDTO *WB::advance(Response p) { return nullptr; }
+void WB::advance_helper() {}
diff --git a/tests/id.cc b/tests/id.cc
index 65cc16a..6d6a155 100644
--- a/tests/id.cc
+++ b/tests/id.cc
@@ -2,7 +2,7 @@
#include "cache.h"
#include "controller.h"
#include "dram.h"
-#include "if.h"
+#include "dum.h"
#include "instr.h"
#include "instrDTO.h"
#include <catch2/catch_test_macros.hpp>
@@ -14,8 +14,8 @@ class IDFixture
{
this->dr = new Dram(3);
this->c = new Cache(this->dr, 1);
- IF *f = new IF(nullptr);
- this->d = new ID(f);
+ this->dum = new DUM(nullptr);
+ this->d = new ID(dum);
this->ct = new Controller(this->d, this->c, true);
};
~IDFixture()
@@ -23,6 +23,12 @@ class IDFixture
delete this->ct;
delete this->c;
};
+ void prime_bits(signed int raw)
+ {
+ InstrDTO *i = new InstrDTO();
+ i->set_instr_bits(raw);
+ this->dum->set_curr_instr(i);
+ }
signed int encode_R_type(
signed int s3,
signed int s2,
@@ -63,10 +69,11 @@ class IDFixture
t = (t << TYPE_SIZE) + type;
return t;
}
-
+
Dram *dr;
Cache *c;
ID *d;
+ DUM *dum;
Controller *ct;
};
@@ -82,88 +89,116 @@ TEST_CASE_METHOD(IDFixture, "Parse invalid type", "[id]")
TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # one", "[id]")
{
- signed int s1 = -1, s2 = -1, s3 = -1;
- Mnemonic m;
+ signed int t;
+ InstrDTO *i;
- s1 = this->encode_R_type(0b0, 0b1, 0b10, 0b11, 0b0);
- this->d->get_instr_fields(s1, s2, s3, m);
+ t = this->encode_R_type(0b0, 0b1, 0b10, 0b11, 0b0);
+ this->prime_bits(t);
- CHECK(s1 == 0x00000000); // registers are empty
- CHECK(s2 == 0x00000000);
- CHECK(s3 == 0x00000000);
- CHECK(m == MUL);
+ i = this->ct->advance(OK);
+ REQUIRE(i == nullptr);
+ i = this->ct->advance(OK);
+ REQUIRE(i != nullptr);
+
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x00000000);
+ CHECK(i->get_s3() == 0x00000000);
+ CHECK(i->get_mnemonic() == MUL);
+
+ delete i;
}
TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # two", "[id]")
{
- signed int s1 = -1, s2 = -1, s3 = -1;
- Mnemonic m;
+ signed int t;
+ InstrDTO *i;
- s1 = this->encode_R_type(0b10000, 0b01000, 0b00100, 0b10, 0b0);
- this->d->get_instr_fields(s1, s2, s3, m);
+ t = this->encode_R_type(0b10000, 0b01000, 0b00100, 0b10, 0b0);
+ this->prime_bits(t);
+
+ i = this->ct->advance(OK);
+ REQUIRE(i == nullptr);
+ i = this->ct->advance(OK);
+ REQUIRE(i != nullptr);
- CHECK(s1 == 0x00000000); // registers are empty
- CHECK(s2 == 0b00000000);
- CHECK(s3 == 0b00000000);
- CHECK(m == SUB);
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x00000000);
+ CHECK(i->get_s3() == 0x00000000);
+ CHECK(i->get_mnemonic() == SUB);
}
TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # one", "[id]")
{
- signed int s1 = -1, s2 = -1, s3 = -1;
- Mnemonic m;
+ signed int t;
+ InstrDTO *i;
- s1 = this->encode_I_type(0xF, 0b1, 0b10, 0b0111, 0b1);
- this->d->get_instr_fields(s1, s2, s3, m);
+ t = this->encode_I_type(0xF, 0b1, 0b10, 0b0111, 0b1);
+ this->prime_bits(t);
+
+ i = this->ct->advance(OK);
+ REQUIRE(i == nullptr);
+ i = this->ct->advance(OK);
+ REQUIRE(i != nullptr);
- CHECK(s1 == 0x00000000); // registers are empty
- CHECK(s2 == 0x00000000);
- CHECK(s3 == 0xF);
- CHECK(m == SFTLI);
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x00000000);
+ CHECK(i->get_s3() == 0xF);
+ CHECK(i->get_mnemonic() == SFTLI);
}
TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # two", "[id]")
{
- signed int s1 = -1, s2 = -1, s3 = -1;
- Mnemonic m;
+ signed int t;
+ InstrDTO *i;
- s1 = this->encode_I_type(0xCC, 0b010, 0b101, 0b1011, 0b1);
- this->d->get_instr_fields(s1, s2, s3, m);
+ t = this->encode_I_type(0xCC, 0b010, 0b101, 0b1011, 0b1);
+ this->prime_bits(t);
- CHECK(s1 == 0x00000000); // registers are empty
- CHECK(s2 == 0x00000000);
- CHECK(s3 == 0xCC);
- CHECK(m == STORE);
+ i = this->ct->advance(OK);
+ REQUIRE(i == nullptr);
+ i = this->ct->advance(OK);
+ REQUIRE(i != nullptr);
+
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x00000000);
+ CHECK(i->get_s3() == 0xCC);
+ CHECK(i->get_mnemonic() == STORE);
}
TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # one", "[id]")
{
- signed int s1 = -1, s2 = -1, s3 = -1;
- Mnemonic m;
+ signed int t;
+ InstrDTO *i;
- s1 = this->encode_J_type(0x3456, 0b10101, 0b0111, 0b10);
- this->d->get_instr_fields(s1, s2, s3, m);
+ t = this->encode_J_type(0x3456, 0b10101, 0b0111, 0b10);
+ this->prime_bits(t);
+
+ i = this->ct->advance(OK);
+ REQUIRE(i == nullptr);
+ i = this->ct->advance(OK);
+ REQUIRE(i != nullptr);
- CHECK(s1 == 0x00000000); // registers are empty
- CHECK(s2 == 0x3456);
- CHECK(m == BOF);
- // behavior does nothing
- CHECK(s3 == -1);
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x3456);
+ CHECK(i->get_mnemonic() == BOF);
}
TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # two", "[id]")
{
- signed int s1 = -1, s2 = -1, s3 = -1;
- Mnemonic m;
+ signed int t;
+ InstrDTO *i;
- s1 = this->encode_J_type(0xBBCCF, 0b10101, 0b0011, 0b10);
- this->d->get_instr_fields(s1, s2, s3, m);
+ t = this->encode_J_type(0xBBCCF, 0b10101, 0b0011, 0b10);
+ this->prime_bits(t);
+
+ i = this->ct->advance(OK);
+ REQUIRE(i == nullptr);
+ i = this->ct->advance(OK);
+ REQUIRE(i != nullptr);
- CHECK(s1 == 0x00000000); // registers are empty
- CHECK(s2 == 0xBBCCF);
- CHECK(m == JAL);
- // behavior does nothing
- CHECK(s3 == -1);
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0xBBCCF);
+ CHECK(i->get_mnemonic() == JAL);
}
TEST_CASE_METHOD(IDFixture, "read does not conflict with read", "[id]")
@@ -221,7 +256,7 @@ TEST_CASE_METHOD(IDFixture, "read does conflict with write", "[id]")
v = 0b1;
r = this->d->read_guard(v);
CHECK(v == 0b01);
- REQUIRE(r == BLOCKED);
+ REQUIRE(r == STALLED);
}
TEST_CASE_METHOD(IDFixture, "stores indefinite conflicts", "[id]")
@@ -242,10 +277,10 @@ TEST_CASE_METHOD(IDFixture, "stores indefinite conflicts", "[id]")
v = 0b110;
r = this->d->read_guard(v);
CHECK(v == 0b110);
- REQUIRE(r == BLOCKED);
+ REQUIRE(r == STALLED);
v = 0b0;
r = this->d->read_guard(v);
CHECK(v == 0b0);
- REQUIRE(r == BLOCKED);
+ REQUIRE(r == STALLED);
}
diff --git a/tests/if.cc b/tests/if.cc
index 185a52a..1f02cb0 100644
--- a/tests/if.cc
+++ b/tests/if.cc
@@ -113,17 +113,17 @@ TEST_CASE_METHOD(IFPipeFixture, "fetch waits with old instruction",
expected_cycles = this->m_delay + (this->c_delay * 2) + 1;
for (j = 0; j < this->m_delay + 1; ++j) {
- i = this->ct->advance(BLOCKED);
+ i = this->ct->advance(STALLED);
// check response
CHECK(i == nullptr);
}
for (j = 0; j < this->c_delay; ++j) {
- i = this->ct->advance(BLOCKED);
+ i = this->ct->advance(STALLED);
// check response
CHECK(i == nullptr);
}
for (j = 0; j < expected_cycles - fetch_cycles; ++j) {
- i = this->ct->advance(BLOCKED);
+ i = this->ct->advance(STALLED);
// check response
CHECK(i != nullptr);
}