aboutsummaryrefslogtreecommitdiff
path: root/src/components/grid/node.c
blob: 0aed7683474604ed057e40c3b1b4a2960d930798 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/* very simple grid node with 32bit private region, does not currently signal
 * being busy or anything. I think I might have to refine the message passing
 * interface I have, but this is good enough.
 *
 * Each node should have a router beneath it, just to simplify my life. A router
 * is basically a bus with a fallback ascension path.
 */
#include <gran/grid/node.h>

struct grid_node {
	struct component component;
	uint8_t u, v, x, y;
	struct component *left, *right, *up, *down, *ascend, *lower;
};

typedef read_callback callback;

static stat grid_route(struct grid_node *grid, struct packet *pkt, callback op)
{
	uint64_t addr = packet_addr(pkt);
	uint8_t u = (addr >> 56) & 0xff;
	uint8_t v = (addr >> 48) & 0xff;
	uint8_t x = (addr >> 40) & 0xff;
	uint8_t y = (addr >> 32) & 0xff;

	if (grid->u == u && grid->v == v && grid->x == x && grid->y == y)
		return op(grid->lower, pkt);

	if (grid->u != u || grid->v != v) {
		if (!grid->ascend)
			return EBUS;

		return op(grid->ascend, pkt);
	}

	if (y < grid->y) {
		if (!grid->down)
			return EBUS;

		return op(grid->down, pkt);
	}

	if (y > grid->y) {
		if (!grid->up)
			return EBUS;

		return op(grid->up, pkt);
	}

	if (x < grid->x) {
		if (!grid->left)
			return EBUS;

		return op(grid->left, pkt);
	}

	if (x > grid->x) {
		if (!grid->right)
			return EBUS;

		return op(grid->right, pkt);
	}

	return EBUS;
}

static stat grid_write(struct grid_node *node, struct packet *pkt)
{
	return grid_route(node, pkt, write);
}

static stat grid_read(struct grid_node *node, struct packet *pkt)
{
	return grid_route(node, pkt, read);
}

struct component *create_grid_node(uint8_t u, uint8_t v, uint8_t x, uint8_t y)
{
	struct grid_node *node = calloc(1, sizeof(struct grid_node));
	if (!node)
		return NULL;

	node->u = u;
	node->v = v;
	node->x = x;
	node->y = y;
	node->component.write = (write_callback)grid_write;
	node->component.read = (read_callback)grid_read;

	return (struct component *)node;
}

stat grid_node_connect(struct component *node,
		struct component *left, struct component *right,
		struct component *up, struct component *down,
		struct component *lower, struct component *ascend)
{
	struct grid_node *n = (struct grid_node *)node;
	n->left = left;
	n->right = right;
	n->up = up;
	n->down = down;
	n->lower = lower;
	n->ascend = ascend;
	return OK;
}