summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-04-01 15:57:14 -0400
committerbd <bdunahu@operationnull.com>2025-04-01 15:57:14 -0400
commit25ce77db5f0dbfe6064eb0553591f1b956bad24a (patch)
tree5a1c347f05f14496d2d3a2f1befd88be9020cad3
parent6579f7272905d1e25b43ef051da6c2180e60ca2b (diff)
Fix a lot of pipeline bugs
-rw-r--r--inc/stage.h6
-rw-r--r--inc/wb.h20
-rw-r--r--src/sim/ex.cc14
-rw-r--r--src/sim/id.cc20
-rw-r--r--src/sim/instrDTO.cc2
-rw-r--r--src/sim/mm.cc1
-rw-r--r--src/sim/stage.cc25
-rw-r--r--src/sim/wb.cc75
-rw-r--r--tests/controller.cc111
-rw-r--r--tests/id.cc320
10 files changed, 371 insertions, 223 deletions
diff --git a/inc/stage.h b/inc/stage.h
index 2f9812f..87ee9c1 100644
--- a/inc/stage.h
+++ b/inc/stage.h
@@ -81,6 +81,12 @@ class Stage
*/
bool is_checked_out(signed int r);
/**
+ * Stores `d` into the register indexed `v`.
+ * @param the register number.
+ * @param the value to store.
+ */
+ void store_register(signed int v, signed int d);
+ /**
* Returns the value of the register corresponding to `v`.
* @param the register number.
* @return the value in the associated register.
diff --git a/inc/wb.h b/inc/wb.h
index 62cef17..c4755ea 100644
--- a/inc/wb.h
+++ b/inc/wb.h
@@ -14,9 +14,27 @@ class WB : public Stage
*/
WB(Stage *next);
using Stage::advance;
-
+
private:
void advance_helper() override;
+ /**
+ * Performs the actual work of storing into a register.
+ */
+ void write_handler();
+ /**
+ * Performs the actual work of processing a jump instruction.
+ */
+ void jump_handler();
+ /**
+ * @return true if the current instruction is an R or I type and is not a
+ * STORE.
+ */
+ bool should_write();
+ /**
+ * @return true if the current instruction is a J type and is not a push.
+ * STORE.
+ */
+ bool should_jump();
};
#endif /* WB_H_INCLUDED */
diff --git a/src/sim/ex.cc b/src/sim/ex.cc
index 3d95917..ec4c47f 100644
--- a/src/sim/ex.cc
+++ b/src/sim/ex.cc
@@ -4,6 +4,7 @@
#include "instrDTO.h"
#include "response.h"
#include "stage.h"
+#include "utils.h"
#include <unordered_map>
// clang-format off
@@ -185,6 +186,7 @@ EX::EX(Stage *stage) : Stage(stage)
ADDI,
{
s1 = s1 + s3;
+ std::cout << "= " << s2 << std::endl;
(void)s2;
(void)this;
}),
@@ -282,28 +284,32 @@ EX::EX(Stage *stage) : Stage(stage)
INIT_INSTRUCTION(
BEQ,
{
- (this->get_condition(EQ)) ? s1 = this->pc + s2 : s1 = this->pc;
+ (this->get_condition(EQ)) ? s1 = wrap_address(this->pc + s2)
+ : s1 = -1;
(void)s3;
}),
INIT_INSTRUCTION(
BGT,
{
- (this->get_condition(GT)) ? s1 = this->pc + s2 : s1 = this->pc;
+ (this->get_condition(GT)) ? s1 = wrap_address(this->pc + s2)
+ : s1 = -1;
(void)s3;
}),
INIT_INSTRUCTION(
BUF,
{
- (this->get_condition(UF)) ? s1 = this->pc + s2 : s1 = this->pc;
+ (this->get_condition(UF)) ? s1 = wrap_address(this->pc) + s2
+ : s1 = -1;
(void)s3;
}),
INIT_INSTRUCTION(
BOF,
{
- (this->get_condition(OF)) ? s1 = this->pc + s2 : s1 = this->pc;
+ (this->get_condition(OF)) ? s1 = wrap_address(this->pc + s2)
+ : s1 = -1;
(void)s3;
}),
diff --git a/src/sim/id.cc b/src/sim/id.cc
index 4a55d04..ddac35b 100644
--- a/src/sim/id.cc
+++ b/src/sim/id.cc
@@ -48,14 +48,18 @@ void ID::advance_helper()
Mnemonic m;
Type t;
- s1 = curr_instr->get_instr_bits();
- get_instr_fields(s1, s2, s3, m, t);
- if (this->status == OK) {
- curr_instr->set_s1(s1);
- curr_instr->set_s2(s2);
- curr_instr->set_s3(s3);
- curr_instr->set_mnemonic(m);
- curr_instr->set_type(t);
+ if (curr_instr->get_mnemonic() == NOP)
+ this->status = OK;
+ else {
+ s1 = curr_instr->get_instr_bits();
+ get_instr_fields(s1, s2, s3, m, t);
+ if (this->status == OK) {
+ curr_instr->set_s1(s1);
+ curr_instr->set_s2(s2);
+ curr_instr->set_s3(s3);
+ curr_instr->set_mnemonic(m);
+ curr_instr->set_type(t);
+ }
}
}
diff --git a/src/sim/instrDTO.cc b/src/sim/instrDTO.cc
index 28364b7..7324ba9 100644
--- a/src/sim/instrDTO.cc
+++ b/src/sim/instrDTO.cc
@@ -7,7 +7,7 @@ InstrDTO::InstrDTO()
this->s1 = 0;
this->s2 = 0;
this->s3 = 0;
- this->mnemonic = NOP;
+ this->mnemonic = ADD;
this->type = INV;
}
diff --git a/src/sim/mm.cc b/src/sim/mm.cc
index c83ae7d..e29bf90 100644
--- a/src/sim/mm.cc
+++ b/src/sim/mm.cc
@@ -10,6 +10,7 @@ void MM::advance_helper()
{
signed int data;
+ std::cout << "mem" << this->curr_instr->get_s2() << std::endl;
switch (this->curr_instr->get_mnemonic()) {
case LOAD:
this->status = this->storage->read_word(
diff --git a/src/sim/stage.cc b/src/sim/stage.cc
index 31d7d0d..b10a206 100644
--- a/src/sim/stage.cc
+++ b/src/sim/stage.cc
@@ -2,7 +2,6 @@
#include "utils.h"
#include <array>
#include <deque>
-#include <iostream>
Stage::Stage(Stage *next)
{
@@ -28,10 +27,12 @@ void Stage::set_pc(unsigned int pc) { this->pc = pc; }
InstrDTO *Stage::advance(Response p)
{
InstrDTO *r = nullptr;
+ InstrDTO *s = nullptr;
Response n;
- if (this->curr_instr && this->status != OK)
+ if (this->curr_instr && this->status != OK) {
this->advance_helper();
+ }
if (this->status == OK && p == WAIT && this->curr_instr) {
// mutual consent
this->curr_instr->set_time_of(this->id, this->clock_cycle);
@@ -42,8 +43,9 @@ InstrDTO *Stage::advance(Response p)
}
n = (p != WAIT || this->status != WAIT) ? STALLED : WAIT;
- // the power of consent
- this->curr_instr = this->next->advance(n);
+ s = this->next->advance(n);
+ if (s)
+ this->curr_instr = s;
return r;
}
@@ -70,6 +72,21 @@ signed int Stage::dereference_register(signed int v)
return r;
}
+void Stage::store_register(signed int v, signed int d)
+{
+ if (v < 0 || v >= GPR_NUM + V_NUM) {
+ throw std::out_of_range(string_format(
+ "instruction tried to access register %d, which does "
+ "not exist",
+ v));
+ }
+
+ if (v >= GPR_NUM)
+ this->vrs[v % GPR_NUM] = d;
+ else
+ this->gprs[v] = d;
+}
+
bool Stage::is_checked_out(signed int r)
{
return std::find(this->checked_out.begin(), this->checked_out.end(), r) !=
diff --git a/src/sim/wb.cc b/src/sim/wb.cc
index 276d1d0..01768e8 100644
--- a/src/sim/wb.cc
+++ b/src/sim/wb.cc
@@ -8,33 +8,54 @@ WB::WB(Stage *stage) : Stage(stage) { this->id = WRITE; }
void WB::advance_helper()
{
- if (this->curr_instr->get_type() == R ||
- this->curr_instr->get_type() == I) {
- if (this->checked_out.size() > 0) {
- signed int reg = this->checked_out.front();
- this->checked_out.pop_front();
- if (reg >= GPR_NUM) {
- // TODO: handle vector instructions
- } else {
- if (this->curr_instr->get_mnemonic() != STORE &&
- this->curr_instr->get_mnemonic() != STOREV) {
- this->gprs[reg] = this->curr_instr->get_s1();
- }
- }
- }
- } else if (this->curr_instr->get_type() == J) {
- // TODO:handle push pop
- // branch taken
- if (this->pc != this->curr_instr->get_s1()) {
- if (this->curr_instr->get_mnemonic() == JAL) {
- // set link register to next instruction
- this->gprs[1] = this->pc + 1;
- }
- this->pc = this->curr_instr->get_s1();
- // clear pending registers and squash pipeline
- this->checked_out = {};
- this->next->squash();
- }
+ if (this->curr_instr->get_mnemonic() != NOP &&
+ this->curr_instr->get_type() != INV) {
+ if (this->should_write())
+ this->write_handler();
+ else if (this->should_jump())
+ this->jump_handler();
}
this->status = OK;
}
+
+void WB::write_handler()
+{
+ signed int reg;
+
+ if (this->checked_out.size() < 1)
+ throw std::runtime_error("instruction tried to pop a register out of "
+ "an empty queue during writeback.");
+
+ reg = this->checked_out.front();
+ this->checked_out.pop_front();
+ this->store_register(reg, this->curr_instr->get_s1());
+}
+
+void WB::jump_handler()
+{
+ if (this->curr_instr->get_s1() > 0) {
+ if (this->curr_instr->get_mnemonic() == JAL)
+ this->gprs[1] = this->pc + 1;
+ this->pc = this->curr_instr->get_s1();
+ this->checked_out = {};
+ this->next->squash();
+ }
+}
+
+bool WB::should_jump()
+{
+ Type t;
+
+ t = this->curr_instr->get_type();
+ return t == J;
+}
+
+bool WB::should_write()
+{
+ Mnemonic m;
+ Type t;
+
+ m = this->curr_instr->get_mnemonic();
+ t = this->curr_instr->get_type();
+ return (t == R || t == I) && (m != STORE && m != STOREV);
+}
diff --git a/tests/controller.cc b/tests/controller.cc
index f6d9b25..f2ef3de 100644
--- a/tests/controller.cc
+++ b/tests/controller.cc
@@ -21,15 +21,27 @@ class ControllerPipeFixture
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->stage_num = 5;
- this->ct = new Controller(e, this->c, true);
+ this->ct = new Controller(w, this->c, true);
}
~ControllerPipeFixture()
{
delete this->ct;
delete this->c;
};
-
+ void fill_pipe()
+ {
+ InstrDTO *i = nullptr;
+ int j;
+ for (j = 0; j < this->stage_num + 1; ++j) {
+ i = this->ct->advance(WAIT);
+ REQUIRE(i == nullptr);
+ }
+ }
+ int stage_num;
Cache *c;
Dram *d;
Controller *ct;
@@ -51,40 +63,103 @@ TEST_CASE_METHOD(
CHECK(this->ct->get_pc() == 0);
}
-TEST_CASE_METHOD(ControllerPipeFixture, "Add until exec", "[tmp]")
+TEST_CASE_METHOD(ControllerPipeFixture, "two num adder", "[full pipe]")
{
- signed int b;
+ signed int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11;
std::vector<signed int> p;
InstrDTO *i;
- b = 0b1010100000000001001101;
- p = {b};
+ // I-TYPE / / / /
+ b0 = 0b00000010000000000001000000001101; // ADDI $sp $0 0x200;
+ b1 = 0b00000000000000010010100000001101; // ADDI $5 $0 0x1;
+ b2 = 0b00000000000000000001000101101101; // STORE $5 0($sp); (RAW HAZARD)!
+ // I-TYPE / / / /
+ b3 = 0b00000000000000100010100000001101; // ADDI $5 $0 0x2; (RAW HAZARD)!
+ b4 = 0b00000000000000010001000101101101; // STORE $5 1($sp); (RAW HAZARD)!
+ // // I-TYPE / / / /
+ // b9 = 0b00000000000000000010100000001101; // ADDI $5 $0 0x0;
+ // // I-TYPE / / / /
+ // b10 = 0b00000000000000110011000000001101; // ADDI $6 $0 0x3;
+ // // J-TYPE / / /
+ // b11 = 0b00000000000000000011100000001010; // jrl CHECK
+
+ p = {b0, b1, b2, b3};
this->d->load(p);
- // dram
+ this->fill_pipe();
+ i = this->ct->advance(WAIT);
+ REQUIRE(i != nullptr);
+
+ CHECK(i->get_time_of(FETCH) == 3);
+ CHECK(i->get_time_of(DCDE) == 4);
+ CHECK(i->get_time_of(EXEC) == 5);
+ CHECK(i->get_time_of(MEM) == 6);
+ CHECK(i->get_time_of(WRITE) == 7);
+ CHECK(i->get_s1() == 0x200);
+ CHECK(i->get_s2() == 0x0);
+ CHECK(i->get_s3() == 0x200);
+ CHECK(this->ct->get_gprs().at(2) == 0x200);
+ CHECK(i->get_mnemonic() == ADDI);
+ CHECK(i->get_instr_bits() == b0);
+
+ delete i;
+ i = this->ct->advance(WAIT);
+ REQUIRE(i != nullptr);
+
+ CHECK(i->get_time_of(FETCH) == 4);
+ CHECK(i->get_time_of(DCDE) == 5);
+ CHECK(i->get_time_of(EXEC) == 6);
+ CHECK(i->get_time_of(MEM) == 7);
+ CHECK(i->get_time_of(WRITE) == 8);
+ CHECK(i->get_s1() == 0x1);
+ CHECK(i->get_s2() == 0x0);
+ CHECK(i->get_s3() == 0x1);
+ CHECK(this->ct->get_gprs().at(5) == 0x1);
+ CHECK(i->get_mnemonic() == ADDI);
+ CHECK(i->get_instr_bits() == b1);
+
+ delete i;
i = this->ct->advance(WAIT);
REQUIRE(i == nullptr);
- // fetch
i = this->ct->advance(WAIT);
REQUIRE(i == nullptr);
- // decode
i = this->ct->advance(WAIT);
REQUIRE(i == nullptr);
- // exec
i = this->ct->advance(WAIT);
REQUIRE(i == nullptr);
- // done
i = this->ct->advance(WAIT);
REQUIRE(i != nullptr);
- CHECK(i->get_time_of(FETCH) == 3);
- CHECK(i->get_time_of(DCDE) == 4);
- CHECK(i->get_time_of(EXEC) == 5);
- CHECK(i->get_s1() == 42);
- CHECK(i->get_s2() == 0);
- CHECK(i->get_s3() == 42);
+ CHECK(i->get_time_of(FETCH) == 5);
+ CHECK(i->get_time_of(DCDE) == 8); // the previous conflicting instruction wrote here!
+ CHECK(i->get_time_of(EXEC) == 9);
+ CHECK(i->get_time_of(MEM) == 12); // waited for fetch + 2 dram
+ CHECK(i->get_time_of(WRITE) == 13);
+ CHECK(i->get_s1() == 0x1);
+ CHECK(i->get_s2() == 0x200);
+ CHECK(i->get_s3() == 0x0);
+ // NO STORE
+ CHECK(this->ct->get_gprs().at(2) == 0x200);
+ CHECK(this->ct->get_gprs().at(5) == 0x1);
+ CHECK(i->get_mnemonic() == STORE);
+ CHECK(i->get_instr_bits() == b2);
+
+ delete i;
+ i = this->ct->advance(WAIT);
+ REQUIRE(i != nullptr);
+
+ CHECK(i->get_time_of(FETCH) == 8);
+ CHECK(i->get_time_of(DCDE) == 9);
+ CHECK(i->get_time_of(EXEC) == 12);
+ CHECK(i->get_time_of(MEM) == 13);
+ CHECK(i->get_time_of(WRITE) == 14);
+ CHECK(i->get_s1() == 0x2);
+ CHECK(i->get_s2() == 0x0);
+ CHECK(i->get_s3() == 0x2);
+ // NO STORE
+ CHECK(this->ct->get_gprs().at(5) == 0x2);
CHECK(i->get_mnemonic() == ADDI);
- CHECK(i->get_instr_bits() == b);
+ CHECK(i->get_instr_bits() == b3);
delete i;
}
diff --git a/tests/id.cc b/tests/id.cc
index 7d5e05d..77a7cd9 100644
--- a/tests/id.cc
+++ b/tests/id.cc
@@ -84,18 +84,18 @@ class IDFixture
Controller *ct;
};
-// TEST_CASE_METHOD(IDFixture, "Parse invalid type", "[id]")
-// {
-// signed int t;
-// InstrDTO *i;
+TEST_CASE_METHOD(IDFixture, "Parse invalid type", "[id]")
+{
+ signed int t;
+ InstrDTO *i;
-// t = this->encode_R_type(0b0, 0b1, 0b10, 0b11, 0b11);
-// i = this->decode_bits(t);
+ t = this->encode_R_type(0b0, 0b1, 0b10, 0b11, 0b11);
+ i = this->decode_bits(t);
-// CHECK(i->get_mnemonic() == NOP);
+ CHECK(i->get_mnemonic() == NOP);
-// delete i;
-// }
+ delete i;
+}
TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # one", "[id]")
{
@@ -113,164 +113,164 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # one", "[id]")
delete i;
}
-// TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # two", "[id]")
-// {
-// signed int t;
-// InstrDTO *i;
+TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # two", "[id]")
+{
+ signed int t;
+ InstrDTO *i;
-// t = this->encode_R_type(0b10000, 0b01000, 0b00100, 0b10, 0b0);
-// i = this->decode_bits(t);
+ t = this->encode_R_type(0b10000, 0b01000, 0b00100, 0b10, 0b0);
+ i = this->decode_bits(t);
-// CHECK(i->get_s1() == 0x00000000); // registers are empty
-// CHECK(i->get_s2() == 0x00000000);
-// CHECK(i->get_s3() == 0x00000000);
-// CHECK(i->get_mnemonic() == SUB);
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x00000000);
+ CHECK(i->get_s3() == 0x00000000);
+ CHECK(i->get_mnemonic() == SUB);
-// delete i;
-// }
+ delete i;
+}
-// TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # one", "[id]")
-// {
-// signed int t;
-// InstrDTO *i;
+TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # one", "[id]")
+{
+ signed int t;
+ InstrDTO *i;
-// t = this->encode_I_type(0xF, 0b1, 0b10, 0b0111, 0b1);
-// i = this->decode_bits(t);
+ t = this->encode_I_type(0xF, 0b1, 0b10, 0b0111, 0b1);
+ i = this->decode_bits(t);
-// CHECK(i->get_s1() == 0x00000000); // registers are empty
-// CHECK(i->get_s2() == 0x00000000);
-// CHECK(i->get_s3() == 0xF);
-// CHECK(i->get_mnemonic() == SFTLI);
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x00000000);
+ CHECK(i->get_s3() == 0xF);
+ CHECK(i->get_mnemonic() == SFTLI);
-// delete i;
-// }
+ delete i;
+}
-// TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # two", "[id]")
-// {
-// signed int t;
-// InstrDTO *i;
+TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # two", "[id]")
+{
+ signed int t;
+ InstrDTO *i;
-// t = this->encode_I_type(0xCC, 0b010, 0b101, 0b1011, 0b1);
-// i = this->decode_bits(t);
+ t = this->encode_I_type(0xCC, 0b010, 0b101, 0b1011, 0b1);
+ i = this->decode_bits(t);
-// CHECK(i->get_s1() == 0x00000000); // registers are empty
-// CHECK(i->get_s2() == 0x00000000);
-// CHECK(i->get_s3() == 0xCC);
-// CHECK(i->get_mnemonic() == STORE);
-
-// delete i;
-// }
-
-// TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # one", "[id]")
-// {
-// signed int t;
-// InstrDTO *i;
-
-// t = this->encode_J_type(0x3456, 0b10101, 0b0111, 0b10);
-// i = this->decode_bits(t);
-
-// CHECK(i->get_s1() == 0x00000000); // registers are empty
-// CHECK(i->get_s2() == 0x3456);
-// CHECK(i->get_mnemonic() == BOF);
-
-// delete i;
-// }
-
-// TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # two", "[id]")
-// {
-// signed int t;
-// InstrDTO *i;
-
-// t = this->encode_J_type(0xBBCCF, 0b10101, 0b0011, 0b10);
-// i = this->decode_bits(t);
-
-// CHECK(i->get_s1() == 0x00000000); // registers are empty
-// CHECK(i->get_s2() == 0xBBCCF);
-// CHECK(i->get_mnemonic() == JAL);
-
-// delete i;
-// }
-
-// TEST_CASE_METHOD(IDFixture, "read does not conflict with read", "[id]")
-// {
-// signed int v;
-// Response r;
-
-// v = 0b1;
-// r = this->d->read_guard(v);
-// CHECK(v == 0b0);
-// REQUIRE(r == OK);
-
-// v = 0b1;
-// this->d->read_guard(v);
-// REQUIRE(v == 0b0);
-// }
-
-// TEST_CASE_METHOD(IDFixture, "write does not conflict with write", "[id]")
-// {
-// signed int v;
-
-// v = 0b1;
-// this->d->write_guard(v);
-// REQUIRE(v == 0b0);
-
-// v = 0b1;
-// this->d->write_guard(v);
-// REQUIRE(v == 0b0);
-// }
-
-// TEST_CASE_METHOD(IDFixture, "write does not conflict with read", "[id]")
-// {
-// signed int v;
-// Response r;
-
-// v = 0b1;
-// r = this->d->read_guard(v);
-// CHECK(v == 0b0);
-// REQUIRE(r == OK);
-
-// v = 0b1;
-// this->d->write_guard(v);
-// REQUIRE(v == 0b0);
-// }
-
-// TEST_CASE_METHOD(IDFixture, "read does conflict with write", "[id]")
-// {
-// signed int v;
-// Response r;
-
-// v = 0b1;
-// this->d->write_guard(v);
-// REQUIRE(v == 0b0);
-
-// v = 0b1;
-// r = this->d->read_guard(v);
-// CHECK(v == 0b01);
-// REQUIRE(r == STALLED);
-// }
-
-// TEST_CASE_METHOD(IDFixture, "stores indefinite conflicts", "[id]")
-// {
-// signed int v, ov;
-// Response r;
-
-// v = 0b0;
-// ov = v;
-// while (v < 0b110) {
-// this->d->write_guard(v);
-// REQUIRE(v == 0b0);
-// v = ++ov;
-// }
-// this->d->write_guard(v);
-// REQUIRE(v == 0b0);
-
-// v = 0b110;
-// r = this->d->read_guard(v);
-// CHECK(v == 0b110);
-// REQUIRE(r == STALLED);
-
-// v = 0b0;
-// r = this->d->read_guard(v);
-// CHECK(v == 0b0);
-// REQUIRE(r == STALLED);
-// }
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x00000000);
+ CHECK(i->get_s3() == 0xCC);
+ CHECK(i->get_mnemonic() == STORE);
+
+ delete i;
+}
+
+TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # one", "[id]")
+{
+ signed int t;
+ InstrDTO *i;
+
+ t = this->encode_J_type(0x3456, 0b10101, 0b0111, 0b10);
+ i = this->decode_bits(t);
+
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0x3456);
+ CHECK(i->get_mnemonic() == BOF);
+
+ delete i;
+}
+
+TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # two", "[id]")
+{
+ signed int t;
+ InstrDTO *i;
+
+ t = this->encode_J_type(0xBBCCF, 0b10101, 0b0011, 0b10);
+ i = this->decode_bits(t);
+
+ CHECK(i->get_s1() == 0x00000000); // registers are empty
+ CHECK(i->get_s2() == 0xBBCCF);
+ CHECK(i->get_mnemonic() == JAL);
+
+ delete i;
+}
+
+TEST_CASE_METHOD(IDFixture, "read does not conflict with read", "[id]")
+{
+ signed int v;
+ Response r;
+
+ v = 0b1;
+ r = this->d->read_guard(v);
+ CHECK(v == 0b0);
+ REQUIRE(r == OK);
+
+ v = 0b1;
+ this->d->read_guard(v);
+ REQUIRE(v == 0b0);
+}
+
+TEST_CASE_METHOD(IDFixture, "write does not conflict with write", "[id]")
+{
+ signed int v;
+
+ v = 0b1;
+ this->d->write_guard(v);
+ REQUIRE(v == 0b0);
+
+ v = 0b1;
+ this->d->write_guard(v);
+ REQUIRE(v == 0b0);
+}
+
+TEST_CASE_METHOD(IDFixture, "write does not conflict with read", "[id]")
+{
+ signed int v;
+ Response r;
+
+ v = 0b1;
+ r = this->d->read_guard(v);
+ CHECK(v == 0b0);
+ REQUIRE(r == OK);
+
+ v = 0b1;
+ this->d->write_guard(v);
+ REQUIRE(v == 0b0);
+}
+
+TEST_CASE_METHOD(IDFixture, "read does conflict with write", "[id]")
+{
+ signed int v;
+ Response r;
+
+ v = 0b1;
+ this->d->write_guard(v);
+ REQUIRE(v == 0b0);
+
+ v = 0b1;
+ r = this->d->read_guard(v);
+ CHECK(v == 0b01);
+ REQUIRE(r == STALLED);
+}
+
+TEST_CASE_METHOD(IDFixture, "stores indefinite conflicts", "[id]")
+{
+ signed int v, ov;
+ Response r;
+
+ v = 0b0;
+ ov = v;
+ while (v < 0b110) {
+ this->d->write_guard(v);
+ REQUIRE(v == 0b0);
+ v = ++ov;
+ }
+ this->d->write_guard(v);
+ REQUIRE(v == 0b0);
+
+ v = 0b110;
+ r = this->d->read_guard(v);
+ CHECK(v == 0b110);
+ REQUIRE(r == STALLED);
+
+ v = 0b0;
+ r = this->d->read_guard(v);
+ CHECK(v == 0b0);
+ REQUIRE(r == STALLED);
+}