From 9366a2948399007b227a7130e8ce580eb3aacb24 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 10 Jan 2016 13:04:55 +0000 Subject: [PATCH] Implement core device storage (fixes #219). --- artiq/coredevice/core.py | 24 ++++++++++++ artiq/gateware/amp/kernel_cpu.py | 2 +- artiq/runtime/Makefile | 10 +++-- artiq/runtime/kloader.h | 4 +- artiq/runtime/ksupport.c | 53 ++++++++++++++++++++++++++ artiq/runtime/ksupport.h | 8 ++++ artiq/runtime/ksupport.ld | 7 ++-- artiq/runtime/main.c | 4 ++ artiq/runtime/messages.h | 28 ++++++++++++++ artiq/runtime/runtime.ld | 6 ++- artiq/runtime/session.c | 64 ++++++++++++++++++++++++++++++++ 11 files changed, 198 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 2be0ccac2..7d0b379c2 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -37,6 +37,18 @@ class CompileError(Exception): def rtio_get_counter() -> TInt64: raise NotImplementedError("syscall not simulated") +@syscall +def cache_get(TStr) -> TList(TInt32): + raise NotImplementedError("syscall not simulated") + +@syscall +def cache_put(TStr, TList(TInt32)): + raise NotImplementedError("syscall not simulated") + +@syscall +def cache_clear(TStr): + raise NotImplementedError("syscall not simulated") + class Core: """Core device driver. @@ -108,3 +120,15 @@ class Core: min_now = rtio_get_counter() + 125000 if now_mu() < min_now: at_mu(min_now) + + @kernel + def get_cache(self, key): + return cache_get(key) + + @kernel + def put_cache(self, key, value): + return cache_put(key, value) + + @kernel + def clear_cache(self, key): + return cache_clear(key) diff --git a/artiq/gateware/amp/kernel_cpu.py b/artiq/gateware/amp/kernel_cpu.py index 6aca00d32..b8aa29803 100644 --- a/artiq/gateware/amp/kernel_cpu.py +++ b/artiq/gateware/amp/kernel_cpu.py @@ -7,7 +7,7 @@ from misoc.integration.soc_core import mem_decoder class KernelCPU(Module): def __init__(self, platform, - exec_address=0x40800000, + exec_address=0x42000000, main_mem_origin=0x40000000, l2_size=8192): self._reset = CSRStorage(reset=1) diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index 3b81d5af8..460f1275c 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -9,7 +9,8 @@ OBJECTS := isr.o clock.o rtiocrg.o flash_storage.o mailbox.o \ OBJECTS_KSUPPORT := ksupport.o artiq_personality.o mailbox.o \ bridge.o rtio.o ttl.o dds.o -CFLAGS += -I$(MISOC_DIRECTORY)/software/include/dyld \ +CFLAGS += -I$(LIBALLOC_DIRECTORY) \ + -I$(MISOC_DIRECTORY)/software/include/dyld \ -I$(LIBDYLD_DIRECTORY)/include \ -I$(LIBUNWIND_DIRECTORY) \ -I$(LIBUNWIND_DIRECTORY)/../unwinder/include \ @@ -31,10 +32,11 @@ runtime.elf: $(OBJECTS) -N -o $@ \ ../libbase/crt0-$(CPU).o \ $(OBJECTS) \ - -L../libbase \ -L../libcompiler_rt \ + -L../libbase \ + -L../liballoc \ -L../liblwip \ - -lbase -lcompiler_rt -llwip + -lbase -lcompiler_rt -lalloc -llwip @chmod -x $@ ksupport.elf: $(OBJECTS_KSUPPORT) @@ -48,7 +50,7 @@ ksupport.elf: $(OBJECTS_KSUPPORT) -L../libcompiler_rt \ -L../libunwind \ -L../libdyld \ - -lbase -lcompiler_rt -lunwind -ldyld + -lbase -lcompiler_rt -ldyld -lunwind @chmod -x $@ ksupport_data.o: ksupport.elf diff --git a/artiq/runtime/kloader.h b/artiq/runtime/kloader.h index 92f353df0..fffcdb36a 100644 --- a/artiq/runtime/kloader.h +++ b/artiq/runtime/kloader.h @@ -3,8 +3,8 @@ #include "artiq_personality.h" -#define KERNELCPU_EXEC_ADDRESS 0x40800000 -#define KERNELCPU_PAYLOAD_ADDRESS 0x40820000 +#define KERNELCPU_EXEC_ADDRESS 0x42000000 +#define KERNELCPU_PAYLOAD_ADDRESS 0x42020000 #define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024) #define KSUPPORT_HEADER_SIZE 0x80 diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index f67509c1b..af2610413 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -122,6 +122,10 @@ static const struct symbol runtime_exports[] = { {"dds_batch_exit", &dds_batch_exit}, {"dds_set", &dds_set}, + {"cache_get", &cache_get}, + {"cache_put", &cache_put}, + {"cache_clear", &cache_clear}, + /* end */ {NULL, NULL} }; @@ -444,6 +448,55 @@ void attribute_writeback(void *utypes) { } } +struct artiq_list cache_get(const char *key) +{ + struct msg_cache_get_request request; + struct msg_cache_get_reply *reply; + + request.type = MESSAGE_TYPE_CACHE_GET_REQUEST; + request.key = key; + mailbox_send_and_wait(&request); + + reply = mailbox_wait_and_receive(); + if(reply->type != MESSAGE_TYPE_CACHE_GET_REPLY) { + log("Malformed MESSAGE_TYPE_CACHE_GET_REQUEST reply type %d", + reply->type); + while(1); + } + + return (struct artiq_list) { reply->length, reply->elements }; +} + +void cache_put(const char *key, struct artiq_list value) +{ + struct msg_cache_put_request request; + struct msg_cache_put_reply *reply; + + request.type = MESSAGE_TYPE_CACHE_PUT_REQUEST; + request.key = key; + request.elements = value.elements; + request.length = value.length; + mailbox_send_and_wait(&request); + + reply = mailbox_wait_and_receive(); + if(reply->type != MESSAGE_TYPE_CACHE_PUT_REPLY) { + log("Malformed MESSAGE_TYPE_CACHE_PUT_REQUEST reply type %d", + reply->type); + while(1); + } + + if(!reply->succeeded) { + artiq_raise_from_c("CacheError", + "cannot put into a busy cache row", + 0, 0, 0); + } +} + +void cache_clear(const char *key) +{ + cache_put(key, (struct artiq_list) { 0, NULL }); +} + void lognonl(const char *fmt, ...) { struct msg_log request; diff --git a/artiq/runtime/ksupport.h b/artiq/runtime/ksupport.h index 88dc7e2a0..144392a15 100644 --- a/artiq/runtime/ksupport.h +++ b/artiq/runtime/ksupport.h @@ -1,12 +1,20 @@ #ifndef __KSTARTUP_H #define __KSTARTUP_H +struct artiq_list { + int32_t length; + int32_t *elements; +}; + long long int now_init(void); void now_save(long long int now); int watchdog_set(int ms); void watchdog_clear(int id); void send_rpc(int service, const char *tag, ...); int recv_rpc(void *slot); +struct artiq_list cache_get(const char *key); +void cache_put(const char *key, struct artiq_list value); +void cache_clear(const char *key); void lognonl(const char *fmt, ...); void log(const char *fmt, ...); diff --git a/artiq/runtime/ksupport.ld b/artiq/runtime/ksupport.ld index 016b9d008..da231b69b 100644 --- a/artiq/runtime/ksupport.ld +++ b/artiq/runtime/ksupport.ld @@ -3,11 +3,12 @@ ENTRY(_start) INCLUDE generated/regions.ld -/* First 8M of main memory are reserved for runtime code/data - * then comes kernel memory. First 128K of kernel memory are for support code. +/* First 32M of main memory are reserved for runtime + * code/data/heap, then comes kernel memory. + * First 128K of kernel memory are for support code. */ MEMORY { - ksupport (RWX) : ORIGIN = 0x40800000, LENGTH = 0x20000 + ksupport (RWX) : ORIGIN = 0x42000000, LENGTH = 0x20000 } /* On AMP systems, kernel stack is at the end of main RAM, diff --git a/artiq/runtime/main.c b/artiq/runtime/main.c index 2e8f7f15e..008a18b71 100644 --- a/artiq/runtime/main.c +++ b/artiq/runtime/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -263,6 +264,8 @@ static int check_test_mode(void) return 0; } +extern void _fheap, _eheap; + int main(void) { irq_setmask(0); @@ -271,6 +274,7 @@ int main(void) puts("ARTIQ runtime built "__DATE__" "__TIME__"\n"); + alloc_give(&_fheap, &_eheap - &_fheap); clock_init(); rtiocrg_init(); puts("Press 't' to enter test mode..."); diff --git a/artiq/runtime/messages.h b/artiq/runtime/messages.h index 2d055763e..c3a7c0a11 100644 --- a/artiq/runtime/messages.h +++ b/artiq/runtime/messages.h @@ -3,6 +3,7 @@ #include #include +#include enum { MESSAGE_TYPE_LOAD_REPLY, @@ -18,6 +19,10 @@ enum { MESSAGE_TYPE_RPC_RECV_REQUEST, MESSAGE_TYPE_RPC_RECV_REPLY, MESSAGE_TYPE_RPC_BATCH, + MESSAGE_TYPE_CACHE_GET_REQUEST, + MESSAGE_TYPE_CACHE_GET_REPLY, + MESSAGE_TYPE_CACHE_PUT_REQUEST, + MESSAGE_TYPE_CACHE_PUT_REPLY, MESSAGE_TYPE_LOG, MESSAGE_TYPE_BRG_READY, @@ -105,6 +110,29 @@ struct msg_rpc_batch { void *ptr; }; +struct msg_cache_get_request { + int type; + const char *key; +}; + +struct msg_cache_get_reply { + int type; + size_t length; + int32_t *elements; +}; + +struct msg_cache_put_request { + int type; + const char *key; + size_t length; + int32_t *elements; +}; + +struct msg_cache_put_reply { + int type; + int succeeded; +}; + struct msg_log { int type; const char *fmt; diff --git a/artiq/runtime/runtime.ld b/artiq/runtime/runtime.ld index ad575a097..011fda2a3 100644 --- a/artiq/runtime/runtime.ld +++ b/artiq/runtime/runtime.ld @@ -7,7 +7,7 @@ INCLUDE generated/regions.ld * ld does not allow this expression here. */ MEMORY { - runtime : ORIGIN = 0x40000000, LENGTH = 0x800000 /* 8M */ + runtime : ORIGIN = 0x40000000, LENGTH = 0x2000000 /* 32M */ } /* Kernel memory space start right after the runtime, @@ -65,5 +65,7 @@ SECTIONS *(.eh_frame) } - _heapstart = .; + _fheap = .; + . += 0x1800000; + _eheap = .; } diff --git a/artiq/runtime/session.c b/artiq/runtime/session.c index c6e215ace..fddf41781 100644 --- a/artiq/runtime/session.c +++ b/artiq/runtime/session.c @@ -908,6 +908,16 @@ static int send_rpc_request(int service, const char *tag, va_list args) return 1; } +struct cache_row { + struct cache_row *next; + char *key; + size_t length; + int32_t *elements; + int borrowed; +}; + +static struct cache_row *cache; + /* assumes output buffer is empty when called */ static int process_kmsg(struct msg_base *umsg) { @@ -984,6 +994,60 @@ static int process_kmsg(struct msg_base *umsg) break; } + case MESSAGE_TYPE_CACHE_GET_REQUEST: { + struct msg_cache_get_request *request = (struct msg_cache_get_request *)umsg; + struct msg_cache_get_reply reply; + + reply.type = MESSAGE_TYPE_CACHE_GET_REPLY; + reply.length = 0; + reply.elements = NULL; + + for(struct cache_row *iter = cache; iter; iter = iter->next) { + if(!strcmp(iter->key, request->key)) { + reply.length = iter->length; + reply.elements = iter->elements; + iter->borrowed = 1; + break; + } + } + + mailbox_send(&reply); + } + + case MESSAGE_TYPE_CACHE_PUT_REQUEST: { + struct msg_cache_put_request *request = (struct msg_cache_put_request *)umsg; + struct msg_cache_put_reply reply; + + reply.type = MESSAGE_TYPE_CACHE_PUT_REPLY; + + struct cache_row *row = NULL; + for(struct cache_row *iter = cache; iter; iter = iter->next) { + if(!strcmp(iter->key, request->key)) { + free(iter->elements); + row = iter; + break; + } + } + + if(!row) { + struct cache_row *row = calloc(1, sizeof(struct cache_row)); + row->key = calloc(strlen(request->key) + 1, 1); + strcpy(row->key, request->key); + } + + if(!row->borrowed) { + row->length = request->length; + row->elements = calloc(row->length, sizeof(int32_t)); + memcpy(row->elements, request->elements, + sizeof(int32_t) * row->length); + reply.succeeded = 1; + } else { + reply.succeeded = 0; + } + + mailbox_send(&reply); + } + default: { log("Received invalid message type %d from kernel CPU", umsg->type);