aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-04-30 16:03:55 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2023-04-30 16:03:55 +0300
commit191eaea25cf569ad9c5fb12b8755ae6400750e58 (patch)
treea0cd14f4a772da01b445355eb35eec54616d01ec /src
downloadgran-191eaea25cf569ad9c5fb12b8755ae6400750e58.tar.gz
gran-191eaea25cf569ad9c5fb12b8755ae6400750e58.zip
initial
Diffstat (limited to 'src')
-rw-r--r--src/clock_domain.c123
-rw-r--r--src/components/bus/simple_bus.c154
-rw-r--r--src/components/bus/source.mk1
-rw-r--r--src/components/mem/simple_mem.c48
-rw-r--r--src/components/mem/source.mk1
-rw-r--r--src/components/source.mk1
-rw-r--r--src/main.c4
-rw-r--r--src/root.c65
-rw-r--r--src/source.mk6
9 files changed, 403 insertions, 0 deletions
diff --git a/src/clock_domain.c b/src/clock_domain.c
new file mode 100644
index 0000000..825cf0d
--- /dev/null
+++ b/src/clock_domain.c
@@ -0,0 +1,123 @@
+#include <stdlib.h>
+#include <threads.h>
+#include <assert.h>
+
+#include <gran/clock_domain.h>
+
+#define MAX_COMPONENTS 512
+
+struct clock_domain {
+ size_t num_components;
+ struct component *components[MAX_COMPONENTS];
+ struct clock_time time;
+ tick period;
+
+ stat ret;
+
+ mtx_t mtx;
+};
+
+void advance_clock(struct clock_domain *clk)
+{
+ tick fs = clk->time.fs + clk->period;
+ while (fs >= SEC(1)) {
+ clk->time.s++;
+ fs -= SEC(1);
+ }
+ clk->time.fs = fs;
+}
+
+struct clock_domain *create_clock_domain(tick period)
+{
+ struct clock_domain *clk = calloc(1, sizeof(struct clock_domain));
+ if (!clk)
+ return NULL;
+
+ clk->period = period;
+ mtx_init(&clk->mtx, mtx_plain);
+
+ return clk;
+}
+
+void destroy_clock_domain(struct clock_domain *clk)
+{
+ for (size_t i = 0; i < clk->num_components; ++i)
+ destroy(clk->components[i]);
+
+ free(clk);
+}
+
+stat clock_domain_add(struct clock_domain *clk, struct component *component)
+{
+ clk->components[clk->num_components++] = 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 clock_domain_tick(struct clock_domain *clk)
+{
+ /* openmp on gcc apparently doesn't really handle if conditionals
+ * particularly efficiently, so it's faster to do it manually */
+ if (clk->num_components == 1) {
+ clocked_component_tick(clk, clk->components[0]);
+ advance_clock(clk);
+ return clk->ret;
+ }
+
+#pragma omp parallel for
+ for (size_t i = 0; i < clk->num_components; ++i)
+ clocked_component_tick(clk, clk->components[i]);
+
+ advance_clock(clk);
+ return clk->ret;
+}
+
+bool eq_time(struct clock_time a, struct clock_time b)
+{
+ return a.s == b.s && a.fs == b.fs;
+}
+
+bool lt_time(struct clock_time a, struct clock_time b)
+{
+ if (a.s == b.s)
+ return a.fs < b.fs;
+
+ return a.s < b.s;
+}
+
+bool le_time(struct clock_time a, struct clock_time b)
+{
+ if (a.s == b.s)
+ return a.fs == b.fs || a.fs < b.fs;
+
+ return a.s < b.s;
+}
+
+struct clock_time max_time(struct clock_time a, struct clock_time b)
+{
+ if (lt_time(a, b))
+ return b;
+
+ return a;
+}
+
+struct clock_time domain_time(struct clock_domain *clk)
+{
+ assert(clk);
+ return clk->time;
+}
diff --git a/src/components/bus/simple_bus.c b/src/components/bus/simple_bus.c
new file mode 100644
index 0000000..23a6bc2
--- /dev/null
+++ b/src/components/bus/simple_bus.c
@@ -0,0 +1,154 @@
+#include <threads.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <gran/common.h>
+#include <gran/component.h>
+
+#include <gran/components/bus/simple_bus.h>
+
+struct mem_region {
+ uintptr_t addr;
+ size_t size;
+ struct component *component;
+ struct mem_region *next;
+};
+
+struct simple_bus {
+ struct component component;
+ mtx_t lock;
+
+ struct mem_region *mem_regions;
+};
+
+static struct mem_region *find_mem_region(struct simple_bus *bus,
+ uintptr_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;
+ }
+
+ return NULL;
+}
+
+static stat add_mem_region(struct simple_bus *bus, struct mem_region *new)
+{
+ if (!bus->mem_regions) {
+ bus->mem_regions = new;
+ 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;
+ }
+
+ new->next = bus->mem_regions;
+ bus->mem_regions = new;
+ return OK;
+}
+
+static stat simple_bus_write(struct simple_bus *bus, uintptr_t addr,
+ size_t size, char *buf)
+{
+ /* 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, addr);
+ if (!mem_region) {
+ warn("nothing to write on bus %s at %" PRIuPTR,
+ bus->component.name, addr);
+ return EBUS;
+ }
+
+ stat ret = write(mem_region->component, addr, size, buf);
+
+ mtx_unlock(&bus->lock);
+ return ret;
+}
+
+static stat simple_bus_read(struct simple_bus *bus, uintptr_t addr, size_t size,
+ char *buf)
+{
+ /* 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, addr);
+ if (!mem_region) {
+ warn("nothing to read on bus %s at %" PRIuPTR,
+ bus->component.name, addr);
+ return EBUS;
+ }
+
+ stat ret = read(mem_region->component, addr, size, buf);
+
+ mtx_unlock(&bus->lock);
+ return ret;
+}
+
+static stat simple_bus_swap(struct simple_bus *bus, uintptr_t addr,
+ size_t wsize, char *wbuf, size_t rsize, char *rbuf)
+{
+ if (mtx_trylock(&bus->lock) != thrd_success)
+ return EBUSY;
+
+ struct mem_region *mem_region = find_mem_region(bus, addr);
+ if (!mem_region) {
+ warn("nothing to swap on bus %s at %" PRIuPTR,
+ bus->component.name, addr);
+ return EBUS;
+ }
+
+ stat ret = swap(mem_region->component, addr, wsize, wbuf, rsize, rbuf);
+
+ mtx_unlock(&bus->lock);
+ return ret;
+}
+
+struct component *create_simple_bus()
+{
+ struct simple_bus *bus = calloc(1, sizeof(struct 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;
+
+ mtx_init(&bus->lock, mtx_plain);
+ return (struct component *)bus;
+}
+
+stat simple_bus_add(struct component *bus, struct component *component,
+ uintptr_t addr, size_t size)
+{
+ struct mem_region *new = calloc(1, sizeof(struct mem_region));
+ if (!new)
+ return ENOMEM;
+
+ new->addr = addr;
+ new->size = size;
+ new->component = component;
+
+ if (add_mem_region((struct simple_bus *)bus, new)) {
+ free(new);
+ return EEXISTS;
+ }
+
+ return OK;
+}
diff --git a/src/components/bus/source.mk b/src/components/bus/source.mk
new file mode 100644
index 0000000..98a10b6
--- /dev/null
+++ b/src/components/bus/source.mk
@@ -0,0 +1 @@
+SOURCES += src/components/bus/simple_bus.c
diff --git a/src/components/mem/simple_mem.c b/src/components/mem/simple_mem.c
new file mode 100644
index 0000000..bea68ed
--- /dev/null
+++ b/src/components/mem/simple_mem.c
@@ -0,0 +1,48 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include <gran/components/mem/simple_mem.h>
+
+struct simple_mem {
+ struct component component;
+ size_t size;
+ char buf[];
+};
+
+static stat simple_mem_write(struct simple_mem *mem, uintptr_t addr,
+ size_t size, char *buf)
+{
+ uintptr_t offset = addr % mem->size;
+ if (offset + size > mem->size) {
+ error("write outside memory");
+ return ESIZE;
+ }
+
+ memcpy(mem->buf + offset, buf, size);
+ return OK;
+}
+
+static stat simple_mem_read(struct simple_mem *mem, uintptr_t addr, size_t size,
+ char *buf)
+{
+ uintptr_t offset = addr % mem->size;
+ if (offset + size > mem->size) {
+ error("read outside memory");
+ return ESIZE;
+ }
+
+ memcpy(buf, mem->buf + offset, size);
+ return OK;
+}
+
+struct component *create_simple_mem(size_t size)
+{
+ struct simple_mem *new = calloc(1, sizeof(struct simple_mem) + size);
+ if (!new)
+ return NULL;
+
+ new->size = size;
+ new->component.write = (write_callback)simple_mem_write;
+ new->component.read = (read_callback)simple_mem_read;
+ return (struct component *)new;
+}
diff --git a/src/components/mem/source.mk b/src/components/mem/source.mk
new file mode 100644
index 0000000..9c339ba
--- /dev/null
+++ b/src/components/mem/source.mk
@@ -0,0 +1 @@
+SOURCES += src/components/mem/simple_mem.c
diff --git a/src/components/source.mk b/src/components/source.mk
new file mode 100644
index 0000000..c45f391
--- /dev/null
+++ b/src/components/source.mk
@@ -0,0 +1 @@
+include src/components/*/source.mk
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..149f017
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,4 @@
+int main(int argc, char **argv)
+{
+
+}
diff --git a/src/root.c b/src/root.c
new file mode 100644
index 0000000..4324437
--- /dev/null
+++ b/src/root.c
@@ -0,0 +1,65 @@
+#include <stdlib.h>
+
+#include <gran/root.h>
+#include <gran/clock_domain.h>
+
+#define MAX_DOMAINS 512
+
+struct gran_root {
+ size_t num_domains;
+ struct clock_domain *(domains[MAX_DOMAINS]);
+};
+
+struct gran_root *create_root()
+{
+ return calloc(1, sizeof(struct gran_root));
+}
+
+stat root_add_clock(struct gran_root *root, struct clock_domain *clk)
+{
+ if (root->num_domains == MAX_DOMAINS) {
+ error("too many clock domains");
+ return ESIZE;
+ }
+
+ root->domains[root->num_domains++] = clk;
+ return OK;
+}
+
+static struct clock_domain *most_delayed_domain(struct gran_root *root)
+{
+ struct clock_domain *min = root->domains[0];
+
+ for (size_t i = 1; i < root->num_domains; ++i) {
+ struct clock_domain *cur = root->domains[i];
+ if (lt_time(domain_time(cur), domain_time(min)))
+ min = cur;
+ }
+
+ return min;
+}
+
+stat root_run(struct gran_root *root)
+{
+ if (root->num_domains == 0) {
+ info("no clock domains added to root, exiting");
+ return OK;
+ }
+
+ stat ret = OK;
+ while (ret == OK)
+ ret = clock_domain_tick(most_delayed_domain(root));
+
+ if (ret == DONE)
+ return OK;
+
+ return ret;
+}
+
+void destroy_root(struct gran_root *root)
+{
+ for (size_t i = 0; i < root->num_domains; ++i)
+ destroy_clock_domain(root->domains[i]);
+
+ free(root);
+}
diff --git a/src/source.mk b/src/source.mk
new file mode 100644
index 0000000..db585ee
--- /dev/null
+++ b/src/source.mk
@@ -0,0 +1,6 @@
+include src/components/source.mk
+
+# everything except main
+SRC_LOCAL != echo src/*.c | sed 's|src/main.c||g'
+SOURCES += $(SRC_LOCAL)
+MAIN_SRC = src/main.c