Merge branch 'master' of github.com:m-labs/artiq

This commit is contained in:
Sebastien Bourdeauducq 2016-01-13 14:42:18 -07:00
commit 79986791bc
20 changed files with 345 additions and 67 deletions

View File

@ -97,6 +97,7 @@ class Target:
llpassmgrbuilder = llvm.create_pass_manager_builder() llpassmgrbuilder = llvm.create_pass_manager_builder()
llpassmgrbuilder.opt_level = 2 # -O2 llpassmgrbuilder.opt_level = 2 # -O2
llpassmgrbuilder.size_level = 1 # -Os llpassmgrbuilder.size_level = 1 # -Os
llpassmgrbuilder.inlining_threshold = 75 # -Os threshold
llpassmgr = llvm.create_module_pass_manager() llpassmgr = llvm.create_module_pass_manager()
llpassmgrbuilder.populate(llpassmgr) llpassmgrbuilder.populate(llpassmgr)
@ -147,6 +148,9 @@ class Target:
return results["output"].read() return results["output"].read()
def symbolize(self, library, addresses): def symbolize(self, library, addresses):
if addresses == []:
return []
# Addresses point one instruction past the jump; offset them back by 1. # Addresses point one instruction past the jump; offset them back by 1.
offset_addresses = [hex(addr - 1) for addr in addresses] offset_addresses = [hex(addr - 1) for addr in addresses]
with RunTool([self.triple + "-addr2line", "--functions", "--inlines", with RunTool([self.triple + "-addr2line", "--functions", "--inlines",

View File

@ -320,7 +320,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
return self.append(ir.Closure(func, self.current_env)) return self.append(ir.Closure(func, self.current_env))
def visit_FunctionDefT(self, node, in_class=None): def visit_FunctionDefT(self, node, in_class=None):
func = self.visit_function(node, is_lambda=False, is_internal=len(self.name) > 2) func = self.visit_function(node, is_lambda=False,
is_internal=len(self.name) > 0 or '.' in node.name)
if in_class is None: if in_class is None:
self._set_local(node.name, func) self._set_local(node.name, func)
else: else:

View File

@ -176,6 +176,7 @@ class LLVMIRGenerator:
self.llobject_map = {} self.llobject_map = {}
self.phis = [] self.phis = []
self.debug_info_emitter = DebugInfoEmitter(self.llmodule) self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
self.empty_metadata = self.llmodule.add_metadata([])
def needs_sret(self, lltyp, may_be_large=True): def needs_sret(self, lltyp, may_be_large=True):
if isinstance(lltyp, ll.VoidType): if isinstance(lltyp, ll.VoidType):
@ -190,8 +191,13 @@ class LLVMIRGenerator:
and len(lltyp.elements) <= 2: and len(lltyp.elements) <= 2:
return not any([self.needs_sret(elt, may_be_large=False) for elt in lltyp.elements]) return not any([self.needs_sret(elt, may_be_large=False) for elt in lltyp.elements])
else: else:
assert isinstance(lltyp, ll.Type)
return True return True
def has_sret(self, functy):
llretty = self.llty_of_type(functy.ret, for_return=True)
return self.needs_sret(llretty)
def llty_of_type(self, typ, bare=False, for_return=False): def llty_of_type(self, typ, bare=False, for_return=False):
typ = typ.find() typ = typ.find()
if types.is_tuple(typ): if types.is_tuple(typ):
@ -218,22 +224,14 @@ class LLVMIRGenerator:
for arg in typ.optargs], for arg in typ.optargs],
return_type=llretty) return_type=llretty)
# TODO: actually mark the first argument as sret (also noalias nocapture).
# llvmlite currently does not have support for this;
# https://github.com/numba/llvmlite/issues/91.
if sretarg:
llty.__has_sret = True
else:
llty.__has_sret = False
if bare: if bare:
return llty return llty
else: else:
return ll.LiteralStructType([envarg, llty.as_pointer()]) return ll.LiteralStructType([envarg, llty.as_pointer()])
elif types.is_method(typ): elif types.is_method(typ):
llfuncty = self.llty_of_type(types.get_method_function(typ)) llfunty = self.llty_of_type(types.get_method_function(typ))
llselfty = self.llty_of_type(types.get_method_self(typ)) llselfty = self.llty_of_type(types.get_method_self(typ))
return ll.LiteralStructType([llfuncty, llselfty]) return ll.LiteralStructType([llfunty, llselfty])
elif builtins.is_none(typ): elif builtins.is_none(typ):
if for_return: if for_return:
return llvoid return llvoid
@ -399,8 +397,13 @@ class LLVMIRGenerator:
elif isinstance(value, ir.Function): elif isinstance(value, ir.Function):
llfun = self.llmodule.get_global(value.name) llfun = self.llmodule.get_global(value.name)
if llfun is None: if llfun is None:
llfun = ll.Function(self.llmodule, self.llty_of_type(value.type, bare=True), llfunty = self.llty_of_type(value.type, bare=True)
value.name) llfun = ll.Function(self.llmodule, llfunty, value.name)
llretty = self.llty_of_type(value.type.ret, for_return=True)
if self.needs_sret(llretty):
llfun.args[0].add_attribute('sret')
return llfun return llfun
else: else:
assert False assert False
@ -515,11 +518,7 @@ class LLVMIRGenerator:
def process_function(self, func): def process_function(self, func):
try: try:
self.llfunction = self.llmodule.get_global(func.name) self.llfunction = self.map(func)
if self.llfunction is None:
llfunty = self.llty_of_type(func.type, bare=True)
self.llfunction = ll.Function(self.llmodule, llfunty, func.name)
if func.is_internal: if func.is_internal:
self.llfunction.linkage = 'internal' self.llfunction.linkage = 'internal'
@ -532,7 +531,7 @@ class LLVMIRGenerator:
disubprogram = self.debug_info_emitter.emit_subprogram(func, self.llfunction) disubprogram = self.debug_info_emitter.emit_subprogram(func, self.llfunction)
# First, map arguments. # First, map arguments.
if self.llfunction.type.pointee.__has_sret: if self.has_sret(func.type):
llactualargs = self.llfunction.args[1:] llactualargs = self.llfunction.args[1:]
else: else:
llactualargs = self.llfunction.args llactualargs = self.llfunction.args
@ -615,7 +614,8 @@ class LLVMIRGenerator:
llalloc = self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True)) llalloc = self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True))
for index, operand in enumerate(insn.operands): for index, operand in enumerate(insn.operands):
lloperand = self.map(operand) lloperand = self.map(operand)
llfieldptr = self.llbuilder.gep(llalloc, [self.llindex(0), self.llindex(index)]) llfieldptr = self.llbuilder.gep(llalloc, [self.llindex(0), self.llindex(index)],
inbounds=True)
self.llbuilder.store(lloperand, llfieldptr) self.llbuilder.store(lloperand, llfieldptr)
return llalloc return llalloc
@ -623,11 +623,14 @@ class LLVMIRGenerator:
if var_name in env_ty.params and (var_type is None or if var_name in env_ty.params and (var_type is None or
env_ty.params[var_name] == var_type): env_ty.params[var_name] == var_type):
var_index = list(env_ty.params.keys()).index(var_name) var_index = list(env_ty.params.keys()).index(var_name)
return self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(var_index)]) return self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(var_index)],
inbounds=True)
else: else:
outer_index = list(env_ty.params.keys()).index("$outer") outer_index = list(env_ty.params.keys()).index("$outer")
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)]) llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)],
inbounds=True)
llouterenv = self.llbuilder.load(llptr) llouterenv = self.llbuilder.load(llptr)
llouterenv.metadata['invariant.load'] = self.empty_metadata
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
def process_GetLocal(self, insn): def process_GetLocal(self, insn):
@ -638,7 +641,9 @@ class LLVMIRGenerator:
def process_GetConstructor(self, insn): def process_GetConstructor(self, insn):
env = insn.environment() env = insn.environment()
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name, insn.type) llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name, insn.type)
return self.llbuilder.load(llptr) llconstr = self.llbuilder.load(llptr)
llconstr.metadata['invariant.load'] = self.empty_metadata
return llconstr
def process_SetLocal(self, insn): def process_SetLocal(self, insn):
env = insn.environment() env = insn.environment()
@ -667,14 +672,14 @@ class LLVMIRGenerator:
else: else:
llptr = self.llbuilder.gep(self.map(insn.object()), llptr = self.llbuilder.gep(self.map(insn.object()),
[self.llindex(0), self.llindex(self.attr_index(insn))], [self.llindex(0), self.llindex(self.attr_index(insn))],
name=insn.name) inbounds=True, name=insn.name)
return self.llbuilder.load(llptr) return self.llbuilder.load(llptr)
def process_SetAttr(self, insn): def process_SetAttr(self, insn):
assert builtins.is_allocated(insn.object().type) assert builtins.is_allocated(insn.object().type)
llptr = self.llbuilder.gep(self.map(insn.object()), llptr = self.llbuilder.gep(self.map(insn.object()),
[self.llindex(0), self.llindex(self.attr_index(insn))], [self.llindex(0), self.llindex(self.attr_index(insn))],
name=insn.name) inbounds=True, name=insn.name)
return self.llbuilder.store(self.map(insn.value()), llptr) return self.llbuilder.store(self.map(insn.value()), llptr)
def process_GetElem(self, insn): def process_GetElem(self, insn):
@ -872,8 +877,10 @@ class LLVMIRGenerator:
def get_outer(llenv, env_ty): def get_outer(llenv, env_ty):
if "$outer" in env_ty.params: if "$outer" in env_ty.params:
outer_index = list(env_ty.params.keys()).index("$outer") outer_index = list(env_ty.params.keys()).index("$outer")
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)]) llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)],
inbounds=True)
llouterenv = self.llbuilder.load(llptr) llouterenv = self.llbuilder.load(llptr)
llouterenv.metadata['invariant.load'] = self.empty_metadata
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
else: else:
return llenv return llenv
@ -920,21 +927,46 @@ class LLVMIRGenerator:
return llvalue return llvalue
def _prepare_closure_call(self, insn): def _prepare_closure_call(self, insn):
llclosure = self.map(insn.target_function())
llargs = [self.map(arg) for arg in insn.arguments()] llargs = [self.map(arg) for arg in insn.arguments()]
llclosure = self.map(insn.target_function())
llenv = self.llbuilder.extract_value(llclosure, 0) llenv = self.llbuilder.extract_value(llclosure, 0)
llfun = self.llbuilder.extract_value(llclosure, 1) if insn.static_target_function is None:
llfun = self.llbuilder.extract_value(llclosure, 1)
else:
llfun = self.map(insn.static_target_function)
return llfun, [llenv] + list(llargs) return llfun, [llenv] + list(llargs)
def _prepare_ffi_call(self, insn): def _prepare_ffi_call(self, insn):
llargs = [self.map(arg) for arg in insn.arguments()] llargs = []
byvals = []
for i, arg in enumerate(insn.arguments()):
llarg = self.map(arg)
if isinstance(llarg.type, (ll.LiteralStructType, ll.IdentifiedStructType)):
llslot = self.llbuilder.alloca(llarg.type)
self.llbuilder.store(llarg, llslot)
llargs.append(llslot)
byvals.append(i)
else:
llargs.append(llarg)
llfunname = insn.target_function().type.name llfunname = insn.target_function().type.name
llfun = self.llmodule.get_global(llfunname) llfun = self.llmodule.get_global(llfunname)
if llfun is None: if llfun is None:
llfunty = ll.FunctionType(self.llty_of_type(insn.type, for_return=True), llretty = self.llty_of_type(insn.type, for_return=True)
[llarg.type for llarg in llargs]) if self.needs_sret(llretty):
llfun = ll.Function(self.llmodule, llfunty, llfunty = ll.FunctionType(llvoid, [llretty.as_pointer()] +
insn.target_function().type.name) [llarg.type for llarg in llargs])
else:
llfunty = ll.FunctionType(llretty, [llarg.type for llarg in llargs])
llfun = ll.Function(self.llmodule, llfunty,
insn.target_function().type.name)
if self.needs_sret(llretty):
llfun.args[0].add_attribute('sret')
byvals = [i + 1 for i in byvals]
for i in byvals:
llfun.args[i].add_attribute('byval')
return llfun, list(llargs) return llfun, list(llargs)
# See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value. # See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value.
@ -1078,24 +1110,22 @@ class LLVMIRGenerator:
llnormalblock=None, llunwindblock=None) llnormalblock=None, llunwindblock=None)
elif types.is_c_function(insn.target_function().type): elif types.is_c_function(insn.target_function().type):
llfun, llargs = self._prepare_ffi_call(insn) llfun, llargs = self._prepare_ffi_call(insn)
return self.llbuilder.call(llfun, llargs,
name=insn.name)
else: else:
llfun, llargs = self._prepare_closure_call(insn) llfun, llargs = self._prepare_closure_call(insn)
if llfun.type.pointee.__has_sret: if self.has_sret(insn.target_function().type):
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), []) llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee) llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
self.llbuilder.call(llfun, [llresultslot] + llargs) self.llbuilder.call(llfun, [llresultslot] + llargs)
llresult = self.llbuilder.load(llresultslot) llresult = self.llbuilder.load(llresultslot)
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
return llresult return llresult
else: else:
return self.llbuilder.call(llfun, llargs, return self.llbuilder.call(llfun, llargs,
name=insn.name) name=insn.name)
def process_Invoke(self, insn): def process_Invoke(self, insn):
llnormalblock = self.map(insn.normal_target()) llnormalblock = self.map(insn.normal_target())
@ -1209,11 +1239,12 @@ class LLVMIRGenerator:
if builtins.is_none(insn.value().type): if builtins.is_none(insn.value().type):
return self.llbuilder.ret_void() return self.llbuilder.ret_void()
else: else:
if self.llfunction.type.pointee.__has_sret: llvalue = self.map(insn.value())
self.llbuilder.store(self.map(insn.value()), self.llfunction.args[0]) if self.needs_sret(llvalue.type):
self.llbuilder.store(llvalue, self.llfunction.args[0])
return self.llbuilder.ret_void() return self.llbuilder.ret_void()
else: else:
return self.llbuilder.ret(self.map(insn.value())) return self.llbuilder.ret(llvalue)
def process_Unreachable(self, insn): def process_Unreachable(self, insn):
return self.llbuilder.unreachable() return self.llbuilder.unreachable()
@ -1250,7 +1281,8 @@ class LLVMIRGenerator:
cleanup=True) cleanup=True)
llrawexn = self.llbuilder.extract_value(lllandingpad, 1) llrawexn = self.llbuilder.extract_value(lllandingpad, 1)
llexn = self.llbuilder.bitcast(llrawexn, self.llty_of_type(insn.type)) llexn = self.llbuilder.bitcast(llrawexn, self.llty_of_type(insn.type))
llexnnameptr = self.llbuilder.gep(llexn, [self.llindex(0), self.llindex(0)]) llexnnameptr = self.llbuilder.gep(llexn, [self.llindex(0), self.llindex(0)],
inbounds=True)
llexnname = self.llbuilder.load(llexnnameptr) llexnname = self.llbuilder.load(llexnnameptr)
for target, typ in insn.clauses(): for target, typ in insn.clauses():

View File

@ -610,8 +610,13 @@ def is_function(typ):
def is_rpc_function(typ): def is_rpc_function(typ):
return isinstance(typ.find(), TRPCFunction) return isinstance(typ.find(), TRPCFunction)
def is_c_function(typ): def is_c_function(typ, name=None):
return isinstance(typ.find(), TCFunction) typ = typ.find()
if name is None:
return isinstance(typ, TCFunction)
else:
return isinstance(typ, TCFunction) and \
typ.name == name
def is_builtin(typ, name=None): def is_builtin(typ, name=None):
typ = typ.find() typ = typ.find()

View File

@ -87,7 +87,13 @@ class RegionOf(algorithm.Visitor):
return None return None
visit_BinOpT = visit_sometimes_allocating visit_BinOpT = visit_sometimes_allocating
visit_CallT = visit_sometimes_allocating
def visit_CallT(self, node):
if types.is_c_function(node.func.type, "cache_get"):
# The cache is borrow checked dynamically
return None
else:
self.visit_sometimes_allocating(node)
# Value lives as long as the object/container, if it's mutable, # Value lives as long as the object/container, if it's mutable,
# or else forever # or else forever

View File

@ -512,7 +512,7 @@ class CommGeneric:
assert exception.id != 0 assert exception.id != 0
python_exn_type = object_map.retrieve(exception.id) python_exn_type = object_map.retrieve(exception.id)
python_exn = python_exn_type(message) python_exn = python_exn_type(message.format(*params))
python_exn.artiq_exception = exception python_exn.artiq_exception = exception
raise python_exn raise python_exn

View File

@ -37,6 +37,14 @@ class CompileError(Exception):
def rtio_get_counter() -> TInt64: def rtio_get_counter() -> TInt64:
raise NotImplementedError("syscall not simulated") raise NotImplementedError("syscall not simulated")
@syscall
def cache_get(key: TStr) -> TList(TInt32):
raise NotImplementedError("syscall not simulated")
@syscall
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
raise NotImplementedError("syscall not simulated")
class Core: class Core:
"""Core device driver. """Core device driver.
@ -108,3 +116,11 @@ class Core:
min_now = rtio_get_counter() + 125000 min_now = rtio_get_counter() + 125000
if now_mu() < min_now: if now_mu() < min_now:
at_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)

View File

@ -11,6 +11,10 @@ class InternalError(Exception):
"""Raised when the runtime encounters an internal error condition.""" """Raised when the runtime encounters an internal error condition."""
class CacheError(Exception):
"""Raised when putting a value into a cache row would violate memory safety."""
class RTIOUnderflow(Exception): class RTIOUnderflow(Exception):
"""Raised when the CPU fails to submit a RTIO event early enough """Raised when the CPU fails to submit a RTIO event early enough
(with respect to the event's timestamp). (with respect to the event's timestamp).

View File

@ -7,7 +7,7 @@ from misoc.integration.soc_core import mem_decoder
class KernelCPU(Module): class KernelCPU(Module):
def __init__(self, platform, def __init__(self, platform,
exec_address=0x40800000, exec_address=0x42000000,
main_mem_origin=0x40000000, main_mem_origin=0x40000000,
l2_size=8192): l2_size=8192):
self._reset = CSRStorage(reset=1) self._reset = CSRStorage(reset=1)

View File

@ -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 \ OBJECTS_KSUPPORT := ksupport.o artiq_personality.o mailbox.o \
bridge.o rtio.o ttl.o dds.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$(LIBDYLD_DIRECTORY)/include \
-I$(LIBUNWIND_DIRECTORY) \ -I$(LIBUNWIND_DIRECTORY) \
-I$(LIBUNWIND_DIRECTORY)/../unwinder/include \ -I$(LIBUNWIND_DIRECTORY)/../unwinder/include \
@ -31,10 +32,11 @@ runtime.elf: $(OBJECTS)
-N -o $@ \ -N -o $@ \
../libbase/crt0-$(CPU).o \ ../libbase/crt0-$(CPU).o \
$(OBJECTS) \ $(OBJECTS) \
-L../libbase \
-L../libcompiler_rt \ -L../libcompiler_rt \
-L../libbase \
-L../liballoc \
-L../liblwip \ -L../liblwip \
-lbase -lcompiler_rt -llwip -lbase -lcompiler_rt -lalloc -llwip
@chmod -x $@ @chmod -x $@
ksupport.elf: $(OBJECTS_KSUPPORT) ksupport.elf: $(OBJECTS_KSUPPORT)
@ -48,7 +50,7 @@ ksupport.elf: $(OBJECTS_KSUPPORT)
-L../libcompiler_rt \ -L../libcompiler_rt \
-L../libunwind \ -L../libunwind \
-L../libdyld \ -L../libdyld \
-lbase -lcompiler_rt -lunwind -ldyld -lbase -lcompiler_rt -ldyld -lunwind
@chmod -x $@ @chmod -x $@
ksupport_data.o: ksupport.elf ksupport_data.o: ksupport.elf

View File

@ -3,8 +3,8 @@
#include "artiq_personality.h" #include "artiq_personality.h"
#define KERNELCPU_EXEC_ADDRESS 0x40800000 #define KERNELCPU_EXEC_ADDRESS 0x42000000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40820000 #define KERNELCPU_PAYLOAD_ADDRESS 0x42020000
#define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024) #define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024)
#define KSUPPORT_HEADER_SIZE 0x80 #define KSUPPORT_HEADER_SIZE 0x80

View File

@ -122,6 +122,9 @@ static const struct symbol runtime_exports[] = {
{"dds_batch_exit", &dds_batch_exit}, {"dds_batch_exit", &dds_batch_exit},
{"dds_set", &dds_set}, {"dds_set", &dds_set},
{"cache_get", &cache_get},
{"cache_put", &cache_put},
/* end */ /* end */
{NULL, NULL} {NULL, NULL}
}; };
@ -222,7 +225,7 @@ void exception_handler(unsigned long vect, unsigned long *regs,
unsigned long pc, unsigned long ea) unsigned long pc, unsigned long ea)
{ {
artiq_raise_from_c("InternalError", artiq_raise_from_c("InternalError",
"Hardware exception {0} at PC {1}, EA {2}", "Hardware exception {0} at PC 0x{1:08x}, EA 0x{2:08x}",
vect, pc, ea); vect, pc, ea);
} }
@ -444,6 +447,50 @@ 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 lognonl(const char *fmt, ...) void lognonl(const char *fmt, ...)
{ {
struct msg_log request; struct msg_log request;

View File

@ -1,12 +1,19 @@
#ifndef __KSTARTUP_H #ifndef __KSTARTUP_H
#define __KSTARTUP_H #define __KSTARTUP_H
struct artiq_list {
int32_t length;
int32_t *elements;
};
long long int now_init(void); long long int now_init(void);
void now_save(long long int now); void now_save(long long int now);
int watchdog_set(int ms); int watchdog_set(int ms);
void watchdog_clear(int id); void watchdog_clear(int id);
void send_rpc(int service, const char *tag, ...); void send_rpc(int service, const char *tag, ...);
int recv_rpc(void *slot); int recv_rpc(void *slot);
struct artiq_list cache_get(const char *key);
void cache_put(const char *key, struct artiq_list value);
void lognonl(const char *fmt, ...); void lognonl(const char *fmt, ...);
void log(const char *fmt, ...); void log(const char *fmt, ...);

View File

@ -3,11 +3,12 @@ ENTRY(_start)
INCLUDE generated/regions.ld INCLUDE generated/regions.ld
/* First 8M of main memory are reserved for runtime code/data /* First 32M of main memory are reserved for runtime
* then comes kernel memory. First 128K of kernel memory are for support code. * code/data/heap, then comes kernel memory.
* First 128K of kernel memory are for support code.
*/ */
MEMORY { 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, /* On AMP systems, kernel stack is at the end of main RAM,

View File

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <alloc.h>
#include <irq.h> #include <irq.h>
#include <uart.h> #include <uart.h>
#include <console.h> #include <console.h>
@ -263,6 +264,8 @@ static int check_test_mode(void)
return 0; return 0;
} }
extern void _fheap, _eheap;
int main(void) int main(void)
{ {
irq_setmask(0); irq_setmask(0);
@ -271,6 +274,7 @@ int main(void)
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n"); puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
alloc_give(&_fheap, &_eheap - &_fheap);
clock_init(); clock_init();
rtiocrg_init(); rtiocrg_init();
puts("Press 't' to enter test mode..."); puts("Press 't' to enter test mode...");

View File

@ -3,6 +3,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
enum { enum {
MESSAGE_TYPE_LOAD_REPLY, MESSAGE_TYPE_LOAD_REPLY,
@ -18,6 +19,10 @@ enum {
MESSAGE_TYPE_RPC_RECV_REQUEST, MESSAGE_TYPE_RPC_RECV_REQUEST,
MESSAGE_TYPE_RPC_RECV_REPLY, MESSAGE_TYPE_RPC_RECV_REPLY,
MESSAGE_TYPE_RPC_BATCH, 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_LOG,
MESSAGE_TYPE_BRG_READY, MESSAGE_TYPE_BRG_READY,
@ -105,6 +110,29 @@ struct msg_rpc_batch {
void *ptr; 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 { struct msg_log {
int type; int type;
const char *fmt; const char *fmt;

View File

@ -7,7 +7,7 @@ INCLUDE generated/regions.ld
* ld does not allow this expression here. * ld does not allow this expression here.
*/ */
MEMORY { MEMORY {
runtime : ORIGIN = 0x40000000, LENGTH = 0x800000 /* 8M */ runtime : ORIGIN = 0x40000000, LENGTH = 0x2000000 /* 32M */
} }
/* Kernel memory space start right after the runtime, /* Kernel memory space start right after the runtime,
@ -65,5 +65,7 @@ SECTIONS
*(.eh_frame) *(.eh_frame)
} }
_heapstart = .; _fheap = .;
. += 0x1800000;
_eheap = .;
} }

View File

@ -908,6 +908,16 @@ static int send_rpc_request(int service, const char *tag, va_list args)
return 1; 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 */ /* assumes output buffer is empty when called */
static int process_kmsg(struct msg_base *umsg) static int process_kmsg(struct msg_base *umsg)
{ {
@ -930,9 +940,12 @@ static int process_kmsg(struct msg_base *umsg)
case MESSAGE_TYPE_FINISHED: case MESSAGE_TYPE_FINISHED:
out_packet_empty(REMOTEMSG_TYPE_KERNEL_FINISHED); out_packet_empty(REMOTEMSG_TYPE_KERNEL_FINISHED);
for(struct cache_row *iter = cache; iter; iter = iter->next)
iter->borrowed = 0;
kloader_stop(); kloader_stop();
user_kernel_state = USER_KERNEL_LOADED; user_kernel_state = USER_KERNEL_LOADED;
mailbox_acknowledge();
break; break;
case MESSAGE_TYPE_EXCEPTION: { case MESSAGE_TYPE_EXCEPTION: {
@ -984,6 +997,67 @@ static int process_kmsg(struct msg_base *umsg)
break; 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);
break;
}
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) {
row = calloc(1, sizeof(struct cache_row));
row->key = calloc(strlen(request->key) + 1, 1);
strcpy(row->key, request->key);
row->next = cache;
cache = row;
}
if(!row->borrowed) {
if(request->length != 0) {
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);
break;
}
default: { default: {
log("Received invalid message type %d from kernel CPU", log("Received invalid message type %d from kernel CPU",
umsg->type); umsg->type);

View File

@ -0,0 +1,44 @@
from artiq.language import *
from artiq.coredevice.exceptions import *
from artiq.test.hardware_testbench import ExperimentCase
class _Cache(EnvExperiment):
def build(self):
self.setattr_device("core")
self.print = lambda x: print(x)
@kernel
def get(self, key):
return self.core.get_cache(key)
@kernel
def put(self, key, value):
self.core.put_cache(key, value)
@kernel
def get_put(self, key, value):
self.get(key)
self.put(key, value)
class CacheTest(ExperimentCase):
def test_get_empty(self):
exp = self.create(_Cache)
self.assertEqual(exp.get("x1"), [])
def test_put_get(self):
exp = self.create(_Cache)
exp.put("x2", [1, 2, 3])
self.assertEqual(exp.get("x2"), [1, 2, 3])
def test_replace(self):
exp = self.create(_Cache)
exp.put("x3", [1, 2, 3])
exp.put("x3", [1, 2, 3, 4, 5])
self.assertEqual(exp.get("x3"), [1, 2, 3, 4, 5])
def test_borrow(self):
exp = self.create(_Cache)
exp.put("x4", [1, 2, 3])
with self.assertRaises(CacheError):
exp.get_put("x4", [])

View File

@ -44,6 +44,7 @@ scripts = [
setup( setup(
name="artiq", name="artiq",
version=versioneer.get_version(), version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
author="M-Labs / NIST Ion Storage Group", author="M-Labs / NIST Ion Storage Group",
author_email="sb@m-labs.hk", author_email="sb@m-labs.hk",
url="http://m-labs.hk/artiq", url="http://m-labs.hk/artiq",