aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-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
5 files changed, 205 insertions, 0 deletions
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