aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-08-09 16:06:43 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2025-08-09 16:06:43 +0300
commit3083284c797fc8fc267144b05c8a58395e4583e3 (patch)
treed0413af85d65cf895aa85fdaaf3a9f090f41dac1
parentaba90a3a6f6c1caee28aaf3dadebb4daba5b5761 (diff)
downloadgran-3083284c797fc8fc267144b05c8a58395e4583e3.tar.gz
gran-3083284c797fc8fc267144b05c8a58395e4583e3.zip
add 1d mesh node and refactor 2d mesh node
+ Seems to decrease performance a little bit, presumably due to extra register copy, but simplifies code a lot and opens up more genericism so I'll consider it an upgrade for now. Copying packets around is rather slow though, might in the future move to some kind of pointer based packet handling
-rw-r--r--Makefile2
-rw-r--r--include/gran/mesh/node.h31
-rw-r--r--include/gran/mesh/node1d.h24
-rw-r--r--include/gran/mesh/node2d.h32
-rw-r--r--src/mesh/node.c164
-rw-r--r--src/mesh/node1d.c307
-rw-r--r--src/mesh/node2d.c281
-rw-r--r--src/mesh/source.mk2
-rw-r--r--src/source.mk2
-rw-r--r--tests/simple_mesh/source.mk18
-rw-r--r--tests/simple_mesh1d/sim.c88
-rw-r--r--tests/simple_mesh1d/source.mk19
-rw-r--r--tests/simple_mesh1d/test.c66
-rw-r--r--tests/simple_mesh2d/sim.c (renamed from tests/simple_mesh/sim.c)23
-rw-r--r--tests/simple_mesh2d/source.mk18
-rw-r--r--tests/simple_mesh2d/test.c (renamed from tests/simple_mesh/test.c)2
-rw-r--r--tests/starved_mesh/sim.c24
17 files changed, 868 insertions, 235 deletions
diff --git a/Makefile b/Makefile
index d6af17d..cc02b8d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
DO != echo -n > deps.mk
DEBUGFLAGS != [ $(RELEASE) ] && echo "-flto=auto -O2 -DNODEBUG" || echo "-O0 -g -DDEBUG"
-CFLAGS = -Wall -Wextra -g -std=gnu23
+CFLAGS = -Wall -Wextra -g
DEPFLAGS = -MT $@ -MMD -MP -MF $@.d
LINTFLAGS = -fsyntax-only
INCLUDEFLAGS = -Iinclude -Ideps/conts/include
diff --git a/include/gran/mesh/node.h b/include/gran/mesh/node.h
deleted file mode 100644
index 53ee08b..0000000
--- a/include/gran/mesh/node.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef GRAN_GRID_NODE_H
-#define GRAN_GRID_NODE_H
-
-#include <gran/component.h>
-#include <stdint.h>
-
-struct component *create_mesh_node(uint16_t x, uint16_t y);
-
-stat mesh_node_connect(struct component *node,
- struct component *n,
- struct component *s,
- struct component *e,
- struct component *w,
- struct component *l);
-
-static inline uint64_t mesh_addr(uint16_t x, uint16_t y, uint32_t off)
-{
- return off
- | ((uint64_t)x << 32)
- | ((uint64_t)y << 48)
- ;
-}
-
-static inline void addr_mesh(uint64_t addr, uint16_t *x, uint16_t *y, uint32_t *off)
-{
- if (off) *off = addr & 0xffffffff;
- if (x) *x = (addr >> 32) & 0xffff;
- if (y) *y = (addr >> 48) & 0xffff;
-}
-
-#endif /* GRAN_GRID_NODE_H */
diff --git a/include/gran/mesh/node1d.h b/include/gran/mesh/node1d.h
new file mode 100644
index 0000000..6c8151e
--- /dev/null
+++ b/include/gran/mesh/node1d.h
@@ -0,0 +1,24 @@
+#ifndef MESH_NODE1D_H
+#define MESH_NODE1D_H
+
+#include <stdint.h>
+#include <gran/component.h>
+
+struct component *create_mesh_node1d(uint16_t cluster, uint16_t elems);
+stat mesh_node1d_connect(struct component *node1d, struct component *component, uint16_t elem);
+stat mesh_node1d_connect_left(struct component *node1d, struct component *left);
+stat mesh_node1d_connect_right(struct component *node1d, struct component *right);
+
+static inline void addr_mesh1d(uint64_t addr, uint16_t *cluster, uint16_t *elem, uint32_t *off)
+{
+ if (off) *off = addr & 0xffffffff;
+ if (elem) *elem = (addr >> 32) & 0xffff;
+ if (cluster) *cluster = (addr >> 48) & 0xffff;
+}
+
+static inline uint64_t mesh1d_addr(uint16_t cluster, uint16_t elem, uint32_t off)
+{
+ return ((uint64_t)cluster << 48) | ((uint64_t)elem << 32) | off;
+}
+
+#endif /* MESH_NODE1D_H */
diff --git a/include/gran/mesh/node2d.h b/include/gran/mesh/node2d.h
new file mode 100644
index 0000000..fe43e59
--- /dev/null
+++ b/include/gran/mesh/node2d.h
@@ -0,0 +1,32 @@
+#ifndef GRAN_MESH_NODE2D_H
+#define GRAN_MESH_NODE2D_H
+
+#include <gran/component.h>
+#include <stdint.h>
+
+struct component *create_mesh_node2d(uint8_t x, uint8_t y, uint16_t elems);
+
+stat mesh_node2d_connect(struct component *c, struct component *e, uint16_t elem);
+stat mesh_node2d_connect_north(struct component *c, struct component *e);
+stat mesh_node2d_connect_south(struct component *c, struct component *e);
+stat mesh_node2d_connect_east(struct component *c, struct component *e);
+stat mesh_node2d_connect_west(struct component *c, struct component *e);
+
+static inline uint64_t mesh2d_addr(uint8_t x, uint8_t y, uint16_t elem, uint32_t off)
+{
+ return off
+ | ((uint64_t)elem << 32)
+ | ((uint64_t)x << 48)
+ | ((uint64_t)y << 56)
+ ;
+}
+
+static inline void addr_mesh2d(uint64_t addr, uint8_t *x, uint8_t *y, uint16_t *elem, uint32_t *off)
+{
+ if (off) *off = addr & 0xffffffff;
+ if (elem) *elem = (addr >> 32) & 0xffff;
+ if (x) *x = (addr >> 48) & 0xff;
+ if (y) *y = (addr >> 56) & 0xff;
+}
+
+#endif /* GRAN_MESH_NODE_H */
diff --git a/src/mesh/node.c b/src/mesh/node.c
deleted file mode 100644
index 2ac921a..0000000
--- a/src/mesh/node.c
+++ /dev/null
@@ -1,164 +0,0 @@
-#include <gran/mesh/node.h>
-
-struct reg {
- struct packet pkt;
- bool busy;
-};
-
-struct node {
- struct component component;
- uint16_t x, y;
-
- uint64_t timestamp;
-
- struct component *n, *s, *e, *w, *l;
-
- struct reg n_in, s_in, e_in, w_in, l_in;
-};
-
-enum order {
- N, S, E, W, L
-};
-
-static inline void maybe_pick(struct reg *output[5], enum order d, struct reg *r)
-{
- if (output[d] && output[d]->pkt.timestamp < r->pkt.timestamp)
- return;
-
- output[d] = r;
-}
-
-static stat node_clock(struct node *node)
-{
- node->timestamp++;
-
- struct reg *output[5] = {NULL, NULL, NULL, NULL, NULL};
- struct reg *input[5] = {
- &node->n_in,
- &node->s_in,
- &node->e_in,
- &node->w_in,
- &node->l_in
- };
-
- uint8_t X = node->x, Y = node->y;
- for (size_t i = 0; i < 5; ++i) {
- struct reg *r = input[i];
- if (!r->busy)
- continue;
-
- uint16_t x, y;
- addr_mesh(r->pkt.to, &x, &y, NULL);
- if (x < X) {
- maybe_pick(output, W, r);
- continue;
- }
-
- if (x > X) {
- maybe_pick(output, E, r);
- continue;
- }
-
- if (y < Y) {
- maybe_pick(output, S, r);
- continue;
- }
-
- if (y > Y) {
- maybe_pick(output, N, r);
- continue;
- }
-
- maybe_pick(output, L, r);
- }
-
- struct component *target[7] = {
- node->n,
- node->s,
- node->e,
- node->w,
- node->l
- };
-
- for (size_t i = 0; i < 5; ++i) {
- if (!output[i])
- continue;
-
- if (!target[i]) {
- /* for now, should send packet back with an error or something */
- abort();
- }
-
- stat ret = SEND(node, target[i], output[i]->pkt);
- if (ret == EBUSY)
- continue;
-
- assert(ret == OK);
- output[i]->busy = false;
- }
-
- return OK;
-}
-
-static stat reg_receive(struct reg *r, struct packet pkt)
-{
- if (r->busy)
- return EBUSY;
-
- r->pkt = pkt;
- r->busy = true;
- return OK;
-}
-
-static stat node_receive(struct node *node, struct component *from, struct packet pkt)
-{
- if (from == node->l) {
- /* add time when packet entered network */
- pkt.timestamp = node->timestamp;
- return reg_receive(&node->l_in, pkt);
- }
-
- if (from == node->n)
- return reg_receive(&node->n_in, pkt);
-
- if (from == node->s)
- return reg_receive(&node->s_in, pkt);
-
- if (from == node->e)
- return reg_receive(&node->e_in, pkt);
-
- if (from == node->w)
- return reg_receive(&node->w_in, pkt);
-
- abort();
- return OK;
-}
-
-struct component *create_mesh_node(uint16_t x, uint16_t y)
-{
- struct node *node = calloc(1, sizeof(struct node));
- if (!node)
- return NULL;
-
- node->component.receive = (receive_callback)node_receive;
- node->component.clock = (clock_callback)node_clock;
- node->x = x;
- node->y = y;
- return (struct component *)node;
-}
-
-stat mesh_node_connect(struct component *node,
- struct component *n,
- struct component *s,
- struct component *e,
- struct component *w,
- struct component *l)
-{
- struct node *nod = (struct node *)node;
- nod->n = n;
- nod->s = s;
- nod->e = e;
- nod->w = w;
- nod->l = l;
- return OK;
-}
diff --git a/src/mesh/node1d.c b/src/mesh/node1d.c
new file mode 100644
index 0000000..23ba2ca
--- /dev/null
+++ b/src/mesh/node1d.c
@@ -0,0 +1,307 @@
+#include <gran/mesh/node1d.h>
+
+#define left_port(n) (n)->ports[(n)->elems + 0]
+#define right_port(n) (n)->ports[(n)->elems + 1]
+
+#define left_in(n) (n)->in[(n)->elems + 0]
+#define right_in(n) (n)->in[(n)->elems + 1]
+
+#define left_out(n) (n)->out[(n)->elems + 0]
+#define right_out(n) (n)->out[(n)->elems + 1]
+
+struct reg {
+ struct packet pkt;
+ bool busy;
+};
+
+struct node1d {
+ struct component component;
+ uint16_t cluster;
+ uint16_t elems;
+
+ uint64_t timestamp;
+
+ struct reg *in; /* countedby[elems + 2] */
+ struct reg *out; /* countedby[elems + 2] */
+ struct component **ports; /* countedby[elems + 2] */
+};
+
+static void node1d_destroy(struct node1d *n)
+{
+ free(n->in);
+ free(n->out);
+ free(n->ports);
+}
+
+static stat reg_busy(struct reg *r, struct packet pkt)
+{
+ bool busy = r->busy;
+ if (!busy) {
+ r->pkt = pkt;
+ r->busy = true;
+ }
+
+ return busy ? EBUSY : OK;
+}
+
+static void copy_reg(struct reg *r, struct reg *s)
+{
+ assert(s->busy);
+ if (r->busy)
+ return;
+
+ r->pkt = s->pkt;
+ r->busy = true;
+ s->busy = false;
+}
+
+static stat node1d_receive(struct node1d *n, struct component *from, struct packet pkt)
+{
+ for (int i = 0; i < n->elems + 2; ++i) {
+ /* add timestamp to packets that originate with us */
+ if (i < n->elems)
+ pkt.timestamp = n->timestamp;
+
+ if (from == n->ports[i])
+ return reg_busy(&n->in[i], pkt);
+ }
+
+ /* shouldn't be possible */
+ abort();
+ return OK;
+}
+
+static void clock_outputs(struct node1d *n)
+{
+ for (int i = 0; i < n->elems + 2; ++i) {
+ if (!n->out[i].busy)
+ continue;
+
+ stat ret = SEND(n, n->ports[i], n->out[i].pkt);
+ if (ret == EBUSY)
+ continue;
+
+ n->out[i].busy = false;
+ }
+}
+
+static void propagate_left(struct node1d *n, struct reg *a, struct reg *b)
+{
+ struct reg *sel_a = NULL, *sel_b = NULL;
+ if (a && a->busy) {
+ uint16_t cluster = 0;
+ addr_mesh1d(a->pkt.to, &cluster, NULL, NULL);
+
+ if (cluster > n->cluster)
+ sel_a = a;
+ }
+
+ if (b && b->busy) {
+ uint16_t cluster = 0;
+ addr_mesh1d(b->pkt.to, &cluster, NULL, NULL);
+
+ if (cluster > n->cluster)
+ sel_b = b;
+ }
+
+ if (!sel_a && !sel_b)
+ return;
+
+ if (sel_a && !sel_b) {
+ copy_reg(&left_out(n), sel_a);
+ return;
+ }
+
+ if (!sel_a && sel_b) {
+ copy_reg(&left_out(n), sel_b);
+ return;
+ }
+
+ /* both available, select older */
+ if (sel_a->pkt.timestamp < sel_b->pkt.timestamp)
+ copy_reg(&left_out(n), sel_a);
+ else
+ copy_reg(&left_out(n), sel_b);
+}
+
+static void propagate_right(struct node1d *n, struct reg *a, struct reg *b)
+{
+ struct reg *sel_a = NULL, *sel_b = NULL;
+ if (a && a->busy) {
+ uint16_t cluster = 0;
+ addr_mesh1d(a->pkt.to, &cluster, NULL, NULL);
+
+ if (cluster < n->cluster)
+ sel_a = a;
+ }
+
+ if (b && b->busy) {
+ uint16_t cluster = 0;
+ addr_mesh1d(b->pkt.to, &cluster, NULL, NULL);
+
+ if (cluster < n->cluster)
+ sel_b = b;
+ }
+
+ if (!sel_a && !sel_b)
+ return;
+
+ if (sel_a && !sel_b) {
+ copy_reg(&right_out(n), sel_a);
+ return;
+ }
+
+ if (!sel_a && sel_b) {
+ copy_reg(&right_out(n), sel_b);
+ return;
+ }
+
+ /* both available, select older */
+ if (sel_a->pkt.timestamp < sel_b->pkt.timestamp)
+ copy_reg(&right_out(n), sel_a);
+ else
+ copy_reg(&right_out(n), sel_b);
+}
+
+static void propagate(struct node1d *n, int elem, struct reg *a, struct reg *b, struct reg *c)
+{
+
+ struct reg *sel_a = NULL, *sel_b = NULL, *sel_c = NULL;
+ if (a && a->busy) {
+ uint16_t cluster = 0, element = 0;
+ addr_mesh1d(a->pkt.to, &cluster, &element, NULL);
+
+ if (cluster == n->cluster && element == elem)
+ sel_a = a;
+ }
+
+ if (b && b->busy) {
+ uint16_t cluster = 0, element = 0;
+ addr_mesh1d(b->pkt.to, &cluster, &element, NULL);
+
+ if (cluster == n->cluster && element == elem)
+ sel_b = b;
+ }
+
+ if (c && c->busy) {
+ uint16_t cluster = 0, element = 0;
+ addr_mesh1d(c->pkt.to, &cluster, &element, NULL);
+
+ if (cluster == n->cluster && element == elem)
+ sel_c = c;
+ }
+
+ struct reg *sel_0 = NULL, *sel_1 = NULL;
+ if (sel_a && sel_b)
+ sel_0 = sel_a->pkt.timestamp < sel_b->pkt.timestamp ? sel_a : sel_b;
+ else
+ sel_0 = sel_a ? sel_a : sel_b;
+
+ if (sel_b && sel_c)
+ sel_1 = sel_b->pkt.timestamp < sel_c->pkt.timestamp ? sel_b : sel_c;
+ else
+ sel_1 = sel_b ? sel_b : sel_c;
+
+ struct reg *sel = NULL;
+ if (sel_0 && sel_1)
+ sel = sel_0->pkt.timestamp < sel_1->pkt.timestamp ? sel_0 : sel_1;
+ else
+ sel = sel_0 ? sel_0 : sel_1;
+
+ if (!sel)
+ return;
+
+ copy_reg(&n->out[elem], sel);
+}
+
+static stat node1d_clock(struct node1d *n)
+{
+ n->timestamp++;
+
+ clock_outputs(n);
+
+ /* select oldest packet to process */
+ struct reg *r = NULL;
+ for (int i = 0; i < n->elems; ++i) {
+ if (!n->in[i].busy)
+ continue;
+
+ if (!r || r->pkt.timestamp > n->in[i].pkt.timestamp)
+ r = &n->in[i];
+ }
+
+ propagate_left(n, r, &right_in(n));
+ propagate_right(n, r, &left_in(n));
+ for (int i = 0; i < n->elems; ++i)
+ propagate(n, i, r, &right_in(n), &left_in(n));
+
+ return OK;
+}
+
+stat mesh_node1d_connect(struct component *c, struct component *e, uint16_t elem)
+{
+ struct node1d *n = (struct node1d *)c;
+ if (elem >= n->elems)
+ return ENOSUCH;
+
+ if (n->ports[elem])
+ return EEXISTS;
+
+ n->ports[elem] = e;
+ return OK;
+}
+
+stat mesh_node1d_connect_left(struct component *c, struct component *e)
+{
+ struct node1d *n = (struct node1d *)c;
+ if (left_port(n))
+ return EEXISTS;
+
+ left_port(n) = e;
+ return OK;
+}
+
+stat mesh_node1d_connect_right(struct component *c, struct component *e)
+{
+ struct node1d *n = (struct node1d *)c;
+ if (right_port(n))
+ return EEXISTS;
+
+ right_port(n) = e;
+ return OK;
+}
+
+struct component *create_mesh_node1d(uint16_t cluster, uint16_t elems)
+{
+ struct node1d *n = (struct node1d *)calloc(1, sizeof(struct node1d));
+ if (!n)
+ return NULL;
+
+ n->in = (struct reg *)calloc(elems + 2, sizeof(struct reg));
+ if (!n->in) {
+ free(n);
+ return NULL;
+ }
+
+ n->out = (struct reg *)calloc(elems + 2, sizeof(struct reg));
+ if (!n->out) {
+ free(n->in);
+ free(n);
+ return NULL;
+ }
+
+ n->ports = (struct component **)calloc(elems + 2, sizeof(struct component *));
+ if (!n->ports) {
+ free(n->out);
+ free(n->in);
+ free(n);
+ return NULL;
+ }
+
+ n->component.destroy = (destroy_callback)node1d_destroy;
+ n->component.receive = (receive_callback)node1d_receive;
+ n->component.clock = (clock_callback)node1d_clock;
+ n->cluster = cluster;
+ n->elems = elems;
+ return (struct component *)n;
+}
diff --git a/src/mesh/node2d.c b/src/mesh/node2d.c
new file mode 100644
index 0000000..81ef8dc
--- /dev/null
+++ b/src/mesh/node2d.c
@@ -0,0 +1,281 @@
+#include <gran/mesh/node2d.h>
+
+#define north_port(n) (n)->ports[(n)->elems + 0]
+#define east_port(n) (n)->ports[(n)->elems + 1]
+#define south_port(n) (n)->ports[(n)->elems + 2]
+#define west_port(n) (n)->ports[(n)->elems + 3]
+
+#define north_in(n) (n)->in[(n)->elems + 0]
+#define east_in(n) (n)->in[(n)->elems + 1]
+#define south_in(n) (n)->in[(n)->elems + 2]
+#define west_in(n) (n)->in[(n)->elems + 3]
+
+#define north_out(n) (n)->out[(n)->elems + 0]
+#define east_out(n) (n)->out[(n)->elems + 1]
+#define south_out(n) (n)->out[(n)->elems + 2]
+#define west_out(n) (n)->out[(n)->elems + 3]
+
+struct reg {
+ struct packet pkt;
+ bool busy;
+};
+
+struct node2d {
+ struct component component;
+ uint16_t elems;
+ uint16_t x, y;
+
+ uint64_t timestamp;
+
+ struct reg *in; /* countedby[elems + 4] */
+ struct reg *out; /* countedby[elems + 4] */
+ struct component **ports; /* countedby[elems + 4] */
+};
+
+static void clock_outputs(struct node2d *n)
+{
+ for (int i = 0; i < n->elems + 4; ++i) {
+ if (!n->out[i].busy)
+ continue;
+
+ stat ret = SEND(n, n->ports[i], n->out[i].pkt);
+ if (ret == EBUSY)
+ continue;
+
+ n->out[i].busy = false;
+ }
+}
+
+static void copy_reg(struct reg *r, struct reg *s)
+{
+ assert(s->busy);
+ if (r->busy)
+ return;
+
+ r->pkt = s->pkt;
+ r->busy = true;
+ s->busy = false;
+}
+
+static void propagate(struct reg *out,
+ size_t count, struct reg *in[static count],
+ bool (*sel)(struct reg *r, void *data), void *data)
+{
+ struct reg *r = NULL;
+ for (size_t i = 0; i < count; ++i) {
+ if (!in[i] || !in[i]->busy)
+ continue;
+
+ if (!sel(in[i], data))
+ continue;
+
+ if (!r || r->pkt.timestamp > in[i]->pkt.timestamp)
+ r = in[i];
+ }
+
+ if (!r)
+ return;
+
+ copy_reg(out, r);
+}
+
+struct sel_helper {
+ uint8_t x, y;
+ uint16_t elem;
+};
+
+static bool north_sel(struct reg *r, void *data)
+{
+ uint8_t y = 0;
+ struct sel_helper *helper = data;
+ addr_mesh2d(r->pkt.to, NULL, &y, NULL, NULL);
+ return y > helper->y;
+}
+
+static bool south_sel(struct reg *r, void *data)
+{
+ uint8_t y = 0;
+ struct sel_helper *helper = data;
+ addr_mesh2d(r->pkt.to, NULL, &y, NULL, NULL);
+ return y < helper->y;
+}
+
+static bool east_sel(struct reg *r, void *data)
+{
+ uint8_t x = 0, y = 0;
+ struct sel_helper *helper = data;
+ addr_mesh2d(r->pkt.to, &x, &y, NULL, NULL);
+ return y == helper->y && x > helper->x;
+}
+
+static bool west_sel(struct reg *r, void *data)
+{
+ uint8_t x = 0, y = 0;
+ struct sel_helper *helper = data;
+ addr_mesh2d(r->pkt.to, &x, &y, NULL, NULL);
+ return y == helper->y && x < helper->x;
+}
+
+static bool elem_sel(struct reg *r, void *data)
+{
+ uint16_t elem = 0;
+ uint8_t x = 0, y = 0;
+ struct sel_helper *helper = data;
+ addr_mesh2d(r->pkt.to, &x, &y, &elem, NULL);
+ return x == helper->x && y == helper->y && elem == helper->elem;
+}
+
+static stat node2d_clock(struct node2d *n)
+{
+ n->timestamp++;
+ clock_outputs(n);
+
+ /* select oldest packet to process */
+ struct reg *r = NULL;
+ for (int i = 0; i < n->elems; ++i) {
+ if (!n->in[i].busy)
+ continue;
+
+ if (!r || r->pkt.timestamp > n->in[i].pkt.timestamp)
+ r = &n->in[i];
+ }
+
+ struct sel_helper helper = {
+ .elem = 0,
+ .x = n->x,
+ .y = n->y,
+ };
+
+ struct reg *north[] = {r, &east_in(n), &south_in(n), &west_in(n)};
+ struct reg *east[] = {r, &north_in(n), &south_in(n), &west_in(n)};
+ struct reg *south[] = {r, &north_in(n), &east_in(n), &west_in(n)};
+ struct reg *west[] = {r, &north_in(n), &east_in(n), &south_in(n)};
+
+ propagate(&north_out(n), 4, north, north_sel, &helper);
+ propagate(&east_out(n), 4, east, east_sel, &helper);
+ propagate(&south_out(n), 4, south, south_sel, &helper);
+ propagate(&west_out(n), 4, west, west_sel, &helper);
+
+ struct reg *all[] = {r, &north_in(n), &east_in(n), &south_in(n), &west_in(n)};
+ for (int i = 0; i < n->elems; ++i) {
+ helper.elem = i;
+ propagate(&n->out[i], 5, all, elem_sel, &helper);
+ }
+
+ return OK;
+}
+
+static stat reg_busy(struct reg *r, struct packet pkt)
+{
+ bool busy = r->busy;
+ if (!busy) {
+ r->pkt = pkt;
+ r->busy = true;
+ }
+
+ return busy ? EBUSY : OK;
+}
+
+static stat node2d_receive(struct node2d *n, struct component *from, struct packet pkt)
+{
+ for (int i = 0; i < n->elems + 4; ++i) {
+ if (from != n->ports[i])
+ continue;
+
+ if (i < n->elems)
+ pkt.timestamp = n->timestamp;
+
+ return reg_busy(&n->in[i], pkt);
+ }
+
+ abort();
+ return OK;
+}
+
+struct component *create_mesh_node2d(uint8_t x, uint8_t y, uint16_t elems)
+{
+ struct node2d *n = calloc(1, sizeof(struct node2d));
+ if (!n)
+ return NULL;
+
+ n->in = calloc(elems + 4, sizeof(struct reg));
+ if (!n->in) {
+ free(n);
+ return NULL;
+ }
+
+ n->out = calloc(elems + 4, sizeof(struct reg));
+ if (!n->out) {
+ free(n->in);
+ free(n);
+ return NULL;
+ }
+
+ n->ports = calloc(elems + 4, sizeof(struct component *));
+ if (!n->ports) {
+ free(n->out);
+ free(n->in);
+ free(n);
+ return NULL;
+ }
+
+ n->component.receive = (receive_callback)node2d_receive;
+ n->component.clock = (clock_callback)node2d_clock;
+ n->elems = elems;
+ n->x = x;
+ n->y = y;
+ return (struct component *)n;
+}
+
+stat mesh_node2d_connect(struct component *c, struct component *e, uint16_t elem)
+{
+ struct node2d *n = (struct node2d *)c;
+ if (elem >= n->elems)
+ return ENOSUCH;
+
+ if (n->ports[elem])
+ return EEXISTS;
+
+ n->ports[elem] = e;
+ return OK;
+}
+
+stat mesh_node2d_connect_north(struct component *c, struct component *e)
+{
+ struct node2d *n = (struct node2d *)c;
+ if (north_port(n))
+ return EEXISTS;
+
+ north_port(n) = e;
+ return OK;
+}
+
+stat mesh_node2d_connect_east(struct component *c, struct component *e)
+{
+ struct node2d *n = (struct node2d *)c;
+ if (east_port(n))
+ return EEXISTS;
+
+ east_port(n) = e;
+ return OK;
+}
+
+stat mesh_node2d_connect_south(struct component *c, struct component *e)
+{
+ struct node2d *n = (struct node2d *)c;
+ if (south_port(n))
+ return EEXISTS;
+
+ south_port(n) = e;
+ return OK;
+}
+
+stat mesh_node2d_connect_west(struct component *c, struct component *e)
+{
+ struct node2d *n = (struct node2d *)c;
+ if (west_port(n))
+ return EEXISTS;
+
+ west_port(n) = e;
+ return OK;
+}
diff --git a/src/mesh/source.mk b/src/mesh/source.mk
index 55a7d03..23d6014 100644
--- a/src/mesh/source.mk
+++ b/src/mesh/source.mk
@@ -1 +1 @@
-SOURCES += src/mesh/node.c src/mesh/node3d.c
+SOURCES += src/mesh/node1d.c src/mesh/node2d.c src/mesh/node3d.c
diff --git a/src/source.mk b/src/source.mk
index 3ed3dba..f6e8ba9 100644
--- a/src/source.mk
+++ b/src/source.mk
@@ -1,4 +1,4 @@
include src/*/source.mk
-SOURCES += src/root.c src/clock_domain.c src/vec.c src/ideal_noc.c
+SOURCES += src/root.c src/clock_domain.c src/ideal_noc.c
MAIN_SRC += src/main.c
diff --git a/tests/simple_mesh/source.mk b/tests/simple_mesh/source.mk
deleted file mode 100644
index 748e252..0000000
--- a/tests/simple_mesh/source.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-MESH_TEST_OBJ != ./scripts/gen-deps --sources "tests/simple_mesh/sim.c"
-TEST_PROGS += build/tests/simple_mesh/sim
-
-build/tests/simple_mesh/test.inc: tests/simple_mesh/test.c
- riscv64-unknown-elf-gcc -O2 -Wall -Wextra -ffreestanding -nostdlib \
- -march=rv64i -mabi=lp64 \
- -o build/tests/simple_mesh/test \
- tests/simple_mesh/test.c
- riscv64-unknown-elf-objcopy -Obinary \
- build/tests/simple_mesh/test \
- build/tests/simple_mesh/test.bin
- xxd -i build/tests/simple_mesh/test.bin \
- > build/tests/simple_mesh/test.inc
-
-build/tests/simple_mesh/sim.o: build/tests/simple_mesh/test.inc
-
-build/tests/simple_mesh/sim: $(MESH_TEST_OBJ) $(OBJS)
- $(COMPILE) $(MESH_TEST_OBJ) $(OBJS) -o $@
diff --git a/tests/simple_mesh1d/sim.c b/tests/simple_mesh1d/sim.c
new file mode 100644
index 0000000..c5f7290
--- /dev/null
+++ b/tests/simple_mesh1d/sim.c
@@ -0,0 +1,88 @@
+#include <assert.h>
+
+#include <gran/root.h>
+#include <gran/mem/simple_mem.h>
+#include <gran/bus/simple_bus.h>
+#include <gran/uart/simple_uart.h>
+#include <gran/mesh/node1d.h>
+#include <gran/cpu/riscv/simple_riscv64.h>
+
+#include "../build/tests/simple_mesh1d/test.inc"
+
+static stat build_node1d(struct clock_domain *clk, uint16_t x, uint16_t y)
+{
+ struct component **mesh = calloc(x + 1, sizeof(struct component *));
+ assert(mesh);
+
+ for (int i = 1; i < x + 1; ++i) {
+ /* 4 CPUs + 1 mem = 5 elems in total */
+ struct component *node = create_mesh_node1d(i, y + 1);
+ clock_domain_add(clk, node);
+ mesh[i] = node;
+
+ for (int j = 0; j < y; ++j) {
+ struct component *imem = create_simple_mem(4096);
+ init_simple_mem(imem, 0,
+ build_tests_simple_mesh1d_test_bin_len,
+ build_tests_simple_mesh1d_test_bin);
+
+ uint64_t rcv = mesh1d_addr(i, j, 0);
+ struct component *rv64 = create_simple_riscv64(rcv, 0, imem, node);
+ simple_riscv64_set_reg(rv64, 10, i); /* a0 */
+ simple_riscv64_set_reg(rv64, 11, j); /* a1 */
+ simple_riscv64_set_reg(rv64, 12, x); /* a2 */
+ simple_riscv64_set_reg(rv64, 13, y); /* a3 */
+
+ clock_domain_add(clk, rv64);
+ clock_domain_add(clk, imem);
+
+ mesh_node1d_connect(node, rv64, j);
+ }
+
+ struct component *dmem = create_simple_mem(4096);
+ clock_domain_add(clk, dmem);
+ mesh_node1d_connect(node, dmem, 4);
+ }
+
+ /* extra I/O node (kind of?) */
+ struct component *node = create_mesh_node1d(0, 2);
+ clock_domain_add(clk, node);
+ mesh[0] = node;
+
+ struct component *uart = create_simple_uart();
+ clock_domain_add(clk, uart);
+ mesh_node1d_connect(node, uart, 0);
+
+ struct component *dmem = create_simple_mem(4096);
+ clock_domain_add(clk, dmem);
+ mesh_node1d_connect(node, dmem, 1);
+
+ for (int i = 0; i < x + 1; ++i) {
+ if (i - 1 >= 0)
+ mesh_node1d_connect_right(mesh[i], mesh[i - 1]);
+
+ if (i + 1 < x + 1)
+ mesh_node1d_connect_left(mesh[i], mesh[i + 1]);
+ }
+
+ free(mesh);
+ return OK;
+}
+
+int main()
+{
+ struct clock_domain *clk = create_clock_domain(NS(1));
+
+ /* one cluster with four cores + mem for each core (should
+ * instructions be fetched from cluster local mem?) */
+ stat r = build_node1d(clk, 8, 8);
+ assert(r == OK);
+
+ struct gran_root *root = create_root();
+ root_add_clock(root, clk);
+
+ r = root_run(root);
+ assert(r == OK);
+
+ destroy_root(root);
+}
diff --git a/tests/simple_mesh1d/source.mk b/tests/simple_mesh1d/source.mk
new file mode 100644
index 0000000..5013c6e
--- /dev/null
+++ b/tests/simple_mesh1d/source.mk
@@ -0,0 +1,19 @@
+MESH1D_TEST_OBJ != ./scripts/gen-deps --sources "tests/simple_mesh1d/sim.c"
+TEST_PROGS += build/tests/simple_mesh1d/sim
+
+build/tests/simple_mesh1d/test.inc: tests/simple_mesh1d/test.c
+ riscv64-unknown-elf-gcc -O2 -Wall -Wextra -ffreestanding -nostdlib \
+ -march=rv64i -mabi=lp64 \
+ -fno-delete-null-pointer-checks \
+ -o build/tests/simple_mesh1d/test \
+ tests/simple_mesh1d/test.c
+ riscv64-unknown-elf-objcopy -Obinary \
+ build/tests/simple_mesh1d/test \
+ build/tests/simple_mesh1d/test.bin
+ xxd -i build/tests/simple_mesh1d/test.bin \
+ > build/tests/simple_mesh1d/test.inc
+
+build/tests/simple_mesh1d/sim.o: build/tests/simple_mesh1d/test.inc
+
+build/tests/simple_mesh1d/sim: $(MESH1D_TEST_OBJ) $(OBJS)
+ $(COMPILE) $(MESH1D_TEST_OBJ) $(OBJS) -o $@
diff --git a/tests/simple_mesh1d/test.c b/tests/simple_mesh1d/test.c
new file mode 100644
index 0000000..b3de347
--- /dev/null
+++ b/tests/simple_mesh1d/test.c
@@ -0,0 +1,66 @@
+#include <stdint.h>
+
+__attribute__((always_inline))
+static inline uint64_t extreme_numa_addr(uint16_t cluster, uint16_t elem, uint32_t off)
+{
+ return ((uint64_t)cluster << 48) | ((uint64_t)elem << 32) | off;
+}
+
+__attribute__((always_inline))
+static inline void print_int8(volatile char *uart, unsigned x)
+{
+ char lo_nibble = (x >> 0) & 0xf;
+ char hi_nibble = (x >> 4) & 0xf;
+
+ *uart = hi_nibble < 10 ? hi_nibble + '0' : (hi_nibble - 10) + 'a';
+ *uart = lo_nibble < 10 ? lo_nibble + '0' : (lo_nibble - 10) + 'a';
+}
+
+__attribute__((always_inline))
+static inline void print_addr(volatile char *uart, unsigned x, unsigned y)
+{
+ *uart = '(';
+ print_int8(uart, x);
+ *uart = ',';
+ *uart = ' ';
+ print_int8(uart, y);
+ *uart = ')';
+ *uart = '\n';
+}
+
+__attribute__((always_inline))
+static inline uint64_t wrap(unsigned x, unsigned X)
+{
+ return x + 1 >= X ? 0 : x + 1;
+}
+
+__attribute__((always_inline))
+static inline uint64_t next_idx(unsigned x, unsigned y, unsigned X, unsigned Y)
+{
+ unsigned yi = wrap(y, Y);
+ unsigned xi = yi < y ? wrap(x, X) : x;
+
+ return extreme_numa_addr(xi, yi, 0);
+}
+
+void _start(unsigned x, unsigned y, unsigned X, unsigned Y)
+{
+ volatile char *uart = (char *)extreme_numa_addr(0, 0, 0);
+ volatile uint64_t *control = (uint64_t *)extreme_numa_addr(0, 1, 0);
+
+ if (x == 1 && y == 0) {
+ goto do_work;
+ } else {
+ while (*control != extreme_numa_addr(x, y, 0)) {}
+ }
+
+do_work:
+ print_addr(uart, x, y);
+ *control = next_idx(x, y, X, Y);
+
+ if (x == X - 1 && y == Y - 1)
+ asm("ebreak");
+
+ /* otherwise just loop */
+ while (1) {}
+}
diff --git a/tests/simple_mesh/sim.c b/tests/simple_mesh2d/sim.c
index c3cdc33..1a9ba32 100644
--- a/tests/simple_mesh/sim.c
+++ b/tests/simple_mesh2d/sim.c
@@ -4,10 +4,10 @@
#include <gran/mem/simple_mem.h>
#include <gran/bus/simple_bus.h>
#include <gran/uart/simple_uart.h>
-#include <gran/mesh/node.h>
+#include <gran/mesh/node2d.h>
#include <gran/cpu/riscv/simple_riscv64.h>
-#include "../build/tests/simple_mesh/test.inc"
+#include "../build/tests/simple_mesh2d/test.inc"
static size_t idx_1d(int x, int y, uint8_t xw, uint8_t yw)
{
@@ -40,12 +40,11 @@ static void connect_mesh(struct component **mesh, struct component *c,
uint16_t x, uint16_t y,
uint16_t xw, uint16_t yw)
{
- mesh_node_connect(mesh_at(mesh, x, y, xw, yw),
- mesh_at(mesh, x , y+1, xw, yw),
- mesh_at(mesh, x , y-1, xw, yw),
- mesh_at(mesh, x+1, y , xw, yw),
- mesh_at(mesh, x-1, y , xw, yw),
- c);
+ mesh_node2d_connect_north(mesh_at(mesh, x, y, xw, yw), mesh_at(mesh, x , y+1, xw, yw));
+ mesh_node2d_connect_south(mesh_at(mesh, x, y, xw, yw), mesh_at(mesh, x , y-1, xw, yw));
+ mesh_node2d_connect_east(mesh_at(mesh, x, y, xw, yw), mesh_at(mesh, x+1, y , xw, yw));
+ mesh_node2d_connect_west(mesh_at(mesh, x, y, xw, yw), mesh_at(mesh, x-1, y , xw, yw));
+ mesh_node2d_connect(mesh_at(mesh, x, y, xw, yw), c, 0);
}
static stat build_mesh(struct clock_domain *clk, uint16_t x, uint16_t y)
@@ -58,7 +57,7 @@ static stat build_mesh(struct clock_domain *clk, uint16_t x, uint16_t y)
for (size_t i = 0; i < x; ++i)
for (size_t j = 0; j < y; ++j) {
- struct component *node = create_mesh_node(i, j);
+ struct component *node = create_mesh_node2d(i, j, 1);
clock_domain_add(clk, node);
mesh[idx_1d(i, j, x, y)] = node;
@@ -70,10 +69,10 @@ static stat build_mesh(struct clock_domain *clk, uint16_t x, uint16_t y)
struct component *imem = create_simple_mem(4096);
init_simple_mem(imem, 0,
- build_tests_simple_mesh_test_bin_len,
- build_tests_simple_mesh_test_bin);
+ build_tests_simple_mesh2d_test_bin_len,
+ build_tests_simple_mesh2d_test_bin);
- uint64_t rcv = mesh_addr(i, j, 0);
+ uint64_t rcv = mesh2d_addr(i, j, 0, 0);
struct component *rv64 = create_simple_riscv64(rcv, 0, imem, node);
simple_riscv64_set_reg(rv64, 10, i); /* a0 */
simple_riscv64_set_reg(rv64, 11, j); /* a1 */
diff --git a/tests/simple_mesh2d/source.mk b/tests/simple_mesh2d/source.mk
new file mode 100644
index 0000000..525efa3
--- /dev/null
+++ b/tests/simple_mesh2d/source.mk
@@ -0,0 +1,18 @@
+MESH2D_TEST_OBJ != ./scripts/gen-deps --sources "tests/simple_mesh2d/sim.c"
+TEST_PROGS += build/tests/simple_mesh2d/sim
+
+build/tests/simple_mesh2d/test.inc: tests/simple_mesh2d/test.c
+ riscv64-unknown-elf-gcc -O2 -Wall -Wextra -ffreestanding -nostdlib \
+ -march=rv64i -mabi=lp64 \
+ -o build/tests/simple_mesh2d/test \
+ tests/simple_mesh2d/test.c
+ riscv64-unknown-elf-objcopy -Obinary \
+ build/tests/simple_mesh2d/test \
+ build/tests/simple_mesh2d/test.bin
+ xxd -i build/tests/simple_mesh2d/test.bin \
+ > build/tests/simple_mesh2d/test.inc
+
+build/tests/simple_mesh2d/sim.o: build/tests/simple_mesh2d/test.inc
+
+build/tests/simple_mesh2d/sim: $(MESH2D_TEST_OBJ) $(OBJS)
+ $(COMPILE) $(MESH2D_TEST_OBJ) $(OBJS) -o $@
diff --git a/tests/simple_mesh/test.c b/tests/simple_mesh2d/test.c
index b1bbe84..d607a59 100644
--- a/tests/simple_mesh/test.c
+++ b/tests/simple_mesh2d/test.c
@@ -35,7 +35,7 @@ static inline unsigned next_idx(unsigned x, unsigned y, unsigned X, unsigned Y)
void _start(unsigned x, unsigned y, unsigned X, unsigned Y)
{
volatile char *uart = (char *)4096;
- volatile unsigned *control = (unsigned *)(1ULL << 48);
+ volatile unsigned *control = (unsigned *)(1ULL << 56);
if (x == 0 && y == 2) {
goto do_work;
diff --git a/tests/starved_mesh/sim.c b/tests/starved_mesh/sim.c
index 1967e0b..990acc5 100644
--- a/tests/starved_mesh/sim.c
+++ b/tests/starved_mesh/sim.c
@@ -7,7 +7,7 @@
#include <gran/mem/simple_mem.h>
#include <gran/bus/simple_bus.h>
#include <gran/uart/simple_uart.h>
-#include <gran/mesh/node.h>
+#include <gran/mesh/node2d.h>
#include <gran/cpu/riscv/simple_riscv64.h>
unsigned char _tmp_test_bin[] = {
@@ -63,7 +63,7 @@ static stat build_mesh(struct clock_domain *clk, uint8_t x, uint8_t y)
for (size_t i = 0; i < x; ++i)
for (size_t j = 0; j < y; ++j) {
- struct component *node = create_mesh_node(i, j);
+ struct component *node = create_mesh_node2d(i, j, 1);
clock_domain_add(clk, node);
mesh[i * x + j] = node;
@@ -76,7 +76,7 @@ static stat build_mesh(struct clock_domain *clk, uint8_t x, uint8_t y)
struct component *imem = create_simple_mem(4096);
init_simple_mem(imem, 0, _tmp_test_bin_len, _tmp_test_bin);
- uint64_t rcv = mesh_addr(i, j, 0);
+ uint64_t rcv = mesh2d_addr(i, j, 0, 0);
struct component *rv64 = create_simple_riscv64(rcv, 0, imem, node);
simple_riscv64_set_reg(rv64, 10, i); /* a0 */
simple_riscv64_set_reg(rv64, 11, j); /* a1 */
@@ -89,11 +89,19 @@ static stat build_mesh(struct clock_domain *clk, uint8_t x, uint8_t y)
struct component *uart = create_simple_uart();
clock_domain_add(clk, uart);
- mesh_node_connect(mesh[0], NULL, mesh[x], mesh[1], NULL, uart);
+ mesh_node2d_connect_north(mesh[0], NULL);
+ mesh_node2d_connect_south(mesh[0], mesh[x]);
+ mesh_node2d_connect_east(mesh[0], mesh[1]);
+ mesh_node2d_connect_west(mesh[0], NULL);
+ mesh_node2d_connect(mesh[0], uart, 0);
struct component *dmem = create_simple_mem(4096);
clock_domain_add(clk, dmem);
- mesh_node_connect(mesh[1], NULL, mesh[x + 1], mesh[2], mesh[0], dmem);
+ mesh_node2d_connect_north(mesh[0], NULL);
+ mesh_node2d_connect_south(mesh[0], mesh[x + 1]);
+ mesh_node2d_connect_east(mesh[0], mesh[2]);
+ mesh_node2d_connect_west(mesh[0], mesh[0]);
+ mesh_node2d_connect(mesh[0], dmem, 0);
for (int i = 0; i < x; ++i)
for (int j = 0; j < y; ++j) {
@@ -109,7 +117,11 @@ static stat build_mesh(struct clock_domain *clk, uint8_t x, uint8_t y)
struct component *right = get_mesh(mesh, i + 1, j , x, y);
struct component *up = get_mesh(mesh, i , j + 1, x, y);
struct component *down = get_mesh(mesh, i , j - 1, x, y);
- mesh_node_connect(node, left, right, up, down, lower);
+ mesh_node2d_connect_north(node, up);
+ mesh_node2d_connect_south(node, down);
+ mesh_node2d_connect_east(node, left);
+ mesh_node2d_connect_west(node, right);
+ mesh_node2d_connect(node, lower, 0);
}
free(pes);