summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorbd <bdunahu@operationnull.com>2025-03-21 01:06:38 -0400
committerbd <bdunahu@operationnull.com>2025-03-21 01:06:38 -0400
commit91886988ddfd276cd6e51f05b9e92fd1926b54ec (patch)
tree3bf1411babb1511e6ad10ed7cdeaba576d8c4731 /tests
parentcf3ac49639bef5082489068e2d92a4d86f42080b (diff)
Rewrite current cache.cc tests, add test-helper function to dram
Diffstat (limited to 'tests')
-rw-r--r--tests/cache.cc312
-rw-r--r--tests/dram.cc130
2 files changed, 161 insertions, 281 deletions
diff --git a/tests/cache.cc b/tests/cache.cc
index 1fc5209..c9fbd20 100644
--- a/tests/cache.cc
+++ b/tests/cache.cc
@@ -2,193 +2,121 @@
#include "definitions.h"
#include "dram.h"
#include <catch2/catch_test_macros.hpp>
+#include <functional>
-TEST_CASE("Constructor singleton cache", "[cache]")
+class CacheFixture
{
- Cache *c = new Cache(nullptr, 0);
- std::array<signed int, LINE_SIZE> expected = {0, 0, 0, 0};
- std::array<signed int, LINE_SIZE> actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- delete c;
-}
-
-TEST_CASE("no delay stores instantly", "[cache]")
-{
- int delay = 0;
- Dram *d = new Dram(delay);
- Cache *c = new Cache(d, delay);
- std::array<signed int, LINE_SIZE> expected = {0, 0, 0, 0};
- std::array<signed int, LINE_SIZE> actual = d->view(0, 1)[0];
- CHECK(expected == actual);
-
- signed int w = 0x11223344;
-
- Response r;
-
- r = c->write_word(MEM, w, 0b0);
- CHECK(r == OK);
- c->resolve();
-
- 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);
-
- delete c;
-}
-
-TEST_CASE("cache takes \"forever\"", "[cache]")
-{
- int delay = 0;
- Dram *d = new Dram(delay);
- Cache *c = new Cache(d, delay + 2);
- std::array<signed int, LINE_SIZE> expected = {0, 0, 0, 0};
- std::array<signed int, LINE_SIZE> actual = d->view(0, 1)[0];
- CHECK(expected == actual);
-
- signed int w = 0x11223344;
-
- int i;
- Response r;
- for (i = 0; i < delay + 2; ++i) {
- r = c->write_word(MEM, w, 0b0);
- CHECK(r == WAIT); // WAIT
-
- actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- c->resolve();
+ 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];
}
- 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);
+ ~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();
+ this->c->resolve();
+
+ // check response
+ CHECK(r == expected);
+ // check for early modifications
+ actual = c->view(0, 1)[0];
+ REQUIRE(this->expected == this->actual);
+ }
+ }
- delete c;
-}
+ 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("dram takes \"forever\"", "[cache]")
+TEST_CASE_METHOD(CacheFixture, "store 0th element in DELAY cycles", "[dram]")
{
- int delay = 0;
- Dram *d = new Dram(delay + 2);
- Cache *c = new Cache(d, delay);
- std::array<signed int, LINE_SIZE> expected = {0, 0, 0, 0};
- std::array<signed int, LINE_SIZE> actual = d->view(0, 1)[0];
+ Response r;
+ signed int w;
CHECK(expected == actual);
- signed int w = 0x11223344;
-
- int i;
- Response r;
- for (i = 0; i < delay + 2; ++i) {
- r = c->write_word(MEM, w, 0b0);
- CHECK(r == BLOCKED); // BLOCKED
+ 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);
+ });
- actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- c->resolve();
- }
+ 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 = d->view(0, 1)[0];
+ 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);
-
- delete c;
}
-TEST_CASE("dram and cache take \"forever\"", "[cache]")
+TEST_CASE_METHOD(
+ CacheFixture,
+ "store 0th, 1st element in DELAY cycles, with conflict",
+ "[cache]")
{
- int delay = 2;
- Dram *d = new Dram(delay + 2);
- Cache *c = new Cache(d, delay);
- std::array<signed int, LINE_SIZE> expected = {0, 0, 0, 0};
- std::array<signed int, LINE_SIZE> actual = d->view(0, 1)[0];
- CHECK(expected == actual);
-
- signed int w = 0x11223344;
-
- int i;
Response r;
- for (i = 0; i < delay + 2; ++i) {
- r = c->write_word(MEM, w, 0b0);
- CHECK(r == BLOCKED); // BLOCKED
-
- actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- c->resolve();
- }
+ signed int w;
+ int i;
+ CHECK(expected == actual);
- for (i = 0; i < delay; ++i) {
+ 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 == WAIT); // WAIT
+ CHECK(r == BLOCKED);
+ r = c->write_word(FETCH, w, 0b1);
+ CHECK(r == WAIT);
+ this->c->resolve();
+ // check for early modifications
actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- c->resolve();
+ REQUIRE(this->expected == this->actual);
}
- r = c->write_word(MEM, w, 0b0);
- CHECK(r == OK);
- c->resolve();
-
- 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);
-
- delete c;
-}
-
-TEST_CASE(
- "dram takes \"forever\", two concurrent requests same index", "[cache]")
-{
- int delay = 0;
- Dram *d = new Dram(delay + 2);
- Cache *c = new Cache(d, delay);
- std::array<signed int, LINE_SIZE> expected = {0, 0, 0, 0};
- std::array<signed int, LINE_SIZE> actual = d->view(0, 1)[0];
- CHECK(expected == actual);
-
- signed int w = 0x11223344;
-
- int i;
- Response r;
- for (i = 0; i < delay + 2; ++i) {
+ for (i = 0; i < this->c_delay; ++i) {
r = c->write_word(MEM, w, 0b0);
- CHECK(r == BLOCKED); // BLOCKED
-
+ CHECK(r == WAIT);
r = c->write_word(FETCH, w, 0b1);
- CHECK(r == WAIT); // WAIT
+ CHECK(r == WAIT);
+ this->c->resolve();
+ // check for early modifications
actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- c->resolve();
+ REQUIRE(this->expected == this->actual);
}
r = c->write_word(MEM, w, 0b0);
CHECK(r == OK);
+ // clock cycle did NOT resolve yet!
+ // this fetch should not make progress
r = c->write_word(FETCH, w, 0b1);
CHECK(r == WAIT);
-
c->resolve();
actual = d->view(0, 1)[0];
@@ -199,84 +127,76 @@ TEST_CASE(
actual = c->view(0, 1)[0];
REQUIRE(expected == actual);
- r = c->write_word(FETCH, w, 0b1);
// this should have been loaded already!
- CHECK(r == OK);
+ 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);
c->resolve();
expected.at(1) = w;
actual = c->view(0, 1)[0];
REQUIRE(expected == actual);
-
- delete c;
}
-TEST_CASE(
- "dram takes \"forever\", two concurrent requests different index",
+TEST_CASE_METHOD(
+ CacheFixture,
+ "store 0th, 1st element different tags, in DELAY cycles, no conflict",
"[cache]")
{
- int delay = 0;
- Dram *d = new Dram(delay + 2);
- Cache *c = new Cache(d, delay);
- std::array<signed int, LINE_SIZE> expected = {0, 0, 0, 0};
- std::array<signed int, LINE_SIZE> actual = d->view(0, 1)[0];
+ Response r;
+ signed int w;
CHECK(expected == actual);
- signed int w = 0x11223344;
-
- int i;
- Response r;
- for (i = 0; i < delay + 2; ++i) {
- r = c->write_word(MEM, w, 0b0);
- CHECK(r == BLOCKED); // BLOCKED
+ 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);
+ });
- r = c->write_word(FETCH, w, 0b100);
- CHECK(r == WAIT); // WAIT
-
- actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- c->resolve();
- }
+ 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);
- r = c->write_word(FETCH, w, 0b1);
- CHECK(r == WAIT);
-
c->resolve();
- 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);
- for (i = 0; i < delay + 2; ++i) {
- r = c->write_word(FETCH, w, 0b100);
- CHECK(r == BLOCKED); // BLOCKED
+ // write back to memory
+ this->wait_for_storage(this->m_delay + 1, BLOCKED, [this, w]() {
+ return this->c->write_word(FETCH, w, 0b10000001);
+ });
- actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
- c->resolve();
- }
+ // 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);
+ });
- r = c->write_word(FETCH, w, 0b1);
+ // after the fetch, this cache line should be empty
+ this->c->write_word(FETCH, w, 0b10000001);
CHECK(r == OK);
-
c->resolve();
- expected.at(1) = w;
+ expected.at(0) = 0;
actual = c->view(0, 1)[0];
- REQUIRE(expected == actual);
+ CHECK(expected == actual);
- delete c;
-}
+ this->wait_for_storage(this->c_delay, WAIT, [this, w]() {
+ return this->c->write_word(FETCH, w, 0b10000001);
+ });
-TEST_CASE(
- "dram takes \"forever\", two concurrent requests different tag", "[cache]")
-{
- // TODO
+ 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
index 4dcdb31..3397f74 100644
--- a/tests/dram.cc
+++ b/tests/dram.cc
@@ -13,7 +13,27 @@ class DramFixture
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();
+ this->d->resolve();
+
+ // 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;
@@ -24,20 +44,12 @@ TEST_CASE_METHOD(DramFixture, "store 0th element in DELAY cycles", "[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);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
+ 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);
this->d->resolve();
@@ -55,20 +67,12 @@ TEST_CASE_METHOD(
{
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);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
+ 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);
@@ -82,16 +86,9 @@ TEST_CASE_METHOD(
actual = d->view(0, 1)[0];
REQUIRE(expected == actual);
- for (i = 0; i < this->delay; ++i) {
- r = this->d->write_word(FETCH, w, 0x1);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- 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);
@@ -135,16 +132,9 @@ TEST_CASE_METHOD(
actual = d->view(0, 1)[0];
REQUIRE(expected == actual);
- for (i = 0; i < this->delay; ++i) {
- r = this->d->write_word(FETCH, w, 0x1);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- 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);
@@ -159,22 +149,14 @@ TEST_CASE_METHOD(DramFixture, "store line in DELAY cycles", "[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);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
+ 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);
@@ -189,22 +171,14 @@ TEST_CASE_METHOD(
{
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);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
+ 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);
@@ -219,16 +193,9 @@ TEST_CASE_METHOD(
REQUIRE(expected == actual);
buffer = {w + 4, w + 5, w + 6, w + 7};
- for (i = 0; i < this->delay; ++i) {
- r = this->d->write_line(FETCH, buffer, 0x1);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
+ 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);
@@ -275,16 +242,9 @@ TEST_CASE_METHOD(
REQUIRE(expected == actual);
buffer = {w + 4, w + 5, w + 6, w + 7};
- for (i = 0; i < this->delay; ++i) {
- r = this->d->write_line(FETCH, buffer, 0x1);
- this->d->resolve();
-
- // check response
- CHECK(r == WAIT);
- // check for early modifications
- actual = d->view(0, 1)[0];
- REQUIRE(expected == actual);
- }
+ 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);
@@ -296,7 +256,7 @@ TEST_CASE_METHOD(
}
TEST_CASE_METHOD(
- DramFixture, "store line in DELAY cycles, read in DELAY cycles", "[dram]")
+ DramFixture, "store line in DELAY cycles, read in DELAY cycles, no conflict", "[dram]")
{
Response r;
signed int w;