From 191eaea25cf569ad9c5fb12b8755ae6400750e58 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sun, 30 Apr 2023 16:03:55 +0300 Subject: initial --- src/clock_domain.c | 123 ++++++++++++++++++++++++++++++++ src/components/bus/simple_bus.c | 154 ++++++++++++++++++++++++++++++++++++++++ src/components/bus/source.mk | 1 + src/components/mem/simple_mem.c | 48 +++++++++++++ src/components/mem/source.mk | 1 + src/components/source.mk | 1 + src/main.c | 4 ++ src/root.c | 65 +++++++++++++++++ src/source.mk | 6 ++ 9 files changed, 403 insertions(+) create mode 100644 src/clock_domain.c create mode 100644 src/components/bus/simple_bus.c create mode 100644 src/components/bus/source.mk create mode 100644 src/components/mem/simple_mem.c create mode 100644 src/components/mem/source.mk create mode 100644 src/components/source.mk create mode 100644 src/main.c create mode 100644 src/root.c create mode 100644 src/source.mk (limited to 'src') 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 +#include +#include + +#include + +#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 +#include +#include + +#include +#include + +#include + +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 +#include + +#include + +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 + +#include +#include + +#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 -- cgit v1.3