From c72267ecf56ade318854829b1018394cb3a2f482 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 10 Aug 2015 19:25:48 +0300 Subject: [PATCH] Implement syscalls for the new compiler. --- artiq/compiler/embedding.py | 104 ++++++++++---- .../compiler/transforms/llvm_ir_generator.py | 25 +++- artiq/compiler/types.py | 27 +++- artiq/coredevice/core.py | 13 +- artiq/coredevice/dds.py | 26 +++- artiq/coredevice/runtime.py | 134 ------------------ artiq/coredevice/ttl.py | 43 ++++-- artiq/language/core.py | 76 +++++----- 8 files changed, 223 insertions(+), 225 deletions(-) delete mode 100644 artiq/coredevice/runtime.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index c35eec7ed..4f79bdfaa 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -238,6 +238,10 @@ class Stitcher: name = function.__code__.co_name source_line = linecache.getline(filename, line) + while source_line.lstrip().startswith("@"): + line += 1 + source_line = linecache.getline(filename, line) + column = re.search("def", source_line).start(0) source_buffer = source.Buffer(source_line, filename, line) return source.Range(source_buffer, column, column) @@ -248,11 +252,16 @@ class Stitcher: {"function": function.__name__}, self._function_loc(function)) - def _extract_annot(self, function, annot, kind, call_loc): + def _extract_annot(self, function, annot, kind, call_loc, is_syscall): if not isinstance(annot, types.Type): - note = diagnostic.Diagnostic("note", - "in function called remotely here", {}, - call_loc) + if is_syscall: + note = diagnostic.Diagnostic("note", + "in system call here", {}, + call_loc) + else: + note = diagnostic.Diagnostic("note", + "in function called remotely here", {}, + call_loc) diag = diagnostic.Diagnostic("error", "type annotation for {kind}, '{annot}', is not an ARTIQ type", {"kind": kind, "annot": repr(annot)}, @@ -264,11 +273,19 @@ class Stitcher: else: return annot - def _type_of_param(self, function, loc, param): + def _type_of_param(self, function, loc, param, is_syscall): if param.annotation is not inspect.Parameter.empty: # Type specified explicitly. return self._extract_annot(function, param.annotation, - "argument {}".format(param.name), loc) + "argument '{}'".format(param.name), loc, + is_syscall) + elif is_syscall: + # Syscalls must be entirely annotated. + diag = diagnostic.Diagnostic("error", + "system call argument '{argument}' must have a type annotation", + {"argument": param.name}, + self._function_loc(function)) + self.engine.process(diag) elif param.default is not inspect.Parameter.empty: # Try and infer the type from the default value. # This is tricky, because the default value might not have @@ -281,8 +298,8 @@ class Stitcher: def proxy_diagnostic(diag): note = diagnostic.Diagnostic("note", "expanded from here while trying to infer a type for an" - " unannotated optional argument '{param_name}' from its default value", - {"param_name": param.name}, + " unannotated optional argument '{argument}' from its default value", + {"argument": param.name}, loc) diag.notes.append(note) @@ -300,7 +317,7 @@ class Stitcher: # Let the rest of the program decide. return types.TVar() - def _quote_rpc_function(self, function, loc): + def _quote_foreign_function(self, function, loc, syscall): signature = inspect.signature(function) arg_types = OrderedDict() @@ -318,44 +335,73 @@ class Stitcher: continue if param.default is inspect.Parameter.empty: - arg_types[param.name] = self._type_of_param(function, loc, param) + arg_types[param.name] = self._type_of_param(function, loc, param, + is_syscall=syscall is not None) + elif syscall is None: + optarg_types[param.name] = self._type_of_param(function, loc, param, + is_syscall=syscall is not None) else: - optarg_types[param.name] = self._type_of_param(function, loc, param) + diag = diagnostic.Diagnostic("error", + "system call argument '{argument}' must not have a default value", + {"argument": param.name}, + self._function_loc(function)) + self.engine.process(diag) if signature.return_annotation is not inspect.Signature.empty: ret_type = self._extract_annot(function, signature.return_annotation, - "return type", loc) - else: - diag = diagnostic.Diagnostic("fatal", - "function must have a return type specified to be called remotely", {}, + "return type", loc, is_syscall=syscall is not None) + elif syscall is None: + diag = diagnostic.Diagnostic("error", + "function must have a return type annotation to be called remotely", {}, self._function_loc(function)) self.engine.process(diag) + ret_type = types.TVar() + else: # syscall is not None + diag = diagnostic.Diagnostic("error", + "system call must have a return type annotation", {}, + self._function_loc(function)) + self.engine.process(diag) + ret_type = types.TVar() - rpc_type = types.TRPCFunction(arg_types, optarg_types, ret_type, - service=self._map(function)) + if syscall is None: + function_type = types.TRPCFunction(arg_types, optarg_types, ret_type, + service=self._map(function)) + function_name = "__rpc_{}__".format(function_type.service) + else: + function_type = types.TCFunction(arg_types, ret_type, + name=syscall) + function_name = "__ffi_{}__".format(function_type.name) - rpc_name = "__rpc_{}__".format(rpc_type.service) - self.globals[rpc_name] = rpc_type - self.functions[function] = rpc_name + self.globals[function_name] = function_type + self.functions[function] = function_name - return rpc_name + return function_name def _quote_function(self, function, loc): if function in self.functions: return self.functions[function] if hasattr(function, "artiq_embedded"): - # Insert the typed AST for the new function and restart inference. - # It doesn't really matter where we insert as long as it is before - # the final call. - function_node = self._quote_embedded_function(function) - self.typedtree.insert(0, function_node) - self.inference_finished = False - return function_node.name + if function.artiq_embedded.function is not None: + # Insert the typed AST for the new function and restart inference. + # It doesn't really matter where we insert as long as it is before + # the final call. + function_node = self._quote_embedded_function(function) + self.typedtree.insert(0, function_node) + self.inference_finished = False + return function_node.name + elif function.artiq_embedded.syscall is not None: + # Insert a storage-less global whose type instructs the compiler + # to perform a system call instead of a regular call. + return self._quote_foreign_function(function, loc, + syscall=function.artiq_embedded.syscall) + else: + assert False else: # Insert a storage-less global whose type instructs the compiler # to perform an RPC instead of a regular call. - return self._quote_rpc_function(function, loc) + return self._quote_foreign_function(function, loc, + syscall=None) def stitch_call(self, function, args, kwargs): function_node = self._quote_embedded_function(function) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 8bda72f5d..4eaf34e68 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -175,7 +175,7 @@ class LLVMIRGenerator: typ = typ.find() if types.is_tuple(typ): return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts]) - elif types.is_rpc_function(typ): + elif types.is_rpc_function(typ) or types.is_c_function(typ): if for_return: return llvoid else: @@ -731,11 +731,20 @@ class LLVMIRGenerator: return llvalue def _prepare_closure_call(self, insn): - llclosure, llargs = self.map(insn.target_function()), map(self.map, insn.arguments()) - llenv = self.llbuilder.extract_value(llclosure, 0) - llfun = self.llbuilder.extract_value(llclosure, 1) + llclosure = self.map(insn.target_function()) + llargs = [self.map(arg) for arg in insn.arguments()] + llenv = self.llbuilder.extract_value(llclosure, 0) + llfun = self.llbuilder.extract_value(llclosure, 1) return llfun, [llenv] + list(llargs) + def _prepare_ffi_call(self, insn): + llargs = [self.map(arg) for arg in insn.arguments()] + llfunty = ll.FunctionType(self.llty_of_type(insn.type, for_return=True), + [llarg.type for llarg in llargs]) + llfun = ll.Function(self.llmodule, llfunty, + insn.target_function().type.name) + return llfun, list(llargs) + # See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value. def _rpc_tag(self, typ, error_handler): if types.is_tuple(typ): @@ -869,6 +878,10 @@ class LLVMIRGenerator: insn.target_function().type, insn.arguments(), llnormalblock=None, llunwindblock=None) + elif types.is_c_function(insn.target_function().type): + llfun, llargs = self._prepare_ffi_call(insn) + return self.llbuilder.call(llfun, llargs, + name=insn.name) else: llfun, llargs = self._prepare_closure_call(insn) return self.llbuilder.call(llfun, llargs, @@ -882,6 +895,10 @@ class LLVMIRGenerator: insn.target_function().type, insn.arguments(), llnormalblock, llunwindblock) + elif types.is_c_function(insn.target_function().type): + llfun, llargs = self._prepare_ffi_call(insn) + return self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock, + name=insn.name) else: llfun, llargs = self._prepare_closure_call(insn) return self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock, diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index a43a235ef..631a9107e 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -258,6 +258,26 @@ class TRPCFunction(TFunction): else: raise UnificationError(self, other) +class TCFunction(TFunction): + """ + A function type of a runtime-provided C function. + + :ivar name: (str) C function name + """ + + def __init__(self, args, ret, name): + super().__init__(args, OrderedDict(), ret) + self.name = name + + def unify(self, other): + if isinstance(other, TCFunction) and \ + self.name == other.name: + super().unify(other) + elif isinstance(other, TVar): + other.unify(self) + else: + raise UnificationError(self, other) + class TBuiltin(Type): """ An instance of builtin type. Every instance of a builtin @@ -371,6 +391,9 @@ def is_function(typ): def is_rpc_function(typ): return isinstance(typ.find(), TRPCFunction) +def is_c_function(typ): + return isinstance(typ.find(), TCFunction) + def is_builtin(typ, name=None): typ = typ.find() if name is None: @@ -423,7 +446,7 @@ class TypePrinter(object): return "(%s,)" % self.name(typ.elts[0]) else: return "(%s)" % ", ".join(list(map(self.name, typ.elts))) - elif isinstance(typ, (TFunction, TRPCFunction)): + elif isinstance(typ, (TFunction, TRPCFunction, TCFunction)): args = [] args += [ "%s:%s" % (arg, self.name(typ.args[arg])) for arg in typ.args] args += ["?%s:%s" % (arg, self.name(typ.optargs[arg])) for arg in typ.optargs] @@ -431,6 +454,8 @@ class TypePrinter(object): if isinstance(typ, TRPCFunction): return "rpc({}) {}".format(typ.service, signature) + if isinstance(typ, TCFunction): + return "ffi({}) {}".format(repr(typ.name), signature) elif isinstance(typ, TFunction): return signature elif isinstance(typ, TBuiltinFunction): diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index fb54cc9a3..1adb1c904 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -1,9 +1,9 @@ -import sys, tempfile +import sys from pythonparser import diagnostic from artiq.language.core import * -from artiq.language.units import ns +from artiq.language.types import * from artiq.compiler import Stitcher, Module from artiq.compiler.targets import OR1KTarget @@ -15,6 +15,11 @@ from artiq.coredevice import exceptions class CompileError(Exception): pass + +@syscall +def rtio_get_counter() -> TInt64: + raise NotImplementedError("syscall not simulated") + class Core: def __init__(self, dmgr, ref_period=8*ns, external_clock=False): self.comm = dmgr.get("comm") @@ -58,8 +63,8 @@ class Core: @kernel def get_rtio_counter_mu(self): - return syscall("rtio_get_counter") + return rtio_get_counter() @kernel def break_realtime(self): - at_mu(syscall("rtio_get_counter") + 125000) + at_mu(rtio_get_counter() + 125000) diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index 9ba4584d8..2f03ff661 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -9,6 +9,24 @@ PHASE_MODE_ABSOLUTE = 1 PHASE_MODE_TRACKING = 2 +@syscall +def dds_init(time_mu: TInt64, channel: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + +@syscall +def dds_batch_enter(time_mu: TInt64) -> TNone: + raise NotImplementedError("syscall not simulated") + +@syscall +def dds_batch_exit() -> TNone: + raise NotImplementedError("syscall not simulated") + +@syscall +def dds_set(time_mu: TInt64, channel: TInt32, ftw: TInt32, + pow: TInt32, phase_mode: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + class _BatchContextManager: def __init__(self, dds_bus): self.dds_bus = dds_bus @@ -34,13 +52,13 @@ class DDSBus: def batch_enter(self): """Starts a DDS command batch. All DDS commands are buffered after this call, until ``batch_exit`` is called.""" - syscall("dds_batch_enter", now_mu()) + dds_batch_enter(now_mu()) @kernel def batch_exit(self): """Ends a DDS command batch. All buffered DDS commands are issued on the bus, and FUD is pulsed at the time the batch started.""" - syscall("dds_batch_exit") + dds_batch_exit() class _DDSGeneric: @@ -91,7 +109,7 @@ class _DDSGeneric: """Resets and initializes the DDS channel. The runtime does this for all channels upon core device startup.""" - syscall("dds_init", now_mu(), self.channel) + dds_init(now_mu(), self.channel) @kernel def set_phase_mode(self, phase_mode): @@ -128,7 +146,7 @@ class _DDSGeneric: """ if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode - syscall("dds_set", now_mu(), self.channel, + dds_set(now_mu(), self.channel, frequency, round(phase*2**self.pow_width), phase_mode) @kernel diff --git a/artiq/coredevice/runtime.py b/artiq/coredevice/runtime.py deleted file mode 100644 index e716aecfc..000000000 --- a/artiq/coredevice/runtime.py +++ /dev/null @@ -1,134 +0,0 @@ -import os - -import llvmlite_or1k.ir as ll -import llvmlite_or1k.binding as llvm - -from artiq.language import units - -_syscalls = { - "now_init": "n:I", - "now_save": "I:n", - "watchdog_set": "i:i", - "watchdog_clear": "i:n", - "rtio_get_counter": "n:I", - "ttl_set_o": "Iib:n", - "ttl_set_oe": "Iib:n", - "ttl_set_sensitivity": "Iii:n", - "ttl_get": "iI:I", - "ttl_clock_set": "Iii:n", - "dds_init": "Ii:n", - "dds_batch_enter": "I:n", - "dds_batch_exit": "n:n", - "dds_set": "Iiiii:n", -} - - -def _chr_to_type(c): - if c == "n": - return ll.VoidType() - if c == "b": - return ll.IntType(1) - if c == "i": - return ll.IntType(32) - if c == "I": - return ll.IntType(64) - raise ValueError - - -def _str_to_functype(s): - assert(s[-2] == ":") - type_ret = _chr_to_type(s[-1]) - type_args = [_chr_to_type(c) for c in s[:-2] if c != "n"] - return ll.FunctionType(type_ret, type_args) - - -def _chr_to_value(c): - if c == "n": - return base_types.VNone() - if c == "b": - return base_types.VBool() - if c == "i": - return base_types.VInt() - if c == "I": - return base_types.VInt(64) - raise ValueError - - -def _value_to_str(v): - if isinstance(v, base_types.VNone): - return "n" - if isinstance(v, base_types.VBool): - return "b" - if isinstance(v, base_types.VInt): - if v.nbits == 32: - return "i" - if v.nbits == 64: - return "I" - raise ValueError - if isinstance(v, base_types.VFloat): - return "f" - if isinstance(v, fractions.VFraction): - return "F" - if isinstance(v, lists.VList): - return "l" + _value_to_str(v.el_type) - raise ValueError - - -class LinkInterface: - def init_module(self, module): - self.module = module - llvm_module = self.module.llvm_module - - # RPC - func_type = ll.FunctionType(ll.IntType(32), [ll.IntType(32)], - var_arg=1) - self.rpc = ll.Function(llvm_module, func_type, "__syscall_rpc") - - # syscalls - self.syscalls = dict() - for func_name, func_type_str in _syscalls.items(): - func_type = _str_to_functype(func_type_str) - self.syscalls[func_name] = ll.Function( - llvm_module, func_type, "__syscall_" + func_name) - - def _build_rpc(self, args, builder): - r = base_types.VInt() - if builder is not None: - new_args = [] - new_args.append(args[0].auto_load(builder)) # RPC number - for arg in args[1:]: - # type tag - arg_type_str = _value_to_str(arg) - arg_type_int = 0 - for c in reversed(arg_type_str): - arg_type_int <<= 8 - arg_type_int |= ord(c) - new_args.append(ll.Constant(ll.IntType(32), arg_type_int)) - - # pointer to value - if not isinstance(arg, base_types.VNone): - if isinstance(arg.llvm_value.type, ll.PointerType): - new_args.append(arg.llvm_value) - else: - arg_ptr = arg.new() - arg_ptr.alloca(builder) - arg_ptr.auto_store(builder, arg.llvm_value) - new_args.append(arg_ptr.llvm_value) - # end marker - new_args.append(ll.Constant(ll.IntType(32), 0)) - r.auto_store(builder, builder.call(self.rpc, new_args)) - return r - - def _build_regular_syscall(self, syscall_name, args, builder): - r = _chr_to_value(_syscalls[syscall_name][-1]) - if builder is not None: - args = [arg.auto_load(builder) for arg in args] - r.auto_store(builder, builder.call(self.syscalls[syscall_name], - args)) - return r - - def build_syscall(self, syscall_name, args, builder): - if syscall_name == "rpc": - return self._build_rpc(args, builder) - else: - return self._build_regular_syscall(syscall_name, args, builder) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 866e884e5..ffc3ca0c4 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -1,4 +1,26 @@ from artiq.language.core import * +from artiq.language.types import * + + +@syscall +def ttl_set_o(time_mu: TInt64, channel: TInt32, enabled: TBool) -> TNone: + raise NotImplementedError("syscall not simulated") + +@syscall +def ttl_set_oe(time_mu: TInt64, channel: TInt32, enabled: TBool) -> TNone: + raise NotImplementedError("syscall not simulated") + +@syscall +def ttl_set_sensitivity(time_mu: TInt64, channel: TInt32, sensitivity: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + +@syscall +def ttl_get(channel: TInt32, time_limit_mu: TInt64) -> TInt64: + raise NotImplementedError("syscall not simulated") + +@syscall +def ttl_clock_set(time_mu: TInt64, channel: TInt32, ftw: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") class TTLOut: @@ -18,14 +40,14 @@ class TTLOut: @kernel def set_o(self, o): - syscall("ttl_set_o", now_mu(), self.channel, o) + ttl_set_o(now_mu(), self.channel, o) self.o_previous_timestamp = now_mu() @kernel def sync(self): """Busy-wait until all programmed level switches have been effected.""" - while syscall("rtio_get_counter") < self.o_previous_timestamp: + while self.core.get_rtio_counter_mu() < self.o_previous_timestamp: pass @kernel @@ -83,7 +105,7 @@ class TTLInOut: @kernel def set_oe(self, oe): - syscall("ttl_set_oe", now_mu(), self.channel, oe) + ttl_set_oe(now_mu(), self.channel, oe) @kernel def output(self): @@ -95,14 +117,14 @@ class TTLInOut: @kernel def set_o(self, o): - syscall("ttl_set_o", now_mu(), self.channel, o) + ttl_set_o(now_mu(), self.channel, o) self.o_previous_timestamp = now_mu() @kernel def sync(self): """Busy-wait until all programmed level switches have been effected.""" - while syscall("rtio_get_counter") < self.o_previous_timestamp: + while self.core.get_rtio_counter_mu() < self.o_previous_timestamp: pass @kernel @@ -133,7 +155,7 @@ class TTLInOut: @kernel def _set_sensitivity(self, value): - syscall("ttl_set_sensitivity", now_mu(), self.channel, value) + ttl_set_sensitivity(now_mu(), self.channel, value) self.i_previous_timestamp = now_mu() @kernel @@ -189,8 +211,7 @@ class TTLInOut: """Poll the RTIO input during all the previously programmed gate openings, and returns the number of registered events.""" count = 0 - while syscall("ttl_get", self.channel, - self.i_previous_timestamp) >= 0: + while ttl_get(self.channel, self.i_previous_timestamp) >= 0: count += 1 return count @@ -201,7 +222,7 @@ class TTLInOut: If the gate is permanently closed, returns a negative value. """ - return syscall("ttl_get", self.channel, self.i_previous_timestamp) + return ttl_get(self.channel, self.i_previous_timestamp) class TTLClockGen: @@ -254,7 +275,7 @@ class TTLClockGen: that are not powers of two cause jitter of one RTIO clock cycle at the output. """ - syscall("ttl_clock_set", now_mu(), self.channel, frequency) + ttl_clock_set(now_mu(), self.channel, frequency) self.previous_timestamp = now_mu() @kernel @@ -271,5 +292,5 @@ class TTLClockGen: def sync(self): """Busy-wait until all programmed frequency switches and stops have been effected.""" - while syscall("rtio_get_counter") < self.o_previous_timestamp: + while self.core.get_rtio_counter_mu() < self.o_previous_timestamp: pass diff --git a/artiq/language/core.py b/artiq/language/core.py index b4f547d35..b0d556969 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -7,15 +7,19 @@ from collections import namedtuple from functools import wraps -__all__ = ["int64", "round64", "kernel", "portable", - "set_time_manager", "set_syscall_manager", "set_watchdog_factory", + +__all__ = ["int64", "round64", + "kernel", "portable", "syscall", + "set_time_manager", "set_watchdog_factory", "ARTIQException"] # global namespace for kernels -kernel_globals = ("sequential", "parallel", +kernel_globals = ( + "sequential", "parallel", "delay_mu", "now_mu", "at_mu", "delay", "seconds_to_mu", "mu_to_seconds", - "syscall", "watchdog") + "watchdog" +) __all__.extend(kernel_globals) @@ -78,11 +82,12 @@ def round64(x): return int64(round(x)) -_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo", "core_name function") - +_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo", + "core_name function syscall") def kernel(arg): - """This decorator marks an object's method for execution on the core + """ + This decorator marks an object's method for execution on the core device. When a decorated method is called from the Python interpreter, the ``core`` @@ -106,15 +111,15 @@ def kernel(arg): def run_on_core(self, *k_args, **k_kwargs): return getattr(self, arg).run(function, ((self,) + k_args), k_kwargs) run_on_core.artiq_embedded = _ARTIQEmbeddedInfo( - core_name=arg, function=function) + core_name=arg, function=function, syscall=None) return run_on_core return inner_decorator else: return kernel("core")(arg) - def portable(function): - """This decorator marks a function for execution on the same device as its + """ + This decorator marks a function for execution on the same device as its caller. In other words, a decorated function called from the interpreter on the @@ -122,9 +127,31 @@ def portable(function): core device). A decorated function called from a kernel will be executed on the core device (no RPC). """ - function.artiq_embedded = _ARTIQEmbeddedInfo(core_name="", function=function) + function.artiq_embedded = \ + _ARTIQEmbeddedInfo(core_name=None, function=function, syscall=None) return function +def syscall(arg): + """ + This decorator marks a function as a system call. When executed on a core + device, a C function with the provided name (or the same name as + the Python function, if not provided) will be called. When executed on + host, the Python function will be called as usual. + + Every argument and the return value must be annotated with ARTIQ types. + + Only drivers should normally define syscalls. + """ + if isinstance(arg, str): + def inner_decorator(function): + function.artiq_embedded = \ + _ARTIQEmbeddedInfo(core_name=None, function=None, + syscall=function.__name__) + return function + return inner_decorator + else: + return syscall(arg.__name__)(arg) + class _DummyTimeManager: def _not_implemented(self, *args, **kwargs): @@ -152,22 +179,6 @@ def set_time_manager(time_manager): _time_manager = time_manager -class _DummySyscallManager: - def do(self, *args): - raise NotImplementedError( - "Attempted to interpret kernel without a syscall manager") - -_syscall_manager = _DummySyscallManager() - - -def set_syscall_manager(syscall_manager): - """Set the system call manager used for simulating the core device's - runtime in the Python interpreter. - """ - global _syscall_manager - _syscall_manager = syscall_manager - - class _Sequential: """In a sequential block, statements are executed one after another, with the time increasing as one moves down the statement list.""" @@ -240,17 +251,6 @@ def mu_to_seconds(mu, core=None): return mu*core.ref_period -def syscall(*args): - """Invokes a service of the runtime. - - Kernels use this function to interface to the outside world: program RTIO - events, make RPCs, etc. - - Only drivers should normally use ``syscall``. - """ - return _syscall_manager.do(*args) - - class _DummyWatchdog: def __init__(self, timeout): pass