diff options
author | bd <bdunahu@operationnull.com> | 2025-03-21 01:06:38 -0400 |
---|---|---|
committer | bd <bdunahu@operationnull.com> | 2025-03-21 01:06:38 -0400 |
commit | 4d1378e802d869271729bc3da1cbc362e8761a22 (patch) | |
tree | 3bf1411babb1511e6ad10ed7cdeaba576d8c4731 | |
parent | 5845ad71d78d310322046906ee4c8e91d007d57e (diff) |
Rewrite current cache.cc tests, add test-helper function to dram
-rw-r--r-- | inc/cache.h | 2 | ||||
-rw-r--r-- | src/storage/cache.cc | 14 | ||||
-rw-r--r-- | tests/cache.cc | 312 | ||||
-rw-r--r-- | tests/dram.cc | 130 |
4 files changed, 169 insertions, 289 deletions
diff --git a/inc/cache.h b/inc/cache.h index 31602ca..3b16ca1 100644 --- a/inc/cache.h +++ b/inc/cache.h @@ -47,7 +47,7 @@ class Cache : public Storage * cache level to true, and the victim line is chosen/written back. * @param the address that must be present in cache. */ - void fetch_resource(int address); + void handle_miss(int address); /** * An array of metadata about elements in `data`. * If the first value of an element is negative, the corresponding diff --git a/src/storage/cache.cc b/src/storage/cache.cc index 3e2a5e0..f15c919 100644 --- a/src/storage/cache.cc +++ b/src/storage/cache.cc @@ -34,7 +34,7 @@ Response Cache::write_word(Accessor accessor, signed int data, int address) this->requester = accessor; if (this->requester == accessor) { - fetch_resource(address); + handle_miss(address); if (this->is_waiting) r = BLOCKED; else if (this->wait_time == 0) { @@ -59,7 +59,7 @@ Response Cache::write_line( this->requester = accessor; if (this->requester == accessor) { - fetch_resource(address); + handle_miss(address); if (this->is_waiting) r = BLOCKED; else if (this->wait_time == 0) { @@ -84,7 +84,7 @@ Response Cache::read_line( if (this->requester == IDLE) this->requester = accessor; if (this->requester == accessor) { - fetch_resource(address); + handle_miss(address); if (this->is_waiting) r = BLOCKED; else if (this->wait_time == 0) { @@ -103,7 +103,7 @@ Response Cache::read_word(Accessor accessor, int address, signed int &data) if (this->requester == IDLE) this->requester = accessor; if (this->requester == accessor) { - fetch_resource(address); + handle_miss(address); if (this->is_waiting) r = BLOCKED; else if (this->wait_time == 0) { @@ -116,15 +116,15 @@ Response Cache::read_word(Accessor accessor, int address, signed int &data) return r; } -void Cache::fetch_resource(int expected) +void Cache::handle_miss(int expected) { - Response r = OK; - Response q; + Response r, q; int tag, index, offset; std::array<signed int, LINE_SIZE> *actual; std::array<int, 2> *meta; get_bit_fields(expected, &tag, &index, &offset); + r = OK; meta = &this->meta.at(index); actual = &this->data->at(index); 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; |