diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | include/gran/mesh/node.h | 31 | ||||
| -rw-r--r-- | include/gran/mesh/node1d.h | 24 | ||||
| -rw-r--r-- | include/gran/mesh/node2d.h | 32 | ||||
| -rw-r--r-- | src/mesh/node.c | 164 | ||||
| -rw-r--r-- | src/mesh/node1d.c | 307 | ||||
| -rw-r--r-- | src/mesh/node2d.c | 281 | ||||
| -rw-r--r-- | src/mesh/source.mk | 2 | ||||
| -rw-r--r-- | src/source.mk | 2 | ||||
| -rw-r--r-- | tests/simple_mesh/source.mk | 18 | ||||
| -rw-r--r-- | tests/simple_mesh1d/sim.c | 88 | ||||
| -rw-r--r-- | tests/simple_mesh1d/source.mk | 19 | ||||
| -rw-r--r-- | tests/simple_mesh1d/test.c | 66 | ||||
| -rw-r--r-- | tests/simple_mesh2d/sim.c (renamed from tests/simple_mesh/sim.c) | 23 | ||||
| -rw-r--r-- | tests/simple_mesh2d/source.mk | 18 | ||||
| -rw-r--r-- | tests/simple_mesh2d/test.c (renamed from tests/simple_mesh/test.c) | 2 | ||||
| -rw-r--r-- | tests/starved_mesh/sim.c | 24 |
17 files changed, 868 insertions, 235 deletions
@@ -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); |
