aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-09-24 16:51:51 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-09-24 18:47:13 +0300
commitfecb86f6093c1e8aed6ab05c29c5af9d0cb93157 (patch)
tree10171c839d77167fc98fbae0b315d2c87aa13fa5 /src
parentb1d67364b4b4832b8efed112f7b0ead1a0b3cd3b (diff)
downloadgran-fecb86f6093c1e8aed6ab05c29c5af9d0cb93157.tar.gz
gran-fecb86f6093c1e8aed6ab05c29c5af9d0cb93157.zip
initial work towards message passing interface
+ As they are currently implemented, grid *may* get stuck if two nodes try to send to eachother at the same time, I should probably add in some kind of input buffer as well
Diffstat (limited to 'src')
-rw-r--r--src/clock_domain.c17
-rw-r--r--src/components/bus/simple_bus.c182
-rw-r--r--src/components/cpu/riscv/simple_riscv64.c207
-rw-r--r--src/components/grid/node.c91
-rw-r--r--src/components/grid/router.c72
-rw-r--r--src/components/mem/simple_mem.c53
-rw-r--r--src/components/uart/simple_uart.c42
-rw-r--r--src/packet.c92
-rw-r--r--src/snoop.c42
9 files changed, 354 insertions, 444 deletions
diff --git a/src/clock_domain.c b/src/clock_domain.c
index 6610d8f..74f0f03 100644
--- a/src/clock_domain.c
+++ b/src/clock_domain.c
@@ -20,8 +20,6 @@ struct clock_domain {
tick period;
stat ret;
-
- mtx_t mtx;
};
void advance_clock(struct clock_domain *clk)
@@ -41,7 +39,6 @@ struct clock_domain *create_clock_domain(tick period)
return NULL;
clk->period = period;
- mtx_init(&clk->mtx, mtx_plain);
clk->components = vec_create(sizeof(struct component *));
return clk;
@@ -62,20 +59,12 @@ stat clock_domain_add(struct clock_domain *clk, struct component *component)
return OK;
}
-static void update_ret(struct clock_domain *clk, stat ret)
-{
- if (ret) {
- mtx_lock(&clk->mtx);
- clk->ret = ret;
- mtx_unlock(&clk->mtx);
- }
-}
-
static void clocked_component_tick(struct clock_domain *clk,
struct component *component)
{
- stat ret = component->clock(component);
- update_ret(clk, ret);
+ stat r = component->clock(component);
+ if (r)
+ clk->ret = r;
}
stat clock_domain_tick(struct clock_domain *clk)
diff --git a/src/components/bus/simple_bus.c b/src/components/bus/simple_bus.c
index 218e930..1932419 100644
--- a/src/components/bus/simple_bus.c
+++ b/src/components/bus/simple_bus.c
@@ -1,154 +1,76 @@
/* SPDX-License-Identifier: copyleft-next-0.3.1 */
/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
-
-#include <threads.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-#include <gran/common.h>
-#include <gran/component.h>
+#include <stdbool.h>
#include <gran/bus/simple_bus.h>
+#include <gran/vec.h>
-struct mem_region {
- uintptr_t addr;
- size_t size;
+struct bus_region {
+ uint64_t addr;
+ uint64_t size;
struct component *component;
- struct mem_region *next;
};
struct simple_bus {
struct component component;
- mtx_t lock;
+ struct vec regions;
- struct mem_region *mem_regions;
+ struct component *send;
+ struct packet pkt;
+ bool busy;
};
-static struct mem_region *find_mem_region(struct simple_bus *bus,
- uintptr_t addr)
+static struct bus_region *find_bus_region(struct simple_bus *bus, uint64_t addr)
{
- if (!bus->mem_regions)
- return NULL;
-
- struct mem_region *cur = bus->mem_regions;
- while (cur) {
- /* address is within memory region */
- if (addr >= cur->addr && addr < cur->addr + cur->size)
- return cur;
-
- cur = cur->next;
+ foreach_vec(i, bus->regions) {
+ struct bus_region *r = vec_at(&bus->regions, i);
+ if (addr >= r->addr && addr < (r->addr + r->size))
+ return r;
}
return NULL;
}
-static stat add_mem_region(struct simple_bus *bus, struct mem_region *new)
+static stat simple_bus_clock(struct simple_bus *bus)
{
- if (!bus->mem_regions) {
- bus->mem_regions = new;
- return OK;
- }
+ if (bus->busy) {
+ stat r = SEND(bus, bus->send, bus->pkt);
+ if (r == EBUSY)
+ return OK;
- struct mem_region *found = NULL;
- if ((found = find_mem_region(bus, new->addr))) {
- error("%s overlaps with %s at %" PRIuPTR,
- new->component->name,
- found->component->name,
- new->addr
- );
- return EEXISTS;
+ bus->busy = false;
+ return r;
}
- new->next = bus->mem_regions;
- bus->mem_regions = new;
return OK;
}
-static stat simple_bus_write(struct simple_bus *bus, struct packet *pkt)
-{
- /* only one device can drive the bus at one time */
- if (mtx_trylock(&bus->lock) != thrd_success)
- return EBUSY;
-
- struct mem_region *mem_region = find_mem_region(bus, packet_addr(pkt));
- if (!mem_region) {
- warn("nothing to write on bus %s at %" PRIuPTR,
- bus->component.name, packet_addr(pkt));
- return EBUS;
- }
-
- stat ret = write(mem_region->component, pkt);
-
- mtx_unlock(&bus->lock);
- return ret;
-}
-
-static stat simple_bus_read(struct simple_bus *bus, struct packet *pkt)
+static stat simple_bus_receive(struct simple_bus *bus, struct component *from, struct packet pkt)
{
- /* only one device can drive the bus at one time */
- if (mtx_trylock(&bus->lock) != thrd_success)
+ if (bus->busy)
return EBUSY;
- struct mem_region *mem_region = find_mem_region(bus, packet_addr(pkt));
- if (!mem_region) {
- warn("nothing to read on bus %s at %" PRIuPTR,
- bus->component.name, packet_addr(pkt));
- return EBUS;
- }
+ bus->busy = true;
- stat ret = read(mem_region->component, pkt);
+ struct bus_region *region = find_bus_region(bus, pkt.to);
+ if (!region) {
+ warn("illegal address on bus %s at %" PRIuPTR,
+ bus->component.name, pkt.to);
- mtx_unlock(&bus->lock);
- return ret;
-}
-
-static stat simple_bus_swap(struct simple_bus *bus, struct packet *pkt)
-{
- if (mtx_trylock(&bus->lock) != thrd_success)
- return EBUSY;
-
- struct mem_region *mem_region = find_mem_region(bus, packet_addr(pkt));
- if (!mem_region) {
- warn("nothing to swap on bus %s at %" PRIuPTR,
- bus->component.name, packet_addr(pkt));
- return EBUS;
- }
-
- stat ret = swap(mem_region->component, pkt);
-
- mtx_unlock(&bus->lock);
- return ret;
-}
-
-static stat simple_bus_snoop(struct simple_bus *bus, struct snoop *snoop)
-{
- struct mem_region *cur = bus->mem_regions;
- while (cur) {
- if (cur->component->snoop) {
- stat ret = cur->component->snoop(cur->component, snoop);
- if (ret)
- return ret;
-
- if (snoop_state(snoop) == SNOOP_ANSWERED)
- return OK;
- }
-
- cur = cur->next;
+ bus->send = from;
+ bus->pkt = response(pkt);
+ set_flags(&bus->pkt, PACKET_ERROR);
+ return OK;
}
+ bus->send = region->component;
+ bus->pkt = pkt;
return OK;
}
static void simple_bus_destroy(struct simple_bus *bus)
{
- struct mem_region *cur = bus->mem_regions, *next = NULL;
- if (cur)
- do {
- next = cur->next;
- destroy(cur->component);
- free(cur);
- } while ((cur = next));
-
+ vec_destroy(&bus->regions);
free(bus);
}
@@ -158,34 +80,38 @@ struct component *create_simple_bus()
if (!bus)
return NULL;
- bus->component.write = (write_callback)simple_bus_write;
- bus->component.read = (read_callback)simple_bus_read;
- bus->component.swap = (swap_callback)simple_bus_swap;
- bus->component.snoop = (snoop_callback)simple_bus_snoop;
- // actually, still not sure about what API I want to use for controls
- // bus->component.ctrl = (ctrl_callback)simple_bus_ctrl;
+ bus->component.receive = (receive_callback)simple_bus_receive;
+ bus->component.clock = (clock_callback)simple_bus_clock;
bus->component.destroy = (destroy_callback)simple_bus_destroy;
+ bus->regions = vec_create(sizeof(struct bus_region));
- mtx_init(&bus->lock, mtx_plain);
return (struct component *)bus;
}
stat simple_bus_add(struct component *bus, struct component *component,
uint64_t addr, uint64_t size)
{
- struct mem_region *new = calloc(1, sizeof(struct mem_region));
- if (!new)
- return ENOMEM;
+ struct simple_bus *b = (struct simple_bus *)bus;
+ struct bus_region *found = find_bus_region(b, addr);
+ if (!found) found = find_bus_region(b, addr + size);
- new->addr = addr;
- new->size = size;
- new->component = component;
+ if (found) {
+ error("%s overlaps with %s at %" PRIuPTR,
+ found->component->name,
+ component->name,
+ found->addr
+ );
- if (add_mem_region((struct simple_bus *)bus, new)) {
- free(new);
return EEXISTS;
}
+ struct bus_region new = (struct bus_region){
+ .component = component,
+ .addr = addr,
+ .size = size
+ };
+
+ vect_append(struct bus_region, b->regions, &new);
return OK;
}
diff --git a/src/components/cpu/riscv/simple_riscv64.c b/src/components/cpu/riscv/simple_riscv64.c
index be96e60..987838e 100644
--- a/src/components/cpu/riscv/simple_riscv64.c
+++ b/src/components/cpu/riscv/simple_riscv64.c
@@ -9,8 +9,13 @@
#include <gran/cpu/riscv/simple_riscv64.h>
-struct simple_rv64_ldst {
- struct packet *pkt;
+enum ldst_state {
+ LDST_IDLE, LDST_BLOCKED, LDST_SENT, LDST_DONE
+};
+
+struct ldst {
+ struct packet pkt;
+ enum ldst_state state;
uint32_t reg;
bool u;
};
@@ -21,8 +26,10 @@ struct simple_riscv64 {
struct component *imem;
struct component *dmem;
- struct simple_rv64_ldst dls;
- struct simple_rv64_ldst ils;
+ struct ldst dls;
+ struct ldst ils;
+
+ uint64_t rcv;
/* have to be careful with x0 */
uint64_t regs[32];
@@ -396,25 +403,31 @@ static stat load(struct simple_riscv64 *cpu, union rv_insn insn)
/* LH/LHU */
case 0b101: u = true; /* fallthrough */
case 0b001: size = 2; break;
- /* LW */
+ /* LW/LWU */
+ case 0b110: u = true; /* fallthrough */
case 0b010: size = 4; break;
+ /* LD */
case 0b011: size = 8; break;
default:
error("unknown LOAD width %x", insn.btype.funct3);
return ENOSUCH;
}
- struct packet *pkt = create_packet(PACKET_READ, addr, size);
- if (!pkt)
- return EMEM;
+ struct packet pkt = create_packet(cpu->rcv,
+ addr,
+ size,
+ NULL,
+ PACKET_READ);
- cpu->dls = (struct simple_rv64_ldst){pkt, insn.itype.rd, u};
- stat ret = read(cpu->dmem, pkt);
- if (ret)
- return ret;
+ cpu->dls = (struct ldst){pkt, LDST_SENT, insn.itype.rd, u};
+ stat ret = SEND(cpu, cpu->dmem, pkt);
+ if (ret == EBUSY) {
+ cpu->dls.state = LDST_BLOCKED;
+ ret = OK;
+ }
cpu->pc += 4;
- return OK;
+ return ret;
}
#define STYPE_IMM(insn) \
@@ -428,66 +441,58 @@ static stat store(struct simple_riscv64 *cpu, union rv_insn insn)
int64_t addr = base + imm;
uint64_t src = get_reg(cpu, insn.stype.rs2);
+ uint64_t size = 0;
switch (insn.stype.funct3) {
/* SB */
- case 0b000: {
- cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 1);
- *(uint8_t *)packet_data(cpu->dls.pkt) = src;
- break;
- }
+ case 0b000: size = 1; break;
/* SH */
- case 0b001: {
- cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 2);
- *(uint16_t *)packet_data(cpu->dls.pkt) = src;
- break;
- }
+ case 0b001: size = 2; break;
/* SW */
- case 0b010: {
- cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 4);
- *(uint32_t *)packet_data(cpu->dls.pkt) = src;
- break;
- }
+ case 0b010: size = 4; break;
/* SD */
- case 0b011: {
- cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 8);
- *(uint64_t *)packet_data(cpu->dls.pkt) = src;
- break;
- }
+ case 0b011: size = 8; break;
default:
error("unknown width of STORE %x", insn.stype.funct3);
return ENOSUCH;
}
+ struct packet pkt = create_packet(cpu->rcv, addr, size, &src, PACKET_WRITE);
+ cpu->dls = (struct ldst){pkt, LDST_SENT, 0, false};
+ stat ret = SEND(cpu, cpu->dmem, pkt);
+ if (ret == EBUSY) {
+ cpu->dls.state = LDST_BLOCKED;
+ ret = OK;
+ }
+
cpu->pc += 4;
- return write(cpu->dmem, cpu->dls.pkt);
+ return ret;
}
static void finalize_ld(struct simple_riscv64 *cpu)
{
- struct simple_rv64_ldst ld = cpu->dls;
+ struct ldst ld = cpu->dls;
uint64_t val = 0;
- void *data = packet_data(ld.pkt);
- switch (packet_size(ld.pkt)) {
+ switch (packet_convsize(&ld.pkt)) {
case 1:
- if (ld.u) val = *(uint8_t *)data;
- else val = *(int8_t *)data;
+ if (ld.u) val = packet_convu8(&ld.pkt);
+ else val = packet_convi8(&ld.pkt);
break;
- case 2: if (ld.u) val = *(uint16_t *)data;
- else val = *(int16_t *)data;
+ case 2: if (ld.u) val = packet_convu16(&ld.pkt);
+ else val = packet_convi16(&ld.pkt);
break;
- case 4: if (ld.u) val = *(uint32_t *)data;
- else val = *(int32_t *)data;
+ case 4: if (ld.u) val = packet_convi32(&ld.pkt);
+ else val = packet_convu32(&ld.pkt);
break;
- case 8: val = *(uint64_t *)data;
+ case 8: val = packet_convu64(&ld.pkt);
break;
default:
- error("unknown load size %zu", packet_size(ld.pkt));
+ error("unknown load size %zu", packet_convsize(&ld.pkt));
}
set_reg(cpu, ld.reg, val);
@@ -501,58 +506,97 @@ static void finalize_st(struct simple_riscv64 *cpu)
static void finalize_dls(struct simple_riscv64 *cpu)
{
- struct packet *pkt = cpu->dls.pkt;
+ cpu->dls.state = LDST_IDLE;
+ struct packet pkt = cpu->dls.pkt;
- if (packet_type(pkt) == PACKET_READ)
+ if (is_set(&pkt, PACKET_READ))
finalize_ld(cpu);
- else if (packet_type(pkt) == PACKET_WRITE)
+ else if (is_set(&pkt, PACKET_WRITE))
finalize_st(cpu);
else
error("unsupported packet type for simple_riscv64");
-
- destroy_packet(pkt);
- cpu->dls.pkt = NULL;
}
static uint32_t finalize_ils(struct simple_riscv64 *cpu)
{
- uint32_t insn = *(uint32_t *)packet_data(cpu->ils.pkt);
- destroy_packet(cpu->ils.pkt);
- cpu->ils.pkt = NULL;
- return insn;
+ cpu->ils.state = LDST_IDLE;
+ return packet_convu32(&cpu->ils.pkt);
+}
+
+static stat simple_riscv64_receive(struct simple_riscv64 *cpu, struct component *from, struct packet pkt)
+{
+ (void)from;
+
+ if (pkt.to == cpu->rcv) {
+ cpu->dls.pkt = pkt;
+ cpu->dls.state = LDST_DONE;
+ return OK;
+ }
+ else if (pkt.to == cpu->rcv + 64) {
+ cpu->ils.pkt = pkt;
+ cpu->ils.state = LDST_DONE;
+ return OK;
+ }
+ else {
+ error("illegal receive on %s", cpu->component.name);
+ return EBUS;
+ }
}
static stat simple_riscv64_clock(struct simple_riscv64 *cpu)
{
/* there's an active data transfer we should handle */
- if (cpu->dls.pkt) {
- assert(packet_state(cpu->dls.pkt) != PACKET_FAILED);
+ if (cpu->dls.state != LDST_IDLE) {
+ assert(!is_set(&cpu->dls.pkt, PACKET_ERROR));
+
+ if (cpu->dls.state == LDST_BLOCKED) {
+ stat r = SEND(cpu, cpu->dmem, cpu->dls.pkt);
+ if (r == EBUSY)
+ return OK;
- if (packet_state(cpu->dls.pkt) == PACKET_DONE)
+ cpu->dls.state = LDST_SENT;
+ return OK;
+ }
+
+ if (cpu->dls.state == LDST_SENT)
+ return OK;
+
+ if (cpu->dls.state == LDST_DONE) {
finalize_dls(cpu);
- else /* wait for data */
+ cpu->dls.state = LDST_IDLE;
+ }
+ else
return OK;
}
- if (!cpu->ils.pkt) {
- cpu->ils.pkt =
- create_packet(PACKET_READ, cpu->pc, sizeof(uint32_t));
- if (!cpu->ils.pkt)
- return EMEM;
+ if (cpu->ils.state == LDST_BLOCKED) {
+ stat ret = SEND(cpu, cpu->imem, cpu->ils.pkt);
+ if (ret == EBUSY)
+ return OK;
- stat ret = read(cpu->imem, cpu->ils.pkt);
- if (ret)
- return ret;
+ return OK;
}
uint32_t insn = 0;
- if (cpu->ils.pkt) {
- assert(packet_state(cpu->ils.pkt) != PACKET_FAILED);
+ if (cpu->ils.state == LDST_DONE) {
+ assert(!is_set(&cpu->dls.pkt, PACKET_ERROR));
- if (packet_state(cpu->ils.pkt) == PACKET_DONE)
- insn = finalize_ils(cpu);
- else /* wait for instruction */
- return OK;
+ insn = finalize_ils(cpu);
+ cpu->ils.state = LDST_IDLE;
+ }
+
+ if (cpu->ils.state == LDST_IDLE) {
+ cpu->ils.pkt = create_packet(cpu->rcv + 64,
+ cpu->pc,
+ sizeof(uint32_t),
+ NULL,
+ PACKET_READ);
+ cpu->ils.state = LDST_SENT;
+ stat ret = SEND(cpu, cpu->imem, cpu->ils.pkt);
+ if (ret == EBUSY) {
+ cpu->ils.state = LDST_BLOCKED;
+ return ret;
+ }
}
// for now assume little endian emulated and host cpu
@@ -586,23 +630,12 @@ static stat simple_riscv64_clock(struct simple_riscv64 *cpu)
static void simple_riscv64_destroy(struct simple_riscv64 *cpu)
{
- /* oh yeah, will have to think about the name stuff,
- * i.e. how and where to free it, and where to assign it */
destroy(cpu->imem);
-
- if (cpu->imem != cpu->dmem)
- destroy(cpu->dmem);
-
- if (cpu->ils.pkt)
- destroy_packet(cpu->ils.pkt);
-
- if (cpu->dls.pkt)
- destroy_packet(cpu->dls.pkt);
-
+ destroy(cpu->dmem);
free(cpu);
}
-struct component *create_simple_riscv64(uint32_t start_pc,
+struct component *create_simple_riscv64(uint64_t rcv, uint32_t start_pc,
struct component *imem,
struct component *dmem)
{
@@ -610,10 +643,12 @@ struct component *create_simple_riscv64(uint32_t start_pc,
if (!new)
return NULL;
+ new->component.receive = (receive_callback)simple_riscv64_receive;
new->component.clock = (clock_callback)simple_riscv64_clock;
new->component.destroy = (destroy_callback)simple_riscv64_destroy;
new->pc = start_pc;
+ new->rcv = rcv;
new->imem = imem;
new->dmem = dmem;
return (struct component *)new;
diff --git a/src/components/grid/node.c b/src/components/grid/node.c
index 0aed768..57ef7ed 100644
--- a/src/components/grid/node.c
+++ b/src/components/grid/node.c
@@ -5,73 +5,101 @@
* 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 <stdbool.h>
+
#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;
+
+ struct component *send;
+ struct packet pkt;
+ bool busy;
};
-typedef read_callback callback;
+static stat grid_clock(struct grid_node *grid)
+{
+ if (!grid->busy)
+ return OK;
+
+ stat r = SEND(grid, grid->send, grid->pkt);
+ if (r == EBUSY)
+ return OK;
+
+ grid->busy = false;
+ return r;
+}
-static stat grid_route(struct grid_node *grid, struct packet *pkt, callback op)
+static stat grid_receive(struct grid_node *grid, struct component *from, struct packet pkt)
{
- 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->busy)
+ return EBUSY;
- if (grid->u == u && grid->v == v && grid->x == x && grid->y == y)
- return op(grid->lower, pkt);
+ uint8_t u;
+ uint8_t v;
+ uint8_t x;
+ uint8_t y;
+ uint64_t addr = pkt.to;
+ addr_grid(addr, NULL, &x, &y, &u, &v);
+
+ grid->busy = true;
+ grid->pkt = pkt;
+
+ if (grid->u == u && grid->v == v && grid->x == x && grid->y == y) {
+ if (!grid->lower)
+ goto nosuch;
+
+ grid->send = grid->lower;
+ return OK;
+ }
if (grid->u != u || grid->v != v) {
if (!grid->ascend)
- return EBUS;
+ goto nosuch;
- return op(grid->ascend, pkt);
+ grid->send = grid->ascend;
+ return OK;
}
if (y < grid->y) {
if (!grid->down)
- return EBUS;
+ goto nosuch;
- return op(grid->down, pkt);
+ grid->send = grid->down;
+ return OK;
}
if (y > grid->y) {
if (!grid->up)
- return EBUS;
+ goto nosuch;
- return op(grid->up, pkt);
+ grid->send = grid->up;
+ return OK;
}
if (x < grid->x) {
if (!grid->left)
- return EBUS;
+ goto nosuch;
- return op(grid->left, pkt);
+ grid->send = grid->left;
+ return OK;
}
if (x > grid->x) {
if (!grid->right)
return EBUS;
- return op(grid->right, pkt);
+ grid->send = grid->right;
+ return OK;
}
- 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);
+nosuch:
+ grid->send = from;
+ grid->pkt = response(pkt);
+ set_flags(&grid->pkt, PACKET_ERROR);
+ return OK;
}
struct component *create_grid_node(uint8_t u, uint8_t v, uint8_t x, uint8_t y)
@@ -80,13 +108,12 @@ struct component *create_grid_node(uint8_t u, uint8_t v, uint8_t x, uint8_t y)
if (!node)
return NULL;
+ node->component.receive = (receive_callback)grid_receive;
+ node->component.clock = (clock_callback)grid_clock;
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;
}
diff --git a/src/components/grid/router.c b/src/components/grid/router.c
index bdb05c8..63c4011 100644
--- a/src/components/grid/router.c
+++ b/src/components/grid/router.c
@@ -1,3 +1,6 @@
+#include <stdbool.h>
+
+#include <gran/grid/node.h>
#include <gran/grid/router.h>
#include <gran/vec.h>
@@ -12,6 +15,10 @@ struct node_router {
struct component *ascend;
struct vec regions;
uint8_t u, v, x, y;
+
+ struct component *send;
+ struct packet pkt;
+ bool busy;
};
static struct router_region *find_region(struct node_router *router, uint32_t addr)
@@ -26,40 +33,55 @@ static struct router_region *find_region(struct node_router *router, uint32_t ad
return NULL;
}
-static stat router_write(struct node_router *router, struct packet *pkt)
+static stat router_clock(struct node_router *router)
{
- 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 (!router->busy)
+ return OK;
- if (router->u != u || router->v != v || router->x != x || router->y != y)
- return write(router->ascend, pkt);
+ stat r = SEND(router, router->send, router->pkt);
+ if (r == EBUSY)
+ return OK;
- struct router_region *region = find_region(router, addr);
- if (!region)
- return write(router->ascend, pkt);
-
- return write(region->component, pkt);
+ router->busy = false;
+ return OK;
}
-static stat router_read(struct node_router *router, struct packet *pkt)
+static stat router_receive(struct node_router *router, struct component *from, struct packet pkt)
{
- 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 (router->busy)
+ return EBUSY;
+
+ router->busy = true;
- if (router->u != u || router->v != v || router->x != x || router->y != y)
- return read(router->ascend, pkt);
+ uint64_t addr = pkt.to;
+ uint8_t u;
+ uint8_t v;
+ uint8_t x;
+ uint8_t y;
+ addr_grid(addr, NULL, &x, &y, &u, &v);
+
+ router->pkt = pkt;
+
+ if (router->u != u || router->v != v || router->x != x || router->y != y) {
+ if (!router->ascend)
+ goto nosuch;
+
+ router->send = router->ascend;
+ return OK;
+ }
struct router_region *region = find_region(router, addr);
if (!region)
- return read(router->ascend, pkt);
+ goto nosuch;
- return read(region->component, pkt);
+ router->send = region->component;
+ return OK;
+
+nosuch:
+ router->send = from;
+ router->pkt = response(pkt);
+ set_flags(&router->pkt, PACKET_ERROR);
+ return OK;
}
struct component *create_node_router(uint8_t u, uint8_t v, uint8_t x, uint8_t y)
@@ -73,8 +95,8 @@ struct component *create_node_router(uint8_t u, uint8_t v, uint8_t x, uint8_t y)
router->x = x;
router->y = y;
- router->component.write = (write_callback)router_write;
- router->component.read = (read_callback)router_read;
+ router->component.receive = (receive_callback)router_receive;
+ router->component.clock = (clock_callback)router_clock;
router->regions = vec_create(sizeof(struct router_region));
return (struct component *)router;
diff --git a/src/components/mem/simple_mem.c b/src/components/mem/simple_mem.c
index bb9dd40..e435ea5 100644
--- a/src/components/mem/simple_mem.c
+++ b/src/components/mem/simple_mem.c
@@ -3,38 +3,57 @@
#include <string.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <gran/mem/simple_mem.h>
struct simple_mem {
struct component component;
+ struct component *send;
+ struct packet pkt;
+ bool busy;
+
size_t size;
- char buf[];
+ uint8_t buf[];
};
-static stat simple_mem_write(struct simple_mem *mem, struct packet *pkt)
+static stat simple_mem_clock(struct simple_mem *mem)
{
- uintptr_t offset = packet_addr(pkt) % mem->size;
- if (offset + packet_size(pkt) > mem->size) {
- error("write outside memory");
- return ESIZE;
- }
+ if (mem->busy)
+ return OK;
+
+ stat r = SEND(mem, mem->send, mem->pkt);
+ if (r == EBUSY)
+ return OK;
- memcpy(mem->buf + offset, packet_data(pkt), packet_size(pkt));
- packet_set_state(pkt, PACKET_DONE);
+ mem->busy = false;
return OK;
}
-static stat simple_mem_read(struct simple_mem *mem, struct packet *pkt)
+static stat simple_mem_receive(struct simple_mem *mem, struct component *from, struct packet pkt)
{
- uintptr_t offset = packet_addr(pkt) % mem->size;
- if (offset + packet_size(pkt) > mem->size) {
+ if (mem->busy)
+ return EBUSY;
+
+ mem->send = from;
+
+ uint64_t offset = pkt.to % mem->size;
+ if (offset >= mem->size) {
error("read outside memory");
- return ESIZE;
+ mem->pkt = response(pkt);
+ set_flags(&mem->pkt, PACKET_ERROR);
+ return OK;
}
- memcpy(packet_data(pkt), mem->buf + offset, packet_size(pkt));
- packet_set_state(pkt, PACKET_DONE);
+ if (is_set(&pkt, PACKET_READ))
+ checked_copyto(&pkt, mem->buf + offset);
+ else if (is_set(&pkt, PACKET_WRITE))
+ checked_copyfrom(&pkt, mem->buf + offset);
+ else
+ abort();
+
+ mem->pkt = response(pkt);
+ set_flags(&mem->pkt, PACKET_DONE);
return OK;
}
@@ -45,8 +64,8 @@ struct component *create_simple_mem(size_t size)
return NULL;
new->size = size;
- new->component.write = (write_callback)simple_mem_write;
- new->component.read = (read_callback)simple_mem_read;
+ new->component.receive = (receive_callback)simple_mem_receive;
+ new->component.clock = (clock_callback)simple_mem_clock;
return (struct component *)new;
}
diff --git a/src/components/uart/simple_uart.c b/src/components/uart/simple_uart.c
index 5c97ccd..1528a70 100644
--- a/src/components/uart/simple_uart.c
+++ b/src/components/uart/simple_uart.c
@@ -3,17 +3,42 @@
struct simple_uart {
struct component component;
+
+ struct component *send;
+ struct packet pkt;
+ bool busy;
};
-static stat simple_uart_write(struct simple_uart *uart, struct packet *pkt)
+static stat simple_uart_clock(struct simple_uart *uart)
{
- (void)uart;
- size_t size = packet_size(pkt);
- if (size != 1)
- return EBUS;
+ if (!uart->busy)
+ return OK;
+
+ stat r = SEND(uart, uart->send, uart->pkt);
+ if (r == EBUSY)
+ return OK;
+
+ uart->busy = false;
+ return OK;
+}
+
+static stat simple_uart_receive(struct simple_uart *uart, struct component *from, struct packet pkt)
+{
+ if (uart->busy)
+ return EBUSY;
+
+ uart->busy = true;
+ uart->send = from;
+ uart->pkt = response(pkt);
+
+ size_t size = packet_convsize(&pkt);
+ if (size != 1) {
+ set_flags(&uart->pkt, PACKET_ERROR);
+ return OK;
+ }
- putchar(*(uint8_t *)packet_data(pkt));
- packet_set_state(pkt, PACKET_DONE);
+ putchar(packet_convu8(&pkt));
+ set_flags(&uart->pkt, PACKET_DONE);
return OK;
}
@@ -23,6 +48,7 @@ struct component *create_simple_uart()
if (!uart)
return NULL;
- uart->component.write = (write_callback)simple_uart_write;
+ uart->component.receive = (receive_callback)simple_uart_receive;
+ uart->component.clock = (clock_callback)simple_uart_clock;
return (struct component *)uart;
}
diff --git a/src/packet.c b/src/packet.c
deleted file mode 100644
index 9442307..0000000
--- a/src/packet.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* SPDX-License-Identifier: copyleft-next-0.3.1 */
-/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
-
-#include <gran/packet.h>
-#include <stdlib.h>
-#include <assert.h>
-
-struct packet {
- enum packet_state state;
- enum packet_type type;
-
- uintptr_t addr;
- size_t size;
- void *data;
-};
-
-
-struct packet *create_packet(enum packet_type type, uintptr_t addr, size_t size)
-{
- struct packet *pkt = malloc(sizeof(struct packet) + size);
- if (!pkt)
- return NULL;
-
- pkt->state = PACKET_INIT;
- pkt->type = type;
- pkt->addr = addr;
- pkt->size = size;
- pkt->data = pkt + 1;
- return pkt;
-}
-
-struct packet *create_packet_with(enum packet_type type, uintptr_t addr,
- size_t size, void *data)
-{
- struct packet *pkt = malloc(sizeof(struct packet));
- if (!pkt)
- return NULL;
-
- pkt->state = PACKET_INIT;
- pkt->type = type;
- pkt->addr = addr;
- pkt->size = size;
- pkt->data = data;
- return pkt;
-}
-
-struct packet *reuse_packet(struct packet *pkt, enum packet_type type,
- uintptr_t addr, size_t size, void *data)
-{
- assert(pkt->state == PACKET_DONE);
- pkt->state = PACKET_INIT;
- pkt->type = type;
- pkt->addr = addr;
- pkt->size = size;
- pkt->data = data;
- return pkt;
-}
-
-enum packet_type packet_type(struct packet *pkt)
-{
- return pkt->type;
-}
-
-enum packet_state packet_state(struct packet *pkt)
-{
- return pkt->state;
-}
-
-void packet_set_state(struct packet *pkt, enum packet_state state)
-{
- pkt->state = state;
-}
-
-size_t packet_size(struct packet *pkt)
-{
- return pkt->size;
-}
-
-uintptr_t packet_addr(struct packet *pkt)
-{
- return pkt->addr;
-}
-
-void *packet_data(struct packet *pkt)
-{
- return pkt->data;
-}
-
-void destroy_packet(struct packet *pkt)
-{
- free(pkt);
-}
diff --git a/src/snoop.c b/src/snoop.c
deleted file mode 100644
index 23970a8..0000000
--- a/src/snoop.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: copyleft-next-0.3.1 */
-/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
-
-#include <stdlib.h>
-
-#include <gran/snoop.h>
-
-struct snoop {
- enum snoop_state state;
- uintptr_t addr;
- size_t size;
-};
-
-struct snoop *create_snoop(uintptr_t addr, size_t size)
-{
- struct snoop *snoop = calloc(1, sizeof(struct snoop));
-
- snoop->state = SNOOP_UNANSWERED;
- snoop->addr = addr;
- snoop->size = size;
- return snoop;
-}
-
-enum snoop_state snoop_state(struct snoop *snoop)
-{
- return snoop->state;
-}
-
-uintptr_t snoop_addr(struct snoop *snoop)
-{
- return snoop->addr;
-}
-
-size_t snoop_size(struct snoop *snoop)
-{
- return snoop->size;
-}
-
-void destroy_snoop(struct snoop *snoop)
-{
- free(snoop);
-}