aboutsummaryrefslogtreecommitdiff
path: root/tests/simple_ideal_alloc/testbench.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-03-02 21:45:51 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2025-03-02 21:45:51 +0200
commit0464b7765aa4d1fc2178e443a3b37d19cfe541a0 (patch)
tree7df54d44f11bcba1c9271148f085501bc2a02d2e /tests/simple_ideal_alloc/testbench.c
parentad6107d33a8a222d9062aae45d0e8d8483939d5d (diff)
downloadgran-0464b7765aa4d1fc2178e443a3b37d19cfe541a0.tar.gz
gran-0464b7765aa4d1fc2178e443a3b37d19cfe541a0.zip
add ideal allocation tracker
+ Kind of like CHERI, but uses out-of-line pointer information. The idea is that a core that is compatible with ALLOC_IF queries the allocation tracker if an address is legal and gets a response. This ideal tracker effectively has infinite memory and doesn't talk to any other components, but a real implementation might want to limit the allocations per process or chat with some reserved memory region somewhere else in the system to maintain a binary tree or something.
Diffstat (limited to 'tests/simple_ideal_alloc/testbench.c')
-rw-r--r--tests/simple_ideal_alloc/testbench.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/tests/simple_ideal_alloc/testbench.c b/tests/simple_ideal_alloc/testbench.c
new file mode 100644
index 0000000..703c2a8
--- /dev/null
+++ b/tests/simple_ideal_alloc/testbench.c
@@ -0,0 +1,119 @@
+#include <gran/if/alloc.h>
+#include "testbench.h"
+
+struct reg {
+ struct packet pkt;
+ bool busy;
+};
+
+struct tb {
+ struct component component;
+ struct component *dut;
+ struct reg in;
+
+ enum {
+ ADD_REGION,
+ QUERY_EXISTING,
+ REMOVE_REGION,
+ QUERY_NONEXISTING,
+ FINAL
+ } state;
+};
+
+static stat tb_receive(struct tb *tb, struct component *from, struct packet pkt)
+{
+ assert(tb->dut == from);
+ tb->in.pkt = pkt;
+ tb->in.busy = true;
+ return OK;
+}
+
+static stat tb_clock(struct tb *tb)
+{
+ assert(tb->dut);
+
+ switch (tb->state) {
+ case ADD_REGION: {
+ struct alloc_if_new n = {.space = 0, .start = 0, .end = 10};
+ struct packet pkt = create_packet(0, ALLOC_IF_NEW, sizeof(n), &n, PACKET_WRITE);
+ assert(SEND(tb, tb->dut, pkt) == OK);
+ tb->state = QUERY_EXISTING;
+ break;
+ }
+
+ case QUERY_EXISTING: {
+ if (!tb->in.busy)
+ break;
+
+ struct alloc_if_r *r = (struct alloc_if_r *)&tb->in.pkt.data;
+ assert(r->r == ALLOC_IF_OK);
+
+ struct alloc_if_q q = {.space = 0, .addr = 5};
+ struct packet pkt = create_packet(0, ALLOC_IF_Q, sizeof(q), &q, PACKET_WRITE);
+ assert(SEND(tb, tb->dut, pkt) == OK);
+ tb->state = REMOVE_REGION;
+ tb->in.busy = false;
+ break;
+ }
+
+ case REMOVE_REGION: {
+ if (!tb->in.busy)
+ break;
+
+ struct alloc_if_r *r = (struct alloc_if_r *)&tb->in.pkt.data;
+ assert(r->r == ALLOC_IF_OK);
+ assert(r->start == 0);
+ assert(r->end == 10);
+
+ struct alloc_if_rm rm = {.space = 0, .start = 0, .end = 10};
+ struct packet pkt = create_packet(0, ALLOC_IF_RM, sizeof(rm), &rm, PACKET_WRITE);
+ assert(SEND(tb, tb->dut, pkt) == OK);
+ tb->state = QUERY_NONEXISTING;
+ tb->in.busy = false;
+ break;
+ }
+
+ case QUERY_NONEXISTING: {
+ if (!tb->in.busy)
+ break;
+
+ struct alloc_if_r *r = (struct alloc_if_r *)&tb->in.pkt.data;
+ assert(r->r == ALLOC_IF_OK);
+
+ struct alloc_if_q q = {.space = 0, .addr = 5};
+ struct packet pkt = create_packet(0, ALLOC_IF_Q, sizeof(q), &q, PACKET_WRITE);
+ assert(SEND(tb, tb->dut, pkt) == OK);
+ tb->state = FINAL;
+ tb->in.busy = false;
+ break;
+ }
+
+ case FINAL: {
+ if (!tb->in.busy)
+ break;
+
+ struct alloc_if_r *r = (struct alloc_if_r *)&tb->in.pkt.data;
+ assert(r->r != ALLOC_IF_OK);
+ return DONE;
+ }
+
+ default: abort();
+ }
+
+ return OK;
+}
+
+struct component *create_testbench()
+{
+ struct tb *tb = calloc(1, sizeof(struct tb));
+ tb->component.clock = (clock_callback)tb_clock;
+ tb->component.receive = (receive_callback)tb_receive;
+ return (struct component *)tb;
+}
+
+stat testbench_connect(struct component *tb, struct component *dut)
+{
+ struct tb *t = (struct tb *)tb;
+ t->dut = dut;
+ return OK;
+}