forked from M-Labs/artiq
Merge branch 'master' into phaser
* master: (47 commits) runtime: disable the Nagle algorithm entirely. runtime: buffer RPC send packets. runtime: don't print debug messages to the UART. runtime: print microsecond timestamps in debug messages. artiq_devtool: abort if build failed. conda: bump llvmlite-artiq dep. conda: bump llvmlite-artiq dep. llvm_ir_generator: use !{→unconditionally.}invariant.load metadata. artiq_devtool: more robust port forwarding. setup: remove paramiko dependency (optional and developer-only) artiq_devtool: implement. artiq_compile: actually disable attribute writeback. conda: use pythonparser 1.0. conda: tighten pythonparser dependency (fixes #600). doc: clarify kernel_invariant doc (fixes #609). compiler: Emit all-kernel_invariant objects as LLVM constants conda: update for LLVM 3.9. add has_dds, use config flags Revert "Revert "Revert "Revert "Update for LLVM 3.9."""" Revert "Revert "Revert "Update for LLVM 3.9.""" ...
This commit is contained in:
commit
aedb6747f2
|
@ -994,8 +994,24 @@ class Stitcher:
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
is_async = False
|
||||||
|
if hasattr(host_function, "artiq_embedded") and \
|
||||||
|
"async" in host_function.artiq_embedded.flags:
|
||||||
|
is_async = True
|
||||||
|
|
||||||
|
if not builtins.is_none(ret_type) and is_async:
|
||||||
|
note = diagnostic.Diagnostic("note",
|
||||||
|
"function called here", {},
|
||||||
|
loc)
|
||||||
|
diag = diagnostic.Diagnostic("fatal",
|
||||||
|
"functions that return a value cannot be defined as async RPCs", {},
|
||||||
|
self._function_loc(host_function.artiq_embedded.function),
|
||||||
|
notes=[note])
|
||||||
|
self.engine.process(diag)
|
||||||
|
|
||||||
function_type = types.TRPC(ret_type,
|
function_type = types.TRPC(ret_type,
|
||||||
service=self.embedding_map.store_object(host_function))
|
service=self.embedding_map.store_object(host_function),
|
||||||
|
async=is_async)
|
||||||
self.functions[function] = function_type
|
self.functions[function] = function_type
|
||||||
return function_type
|
return function_type
|
||||||
|
|
||||||
|
@ -1007,7 +1023,11 @@ class Stitcher:
|
||||||
|
|
||||||
if function in self.functions:
|
if function in self.functions:
|
||||||
pass
|
pass
|
||||||
elif not hasattr(host_function, "artiq_embedded"):
|
elif not hasattr(host_function, "artiq_embedded") or \
|
||||||
|
(host_function.artiq_embedded.core_name is None and
|
||||||
|
host_function.artiq_embedded.portable is False and
|
||||||
|
host_function.artiq_embedded.syscall is None and
|
||||||
|
host_function.artiq_embedded.forbidden is False):
|
||||||
self._quote_rpc(function, loc)
|
self._quote_rpc(function, loc)
|
||||||
elif host_function.artiq_embedded.function is not None:
|
elif host_function.artiq_embedded.function is not None:
|
||||||
if host_function.__name__ == "<lambda>":
|
if host_function.__name__ == "<lambda>":
|
||||||
|
|
|
@ -40,7 +40,8 @@ class Source:
|
||||||
return cls(source.Buffer(f.read(), filename, 1), engine=engine)
|
return cls(source.Buffer(f.read(), filename, 1), engine=engine)
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
def __init__(self, src, ref_period=1e-6):
|
def __init__(self, src, ref_period=1e-6, attribute_writeback=True):
|
||||||
|
self.attribute_writeback = attribute_writeback
|
||||||
self.engine = src.engine
|
self.engine = src.engine
|
||||||
self.embedding_map = src.embedding_map
|
self.embedding_map = src.embedding_map
|
||||||
self.name = src.name
|
self.name = src.name
|
||||||
|
@ -79,7 +80,8 @@ class Module:
|
||||||
llvm_ir_generator = transforms.LLVMIRGenerator(
|
llvm_ir_generator = transforms.LLVMIRGenerator(
|
||||||
engine=self.engine, module_name=self.name, target=target,
|
engine=self.engine, module_name=self.name, target=target,
|
||||||
embedding_map=self.embedding_map)
|
embedding_map=self.embedding_map)
|
||||||
return llvm_ir_generator.process(self.artiq_ir, attribute_writeback=True)
|
return llvm_ir_generator.process(self.artiq_ir,
|
||||||
|
attribute_writeback=self.attribute_writeback)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
printer = types.TypePrinter()
|
printer = types.TypePrinter()
|
||||||
|
|
|
@ -31,6 +31,7 @@ def globals():
|
||||||
# ARTIQ decorators
|
# ARTIQ decorators
|
||||||
"kernel": builtins.fn_kernel(),
|
"kernel": builtins.fn_kernel(),
|
||||||
"portable": builtins.fn_kernel(),
|
"portable": builtins.fn_kernel(),
|
||||||
|
"rpc": builtins.fn_kernel(),
|
||||||
|
|
||||||
# ARTIQ context managers
|
# ARTIQ context managers
|
||||||
"parallel": builtins.obj_parallel(),
|
"parallel": builtins.obj_parallel(),
|
||||||
|
|
|
@ -86,14 +86,11 @@ class Target:
|
||||||
llmachine = lltarget.create_target_machine(
|
llmachine = lltarget.create_target_machine(
|
||||||
features=",".join(["+{}".format(f) for f in self.features]),
|
features=",".join(["+{}".format(f) for f in self.features]),
|
||||||
reloc="pic", codemodel="default")
|
reloc="pic", codemodel="default")
|
||||||
llmachine.set_verbose(True)
|
llmachine.set_asm_verbosity(True)
|
||||||
return llmachine
|
return llmachine
|
||||||
|
|
||||||
def optimize(self, llmodule):
|
def optimize(self, llmodule):
|
||||||
llmachine = self.target_machine()
|
|
||||||
llpassmgr = llvm.create_module_pass_manager()
|
llpassmgr = llvm.create_module_pass_manager()
|
||||||
llmachine.target_data.add_pass(llpassmgr)
|
|
||||||
llmachine.add_analysis_passes(llpassmgr)
|
|
||||||
|
|
||||||
# Register our alias analysis passes.
|
# Register our alias analysis passes.
|
||||||
llpassmgr.add_basic_alias_analysis_pass()
|
llpassmgr.add_basic_alias_analysis_pass()
|
||||||
|
|
|
@ -452,30 +452,30 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
self.current_block = body
|
self.current_block = body
|
||||||
self.visit(node.body)
|
self.visit(node.body)
|
||||||
post_body = self.current_block
|
post_body = self.current_block
|
||||||
|
|
||||||
if any(node.orelse):
|
|
||||||
else_tail = self.add_block("while.else")
|
|
||||||
self.current_block = else_tail
|
|
||||||
self.visit(node.orelse)
|
|
||||||
post_else_tail = self.current_block
|
|
||||||
|
|
||||||
tail = self.add_block("while.tail")
|
|
||||||
self.current_block = tail
|
|
||||||
|
|
||||||
if any(node.orelse):
|
|
||||||
if not post_else_tail.is_terminated():
|
|
||||||
post_else_tail.append(ir.Branch(tail))
|
|
||||||
else:
|
|
||||||
else_tail = tail
|
|
||||||
|
|
||||||
post_head.append(ir.BranchIf(cond, body, else_tail))
|
|
||||||
if not post_body.is_terminated():
|
|
||||||
post_body.append(ir.Branch(head))
|
|
||||||
break_block.append(ir.Branch(tail))
|
|
||||||
finally:
|
finally:
|
||||||
self.break_target = old_break
|
self.break_target = old_break
|
||||||
self.continue_target = old_continue
|
self.continue_target = old_continue
|
||||||
|
|
||||||
|
if any(node.orelse):
|
||||||
|
else_tail = self.add_block("while.else")
|
||||||
|
self.current_block = else_tail
|
||||||
|
self.visit(node.orelse)
|
||||||
|
post_else_tail = self.current_block
|
||||||
|
|
||||||
|
tail = self.add_block("while.tail")
|
||||||
|
self.current_block = tail
|
||||||
|
|
||||||
|
if any(node.orelse):
|
||||||
|
if not post_else_tail.is_terminated():
|
||||||
|
post_else_tail.append(ir.Branch(tail))
|
||||||
|
else:
|
||||||
|
else_tail = tail
|
||||||
|
|
||||||
|
post_head.append(ir.BranchIf(cond, body, else_tail))
|
||||||
|
if not post_body.is_terminated():
|
||||||
|
post_body.append(ir.Branch(head))
|
||||||
|
break_block.append(ir.Branch(tail))
|
||||||
|
|
||||||
def iterable_len(self, value, typ=_size_type):
|
def iterable_len(self, value, typ=_size_type):
|
||||||
if builtins.is_listish(value.type):
|
if builtins.is_listish(value.type):
|
||||||
if isinstance(value, ir.Constant):
|
if isinstance(value, ir.Constant):
|
||||||
|
@ -541,33 +541,33 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
self.current_assign = None
|
self.current_assign = None
|
||||||
self.visit(node.body)
|
self.visit(node.body)
|
||||||
post_body = self.current_block
|
post_body = self.current_block
|
||||||
|
|
||||||
if any(node.orelse):
|
|
||||||
else_tail = self.add_block("for.else")
|
|
||||||
self.current_block = else_tail
|
|
||||||
self.visit(node.orelse)
|
|
||||||
post_else_tail = self.current_block
|
|
||||||
|
|
||||||
tail = self.add_block("for.tail")
|
|
||||||
self.current_block = tail
|
|
||||||
|
|
||||||
if any(node.orelse):
|
|
||||||
if not post_else_tail.is_terminated():
|
|
||||||
post_else_tail.append(ir.Branch(tail))
|
|
||||||
else:
|
|
||||||
else_tail = tail
|
|
||||||
|
|
||||||
if node.trip_count is not None:
|
|
||||||
head.append(ir.Loop(node.trip_count, phi, cond, body, else_tail))
|
|
||||||
else:
|
|
||||||
head.append(ir.BranchIf(cond, body, else_tail))
|
|
||||||
if not post_body.is_terminated():
|
|
||||||
post_body.append(ir.Branch(continue_block))
|
|
||||||
break_block.append(ir.Branch(tail))
|
|
||||||
finally:
|
finally:
|
||||||
self.break_target = old_break
|
self.break_target = old_break
|
||||||
self.continue_target = old_continue
|
self.continue_target = old_continue
|
||||||
|
|
||||||
|
if any(node.orelse):
|
||||||
|
else_tail = self.add_block("for.else")
|
||||||
|
self.current_block = else_tail
|
||||||
|
self.visit(node.orelse)
|
||||||
|
post_else_tail = self.current_block
|
||||||
|
|
||||||
|
tail = self.add_block("for.tail")
|
||||||
|
self.current_block = tail
|
||||||
|
|
||||||
|
if any(node.orelse):
|
||||||
|
if not post_else_tail.is_terminated():
|
||||||
|
post_else_tail.append(ir.Branch(tail))
|
||||||
|
else:
|
||||||
|
else_tail = tail
|
||||||
|
|
||||||
|
if node.trip_count is not None:
|
||||||
|
head.append(ir.Loop(node.trip_count, phi, cond, body, else_tail))
|
||||||
|
else:
|
||||||
|
head.append(ir.BranchIf(cond, body, else_tail))
|
||||||
|
if not post_body.is_terminated():
|
||||||
|
post_body.append(ir.Branch(continue_block))
|
||||||
|
break_block.append(ir.Branch(tail))
|
||||||
|
|
||||||
def visit_Break(self, node):
|
def visit_Break(self, node):
|
||||||
self.append(ir.Branch(self.break_target))
|
self.append(ir.Branch(self.break_target))
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,7 @@ class ASTTypedRewriter(algorithm.Transformer):
|
||||||
visit_DictComp = visit_unsupported
|
visit_DictComp = visit_unsupported
|
||||||
visit_Ellipsis = visit_unsupported
|
visit_Ellipsis = visit_unsupported
|
||||||
visit_GeneratorExp = visit_unsupported
|
visit_GeneratorExp = visit_unsupported
|
||||||
visit_Set = visit_unsupported
|
# visit_Set = visit_unsupported
|
||||||
visit_SetComp = visit_unsupported
|
visit_SetComp = visit_unsupported
|
||||||
visit_Starred = visit_unsupported
|
visit_Starred = visit_unsupported
|
||||||
visit_Yield = visit_unsupported
|
visit_Yield = visit_unsupported
|
||||||
|
|
|
@ -37,9 +37,16 @@ def memoize(generator):
|
||||||
class DebugInfoEmitter:
|
class DebugInfoEmitter:
|
||||||
def __init__(self, llmodule):
|
def __init__(self, llmodule):
|
||||||
self.llmodule = llmodule
|
self.llmodule = llmodule
|
||||||
self.llsubprograms = []
|
self.llcompileunit = None
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
|
|
||||||
|
llident = self.llmodule.add_named_metadata('llvm.ident')
|
||||||
|
llident.add(self.emit_metadata(["ARTIQ"]))
|
||||||
|
|
||||||
|
llflags = self.llmodule.add_named_metadata('llvm.module.flags')
|
||||||
|
llflags.add(self.emit_metadata([2, "Debug Info Version", 3]))
|
||||||
|
llflags.add(self.emit_metadata([2, "Dwarf Version", 4]))
|
||||||
|
|
||||||
def emit_metadata(self, operands):
|
def emit_metadata(self, operands):
|
||||||
def map_operand(operand):
|
def map_operand(operand):
|
||||||
if operand is None:
|
if operand is None:
|
||||||
|
@ -67,14 +74,13 @@ class DebugInfoEmitter:
|
||||||
})
|
})
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
def emit_compile_unit(self, source_buffer, llsubprograms):
|
def emit_compile_unit(self, source_buffer):
|
||||||
return self.emit_debug_info("DICompileUnit", {
|
return self.emit_debug_info("DICompileUnit", {
|
||||||
"language": ll.DIToken("DW_LANG_Python"),
|
"language": ll.DIToken("DW_LANG_Python"),
|
||||||
"file": self.emit_file(source_buffer),
|
"file": self.emit_file(source_buffer),
|
||||||
"producer": "ARTIQ",
|
"producer": "ARTIQ",
|
||||||
"runtimeVersion": 0,
|
"runtimeVersion": 0,
|
||||||
"emissionKind": 2, # full=1, lines only=2
|
"emissionKind": 2, # full=1, lines only=2
|
||||||
"subprograms": self.emit_metadata(llsubprograms)
|
|
||||||
}, is_distinct=True)
|
}, is_distinct=True)
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
|
@ -86,21 +92,26 @@ class DebugInfoEmitter:
|
||||||
@memoize
|
@memoize
|
||||||
def emit_subprogram(self, func, llfunc):
|
def emit_subprogram(self, func, llfunc):
|
||||||
source_buffer = func.loc.source_buffer
|
source_buffer = func.loc.source_buffer
|
||||||
|
|
||||||
|
if self.llcompileunit is None:
|
||||||
|
self.llcompileunit = self.emit_compile_unit(source_buffer)
|
||||||
|
llcompileunits = self.llmodule.add_named_metadata('llvm.dbg.cu')
|
||||||
|
llcompileunits.add(self.llcompileunit)
|
||||||
|
|
||||||
display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type))
|
display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type))
|
||||||
llsubprogram = self.emit_debug_info("DISubprogram", {
|
return self.emit_debug_info("DISubprogram", {
|
||||||
"name": func.name,
|
"name": func.name,
|
||||||
"linkageName": llfunc.name,
|
"linkageName": llfunc.name,
|
||||||
"type": self.emit_subroutine_type(func.type),
|
"type": self.emit_subroutine_type(func.type),
|
||||||
"file": self.emit_file(source_buffer),
|
"file": self.emit_file(source_buffer),
|
||||||
"line": func.loc.line(),
|
"line": func.loc.line(),
|
||||||
|
"unit": self.llcompileunit,
|
||||||
"scope": self.emit_file(source_buffer),
|
"scope": self.emit_file(source_buffer),
|
||||||
"scopeLine": func.loc.line(),
|
"scopeLine": func.loc.line(),
|
||||||
"isLocal": func.is_internal,
|
"isLocal": func.is_internal,
|
||||||
"isDefinition": True,
|
"isDefinition": True,
|
||||||
"variables": self.emit_metadata([])
|
"variables": self.emit_metadata([])
|
||||||
}, is_distinct=True)
|
}, is_distinct=True)
|
||||||
self.llsubprograms.append(llsubprogram)
|
|
||||||
return llsubprogram
|
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
def emit_loc(self, loc, scope):
|
def emit_loc(self, loc, scope):
|
||||||
|
@ -110,18 +121,6 @@ class DebugInfoEmitter:
|
||||||
"scope": scope
|
"scope": scope
|
||||||
})
|
})
|
||||||
|
|
||||||
def finalize(self, source_buffer):
|
|
||||||
llident = self.llmodule.add_named_metadata('llvm.ident')
|
|
||||||
llident.add(self.emit_metadata(["ARTIQ"]))
|
|
||||||
|
|
||||||
llflags = self.llmodule.add_named_metadata('llvm.module.flags')
|
|
||||||
llflags.add(self.emit_metadata([2, "Debug Info Version", 3]))
|
|
||||||
llflags.add(self.emit_metadata([2, "Dwarf Version", 4]))
|
|
||||||
|
|
||||||
llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu')
|
|
||||||
llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.llsubprograms)))
|
|
||||||
|
|
||||||
|
|
||||||
class LLVMIRGenerator:
|
class LLVMIRGenerator:
|
||||||
def __init__(self, engine, module_name, target, embedding_map):
|
def __init__(self, engine, module_name, target, embedding_map):
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
|
@ -323,6 +322,8 @@ class LLVMIRGenerator:
|
||||||
llty = ll.FunctionType(llvoid, [])
|
llty = ll.FunctionType(llvoid, [])
|
||||||
elif name == "llvm.floor.f64":
|
elif name == "llvm.floor.f64":
|
||||||
llty = ll.FunctionType(lldouble, [lldouble])
|
llty = ll.FunctionType(lldouble, [lldouble])
|
||||||
|
elif name == "llvm.round.f64":
|
||||||
|
llty = ll.FunctionType(lldouble, [lldouble])
|
||||||
elif name == "llvm.pow.f64":
|
elif name == "llvm.pow.f64":
|
||||||
llty = ll.FunctionType(lldouble, [lldouble, lldouble])
|
llty = ll.FunctionType(lldouble, [lldouble, lldouble])
|
||||||
elif name == "llvm.powi.f64":
|
elif name == "llvm.powi.f64":
|
||||||
|
@ -347,10 +348,10 @@ class LLVMIRGenerator:
|
||||||
llty = ll.FunctionType(lli32, [llptr])
|
llty = ll.FunctionType(lli32, [llptr])
|
||||||
elif name == "strcmp":
|
elif name == "strcmp":
|
||||||
llty = ll.FunctionType(lli32, [llptr, llptr])
|
llty = ll.FunctionType(lli32, [llptr, llptr])
|
||||||
elif name == "lround":
|
|
||||||
llty = ll.FunctionType(lli32, [lldouble])
|
|
||||||
elif name == "send_rpc":
|
elif name == "send_rpc":
|
||||||
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
|
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
|
||||||
|
elif name == "send_async_rpc":
|
||||||
|
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
|
||||||
elif name == "recv_rpc":
|
elif name == "recv_rpc":
|
||||||
llty = ll.FunctionType(lli32, [llptr])
|
llty = ll.FunctionType(lli32, [llptr])
|
||||||
elif name == "now":
|
elif name == "now":
|
||||||
|
@ -366,7 +367,8 @@ class LLVMIRGenerator:
|
||||||
llglobal = ll.Function(self.llmodule, llty, name)
|
llglobal = ll.Function(self.llmodule, llty, name)
|
||||||
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
|
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
|
||||||
llglobal.attributes.add("noreturn")
|
llglobal.attributes.add("noreturn")
|
||||||
if name in ("rtio_log", "send_rpc", "watchdog_set", "watchdog_clear",
|
if name in ("rtio_log", "send_rpc", "send_async_rpc",
|
||||||
|
"watchdog_set", "watchdog_clear",
|
||||||
self.target.print_function):
|
self.target.print_function):
|
||||||
llglobal.attributes.add("nounwind")
|
llglobal.attributes.add("nounwind")
|
||||||
else:
|
else:
|
||||||
|
@ -407,9 +409,6 @@ class LLVMIRGenerator:
|
||||||
for func in functions:
|
for func in functions:
|
||||||
self.process_function(func)
|
self.process_function(func)
|
||||||
|
|
||||||
if any(functions):
|
|
||||||
self.debug_info_emitter.finalize(functions[0].loc.source_buffer)
|
|
||||||
|
|
||||||
if attribute_writeback and self.embedding_map is not None:
|
if attribute_writeback and self.embedding_map is not None:
|
||||||
self.emit_attribute_writeback()
|
self.emit_attribute_writeback()
|
||||||
|
|
||||||
|
@ -652,7 +651,7 @@ class LLVMIRGenerator:
|
||||||
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)
|
inbounds=True)
|
||||||
llouterenv = self.llbuilder.load(llptr)
|
llouterenv = self.llbuilder.load(llptr)
|
||||||
llouterenv.set_metadata('invariant.load', self.empty_metadata)
|
llouterenv.set_metadata('unconditionally.invariant.load', self.empty_metadata)
|
||||||
llouterenv.set_metadata('nonnull', self.empty_metadata)
|
llouterenv.set_metadata('nonnull', 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)
|
||||||
|
|
||||||
|
@ -796,7 +795,7 @@ class LLVMIRGenerator:
|
||||||
inbounds=True, name="ptr.{}".format(insn.name))
|
inbounds=True, name="ptr.{}".format(insn.name))
|
||||||
llvalue = self.llbuilder.load(llptr, name="val.{}".format(insn.name))
|
llvalue = self.llbuilder.load(llptr, name="val.{}".format(insn.name))
|
||||||
if types.is_instance(typ) and attr in typ.constant_attributes:
|
if types.is_instance(typ) and attr in typ.constant_attributes:
|
||||||
llvalue.set_metadata('invariant.load', self.empty_metadata)
|
llvalue.set_metadata('unconditionally.invariant.load', self.empty_metadata)
|
||||||
if isinstance(llvalue.type, ll.PointerType):
|
if isinstance(llvalue.type, ll.PointerType):
|
||||||
self.mark_dereferenceable(llvalue)
|
self.mark_dereferenceable(llvalue)
|
||||||
return llvalue
|
return llvalue
|
||||||
|
@ -1041,8 +1040,9 @@ class LLVMIRGenerator:
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
elif insn.op == "round":
|
elif insn.op == "round":
|
||||||
llarg = self.map(insn.operands[0])
|
llarg = self.map(insn.operands[0])
|
||||||
return self.llbuilder.call(self.llbuiltin("lround"), [llarg],
|
llvalue = self.llbuilder.call(self.llbuiltin("llvm.round.f64"), [llarg])
|
||||||
name=insn.name)
|
return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type),
|
||||||
|
name=insn.name)
|
||||||
elif insn.op == "globalenv":
|
elif insn.op == "globalenv":
|
||||||
def get_outer(llenv, env_ty):
|
def get_outer(llenv, env_ty):
|
||||||
if "$outer" in env_ty.params:
|
if "$outer" in env_ty.params:
|
||||||
|
@ -1050,7 +1050,7 @@ class LLVMIRGenerator:
|
||||||
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)
|
inbounds=True)
|
||||||
llouterenv = self.llbuilder.load(llptr)
|
llouterenv = self.llbuilder.load(llptr)
|
||||||
llouterenv.set_metadata('invariant.load', self.empty_metadata)
|
llouterenv.set_metadata('unconditionally.invariant.load', self.empty_metadata)
|
||||||
llouterenv.set_metadata('nonnull', self.empty_metadata)
|
llouterenv.set_metadata('nonnull', 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:
|
||||||
|
@ -1248,17 +1248,26 @@ class LLVMIRGenerator:
|
||||||
llargptr = self.llbuilder.gep(llargs, [ll.Constant(lli32, index)])
|
llargptr = self.llbuilder.gep(llargs, [ll.Constant(lli32, index)])
|
||||||
self.llbuilder.store(llargslot, llargptr)
|
self.llbuilder.store(llargslot, llargptr)
|
||||||
|
|
||||||
self.llbuilder.call(self.llbuiltin("send_rpc"),
|
if fun_type.async:
|
||||||
[llservice, lltag, llargs])
|
self.llbuilder.call(self.llbuiltin("send_async_rpc"),
|
||||||
|
[llservice, lltag, llargs])
|
||||||
|
else:
|
||||||
|
self.llbuilder.call(self.llbuiltin("send_rpc"),
|
||||||
|
[llservice, lltag, llargs])
|
||||||
|
|
||||||
# Don't waste stack space on saved arguments.
|
# Don't waste stack space on saved arguments.
|
||||||
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
||||||
|
|
||||||
|
if fun_type.async:
|
||||||
|
return ll.Undefined
|
||||||
|
|
||||||
# T result = {
|
# T result = {
|
||||||
# void *ptr = NULL;
|
# void *ret_ptr = alloca(sizeof(T));
|
||||||
# loop: int size = rpc_recv("tag", ptr);
|
# void *ptr = ret_ptr;
|
||||||
|
# loop: int size = recv_rpc(ptr);
|
||||||
|
# // Non-zero: Provide `size` bytes of extra storage for variable-length data.
|
||||||
# if(size) { ptr = alloca(size); goto loop; }
|
# if(size) { ptr = alloca(size); goto loop; }
|
||||||
# else *(T*)ptr
|
# else *(T*)ret_ptr
|
||||||
# }
|
# }
|
||||||
llprehead = self.llbuilder.basic_block
|
llprehead = self.llbuilder.basic_block
|
||||||
llhead = self.llbuilder.append_basic_block(name="rpc.head")
|
llhead = self.llbuilder.append_basic_block(name="rpc.head")
|
||||||
|
@ -1273,7 +1282,7 @@ class LLVMIRGenerator:
|
||||||
self.llbuilder.branch(llhead)
|
self.llbuilder.branch(llhead)
|
||||||
|
|
||||||
self.llbuilder.position_at_end(llhead)
|
self.llbuilder.position_at_end(llhead)
|
||||||
llphi = self.llbuilder.phi(llslotgen.type, name="rpc.size")
|
llphi = self.llbuilder.phi(llslotgen.type, name="rpc.ptr")
|
||||||
llphi.add_incoming(llslotgen, llprehead)
|
llphi.add_incoming(llslotgen, llprehead)
|
||||||
if llunwindblock:
|
if llunwindblock:
|
||||||
llsize = self.llbuilder.invoke(self.llbuiltin("recv_rpc"), [llphi],
|
llsize = self.llbuilder.invoke(self.llbuiltin("recv_rpc"), [llphi],
|
||||||
|
@ -1375,6 +1384,7 @@ class LLVMIRGenerator:
|
||||||
def _quote_attributes():
|
def _quote_attributes():
|
||||||
llglobal = None
|
llglobal = None
|
||||||
llfields = []
|
llfields = []
|
||||||
|
emit_as_constant = True
|
||||||
for attr in typ.attributes:
|
for attr in typ.attributes:
|
||||||
if attr == "__objectid__":
|
if attr == "__objectid__":
|
||||||
objectid = self.embedding_map.store_object(value)
|
objectid = self.embedding_map.store_object(value)
|
||||||
|
@ -1395,6 +1405,8 @@ class LLVMIRGenerator:
|
||||||
not types.is_c_function(typ.attributes[attr]))
|
not types.is_c_function(typ.attributes[attr]))
|
||||||
if is_class_function:
|
if is_class_function:
|
||||||
attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue)
|
attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue)
|
||||||
|
if not (types.is_instance(typ) and attr in typ.constant_attributes):
|
||||||
|
emit_as_constant = False
|
||||||
llattrvalue = self._quote(attrvalue, typ.attributes[attr],
|
llattrvalue = self._quote(attrvalue, typ.attributes[attr],
|
||||||
lambda: path() + [attr])
|
lambda: path() + [attr])
|
||||||
llfields.append(llattrvalue)
|
llfields.append(llattrvalue)
|
||||||
|
@ -1402,6 +1414,7 @@ class LLVMIRGenerator:
|
||||||
llclosureptr = self.get_global_closure_ptr(typ, attr)
|
llclosureptr = self.get_global_closure_ptr(typ, attr)
|
||||||
llclosureptr.initializer = llattrvalue
|
llclosureptr.initializer = llattrvalue
|
||||||
|
|
||||||
|
llglobal.global_constant = emit_as_constant
|
||||||
llglobal.initializer = ll.Constant(llty.pointee, llfields)
|
llglobal.initializer = ll.Constant(llty.pointee, llfields)
|
||||||
llglobal.linkage = "private"
|
llglobal.linkage = "private"
|
||||||
return llglobal
|
return llglobal
|
||||||
|
|
|
@ -308,20 +308,22 @@ class TRPC(Type):
|
||||||
:ivar ret: (:class:`Type`)
|
:ivar ret: (:class:`Type`)
|
||||||
return type
|
return type
|
||||||
:ivar service: (int) RPC service number
|
:ivar service: (int) RPC service number
|
||||||
|
:ivar async: (bool) whether the RPC blocks until return
|
||||||
"""
|
"""
|
||||||
|
|
||||||
attributes = OrderedDict()
|
attributes = OrderedDict()
|
||||||
|
|
||||||
def __init__(self, ret, service):
|
def __init__(self, ret, service, async=False):
|
||||||
assert isinstance(ret, Type)
|
assert isinstance(ret, Type)
|
||||||
self.ret, self.service = ret, service
|
self.ret, self.service, self.async = ret, service, async
|
||||||
|
|
||||||
def find(self):
|
def find(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def unify(self, other):
|
def unify(self, other):
|
||||||
if isinstance(other, TRPC) and \
|
if isinstance(other, TRPC) and \
|
||||||
self.service == other.service:
|
self.service == other.service and \
|
||||||
|
self.async == other.async:
|
||||||
self.ret.unify(other.ret)
|
self.ret.unify(other.ret)
|
||||||
elif isinstance(other, TVar):
|
elif isinstance(other, TVar):
|
||||||
other.unify(self)
|
other.unify(self)
|
||||||
|
@ -337,7 +339,8 @@ class TRPC(Type):
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return isinstance(other, TRPC) and \
|
return isinstance(other, TRPC) and \
|
||||||
self.service == other.service
|
self.service == other.service and \
|
||||||
|
self.async == other.async
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not (self == other)
|
return not (self == other)
|
||||||
|
@ -727,7 +730,9 @@ class TypePrinter(object):
|
||||||
elif isinstance(typ, TFunction):
|
elif isinstance(typ, TFunction):
|
||||||
return signature
|
return signature
|
||||||
elif isinstance(typ, TRPC):
|
elif isinstance(typ, TRPC):
|
||||||
return "[rpc #{}](...)->{}".format(typ.service, self.name(typ.ret, depth + 1))
|
return "[rpc{} #{}](...)->{}".format(typ.service,
|
||||||
|
" async" if typ.async else "",
|
||||||
|
self.name(typ.ret, depth + 1))
|
||||||
elif isinstance(typ, TBuiltinFunction):
|
elif isinstance(typ, TBuiltinFunction):
|
||||||
return "<function {}>".format(typ.name)
|
return "<function {}>".format(typ.name)
|
||||||
elif isinstance(typ, (TConstructor, TExceptionConstructor)):
|
elif isinstance(typ, (TConstructor, TExceptionConstructor)):
|
||||||
|
|
|
@ -141,6 +141,9 @@ class CommGeneric:
|
||||||
(value, ) = struct.unpack(">d", self._read_chunk(8))
|
(value, ) = struct.unpack(">d", self._read_chunk(8))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def _read_bool(self):
|
||||||
|
return True if self._read_int8() else False
|
||||||
|
|
||||||
def _read_bytes(self):
|
def _read_bytes(self):
|
||||||
return self._read_chunk(self._read_int32())
|
return self._read_chunk(self._read_int32())
|
||||||
|
|
||||||
|
@ -177,6 +180,9 @@ class CommGeneric:
|
||||||
def _write_float64(self, value):
|
def _write_float64(self, value):
|
||||||
self.write(struct.pack(">d", value))
|
self.write(struct.pack(">d", value))
|
||||||
|
|
||||||
|
def _write_bool(self, value):
|
||||||
|
self.write(struct.pack("B", value))
|
||||||
|
|
||||||
def _write_bytes(self, value):
|
def _write_bytes(self, value):
|
||||||
self._write_int32(len(value))
|
self._write_int32(len(value))
|
||||||
self.write(value)
|
self.write(value)
|
||||||
|
@ -405,24 +411,29 @@ class CommGeneric:
|
||||||
raise IOError("Unknown RPC value tag: {}".format(repr(tag)))
|
raise IOError("Unknown RPC value tag: {}".format(repr(tag)))
|
||||||
|
|
||||||
def _serve_rpc(self, embedding_map):
|
def _serve_rpc(self, embedding_map):
|
||||||
service_id = self._read_int32()
|
async = self._read_bool()
|
||||||
if service_id == 0:
|
service_id = self._read_int32()
|
||||||
service = lambda obj, attr, value: setattr(obj, attr, value)
|
|
||||||
else:
|
|
||||||
service = embedding_map.retrieve_object(service_id)
|
|
||||||
|
|
||||||
args, kwargs = self._receive_rpc_args(embedding_map)
|
args, kwargs = self._receive_rpc_args(embedding_map)
|
||||||
return_tags = self._read_bytes()
|
return_tags = self._read_bytes()
|
||||||
logger.debug("rpc service: [%d]%r %r %r -> %s", service_id, service, args, kwargs, return_tags)
|
|
||||||
|
if service_id is 0:
|
||||||
|
service = lambda obj, attr, value: setattr(obj, attr, value)
|
||||||
|
else:
|
||||||
|
service = embedding_map.retrieve_object(service_id)
|
||||||
|
logger.debug("rpc service: [%d]%r%s %r %r -> %s", service_id, service,
|
||||||
|
(" (async)" if async else ""), args, kwargs, return_tags)
|
||||||
|
|
||||||
|
if async:
|
||||||
|
service(*args, **kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = service(*args, **kwargs)
|
result = service(*args, **kwargs)
|
||||||
logger.debug("rpc service: %d %r %r == %r", service_id, args, kwargs, result)
|
logger.debug("rpc service: %d %r %r = %r", service_id, args, kwargs, result)
|
||||||
|
|
||||||
if service_id != 0:
|
self._write_header(_H2DMsgType.RPC_REPLY)
|
||||||
self._write_header(_H2DMsgType.RPC_REPLY)
|
self._write_bytes(return_tags)
|
||||||
self._write_bytes(return_tags)
|
self._send_rpc_value(bytearray(return_tags), result, result, service)
|
||||||
self._send_rpc_value(bytearray(return_tags), result, result, service)
|
|
||||||
except Exception as exn:
|
except Exception as exn:
|
||||||
logger.debug("rpc service: %d %r %r ! %r", service_id, args, kwargs, exn)
|
logger.debug("rpc service: %d %r %r ! %r", service_id, args, kwargs, exn)
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ class Core:
|
||||||
self.core = self
|
self.core = self
|
||||||
self.comm.core = self
|
self.comm.core = self
|
||||||
|
|
||||||
def compile(self, function, args, kwargs, set_result=None, with_attr_writeback=True):
|
def compile(self, function, args, kwargs, set_result=None, attribute_writeback=True):
|
||||||
try:
|
try:
|
||||||
engine = _DiagnosticEngine(all_errors_are_fatal=True)
|
engine = _DiagnosticEngine(all_errors_are_fatal=True)
|
||||||
|
|
||||||
|
@ -89,7 +89,9 @@ class Core:
|
||||||
stitcher.stitch_call(function, args, kwargs, set_result)
|
stitcher.stitch_call(function, args, kwargs, set_result)
|
||||||
stitcher.finalize()
|
stitcher.finalize()
|
||||||
|
|
||||||
module = Module(stitcher, ref_period=self.ref_period)
|
module = Module(stitcher,
|
||||||
|
ref_period=self.ref_period,
|
||||||
|
attribute_writeback=attribute_writeback)
|
||||||
target = OR1KTarget()
|
target = OR1KTarget()
|
||||||
|
|
||||||
library = target.compile_and_link([module])
|
library = target.compile_and_link([module])
|
||||||
|
@ -103,6 +105,7 @@ class Core:
|
||||||
|
|
||||||
def run(self, function, args, kwargs):
|
def run(self, function, args, kwargs):
|
||||||
result = None
|
result = None
|
||||||
|
@rpc(flags={"async"})
|
||||||
def set_result(new_result):
|
def set_result(new_result):
|
||||||
nonlocal result
|
nonlocal result
|
||||||
result = new_result
|
result = new_result
|
||||||
|
|
|
@ -23,35 +23,26 @@ _mode_enc = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class _MoninjWidget(QtWidgets.QFrame):
|
class _TTLWidget(QtWidgets.QFrame):
|
||||||
def __init__(self):
|
|
||||||
QtWidgets.QFrame.__init__(self)
|
|
||||||
qfm = QtGui.QFontMetrics(self.font())
|
|
||||||
self._size = QtCore.QSize(
|
|
||||||
18*qfm.averageCharWidth(),
|
|
||||||
6*qfm.lineSpacing())
|
|
||||||
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
|
||||||
|
|
||||||
self.setFrameShape(QtWidgets.QFrame.Box)
|
|
||||||
self.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
||||||
|
|
||||||
def sizeHint(self):
|
|
||||||
return self._size
|
|
||||||
|
|
||||||
|
|
||||||
class _TTLWidget(_MoninjWidget):
|
|
||||||
def __init__(self, channel, send_to_device, force_out, title):
|
def __init__(self, channel, send_to_device, force_out, title):
|
||||||
|
QtWidgets.QFrame.__init__(self)
|
||||||
|
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.send_to_device = send_to_device
|
self.send_to_device = send_to_device
|
||||||
self.force_out = force_out
|
self.force_out = force_out
|
||||||
|
|
||||||
_MoninjWidget.__init__(self)
|
self.setFrameShape(QtWidgets.QFrame.Box)
|
||||||
|
self.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
|
||||||
grid = QtWidgets.QGridLayout()
|
grid = QtWidgets.QGridLayout()
|
||||||
|
grid.setContentsMargins(0, 0, 0, 0)
|
||||||
|
grid.setHorizontalSpacing(0)
|
||||||
|
grid.setVerticalSpacing(0)
|
||||||
self.setLayout(grid)
|
self.setLayout(grid)
|
||||||
label = QtWidgets.QLabel(title)
|
label = QtWidgets.QLabel(title)
|
||||||
label.setAlignment(QtCore.Qt.AlignCenter)
|
label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
label.setWordWrap(True)
|
label.setSizePolicy(QtWidgets.QSizePolicy.Ignored,
|
||||||
|
QtWidgets.QSizePolicy.Preferred)
|
||||||
grid.addWidget(label, 1, 1)
|
grid.addWidget(label, 1, 1)
|
||||||
|
|
||||||
self.stack = QtWidgets.QStackedWidget()
|
self.stack = QtWidgets.QStackedWidget()
|
||||||
|
@ -62,9 +53,18 @@ class _TTLWidget(_MoninjWidget):
|
||||||
self.stack.addWidget(self.direction)
|
self.stack.addWidget(self.direction)
|
||||||
|
|
||||||
grid_cb = LayoutWidget()
|
grid_cb = LayoutWidget()
|
||||||
self.override = QtWidgets.QCheckBox("Override")
|
grid_cb.layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
grid_cb.layout.setHorizontalSpacing(0)
|
||||||
|
grid_cb.layout.setVerticalSpacing(0)
|
||||||
|
self.override = QtWidgets.QToolButton()
|
||||||
|
self.override.setText("OVR")
|
||||||
|
self.override.setCheckable(True)
|
||||||
|
self.override.setToolTip("Override")
|
||||||
grid_cb.addWidget(self.override, 3, 1)
|
grid_cb.addWidget(self.override, 3, 1)
|
||||||
self.level = QtWidgets.QCheckBox("Level")
|
self.level = QtWidgets.QToolButton()
|
||||||
|
self.level.setText("LVL")
|
||||||
|
self.level.setCheckable(True)
|
||||||
|
self.level.setToolTip("Level")
|
||||||
grid_cb.addWidget(self.level, 3, 2)
|
grid_cb.addWidget(self.level, 3, 2)
|
||||||
self.stack.addWidget(grid_cb)
|
self.stack.addWidget(grid_cb)
|
||||||
|
|
||||||
|
@ -78,19 +78,19 @@ class _TTLWidget(_MoninjWidget):
|
||||||
grid.setRowStretch(4, 1)
|
grid.setRowStretch(4, 1)
|
||||||
|
|
||||||
self.programmatic_change = False
|
self.programmatic_change = False
|
||||||
self.override.stateChanged.connect(self.override_toggled)
|
self.override.clicked.connect(self.override_toggled)
|
||||||
self.level.stateChanged.connect(self.level_toggled)
|
self.level.clicked.connect(self.level_toggled)
|
||||||
|
|
||||||
self.set_value(0, False, False)
|
self.set_value(0, False, False)
|
||||||
|
|
||||||
def enterEvent(self, event):
|
def enterEvent(self, event):
|
||||||
self.stack.setCurrentIndex(1)
|
self.stack.setCurrentIndex(1)
|
||||||
_MoninjWidget.enterEvent(self, event)
|
QtWidgets.QFrame.enterEvent(self, event)
|
||||||
|
|
||||||
def leaveEvent(self, event):
|
def leaveEvent(self, event):
|
||||||
if not self.override.isChecked():
|
if not self.override.isChecked():
|
||||||
self.stack.setCurrentIndex(0)
|
self.stack.setCurrentIndex(0)
|
||||||
_MoninjWidget.leaveEvent(self, event)
|
QtWidgets.QFrame.leaveEvent(self, event)
|
||||||
|
|
||||||
def override_toggled(self, override):
|
def override_toggled(self, override):
|
||||||
if self.programmatic_change:
|
if self.programmatic_change:
|
||||||
|
@ -125,11 +125,11 @@ class _TTLWidget(_MoninjWidget):
|
||||||
color = " color=\"red\""
|
color = " color=\"red\""
|
||||||
else:
|
else:
|
||||||
color = ""
|
color = ""
|
||||||
self.value.setText("<font size=\"9\"{}>{}</font>".format(
|
self.value.setText("<font size=\"5\"{}>{}</font>".format(
|
||||||
color, value_s))
|
color, value_s))
|
||||||
oe = oe or self.force_out
|
oe = oe or self.force_out
|
||||||
direction = "OUT" if oe else "IN"
|
direction = "OUT" if oe else "IN"
|
||||||
self.direction.setText("<font size=\"1\">" + direction + "</font>")
|
self.direction.setText("<font size=\"2\">" + direction + "</font>")
|
||||||
|
|
||||||
self.programmatic_change = True
|
self.programmatic_change = True
|
||||||
try:
|
try:
|
||||||
|
@ -144,24 +144,30 @@ class _TTLWidget(_MoninjWidget):
|
||||||
return self.channel
|
return self.channel
|
||||||
|
|
||||||
|
|
||||||
class _DDSWidget(_MoninjWidget):
|
class _DDSWidget(QtWidgets.QFrame):
|
||||||
def __init__(self, bus_channel, channel, sysclk, title):
|
def __init__(self, bus_channel, channel, sysclk, title):
|
||||||
|
QtWidgets.QFrame.__init__(self)
|
||||||
|
|
||||||
self.bus_channel = bus_channel
|
self.bus_channel = bus_channel
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.sysclk = sysclk
|
self.sysclk = sysclk
|
||||||
|
|
||||||
_MoninjWidget.__init__(self)
|
self.setFrameShape(QtWidgets.QFrame.Box)
|
||||||
|
self.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
|
||||||
grid = QtWidgets.QGridLayout()
|
grid = QtWidgets.QGridLayout()
|
||||||
|
grid.setContentsMargins(0, 0, 0, 0)
|
||||||
|
grid.setHorizontalSpacing(0)
|
||||||
|
grid.setVerticalSpacing(0)
|
||||||
self.setLayout(grid)
|
self.setLayout(grid)
|
||||||
label = QtWidgets.QLabel(title)
|
label = QtWidgets.QLabel(title)
|
||||||
label.setAlignment(QtCore.Qt.AlignCenter)
|
label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
label.setWordWrap(True)
|
label.setSizePolicy(QtWidgets.QSizePolicy.Ignored,
|
||||||
|
QtWidgets.QSizePolicy.Preferred)
|
||||||
grid.addWidget(label, 1, 1)
|
grid.addWidget(label, 1, 1)
|
||||||
|
|
||||||
self.value = QtWidgets.QLabel()
|
self.value = QtWidgets.QLabel()
|
||||||
self.value.setAlignment(QtCore.Qt.AlignCenter)
|
self.value.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
self.value.setWordWrap(True)
|
|
||||||
grid.addWidget(self.value, 2, 1, 6, 1)
|
grid.addWidget(self.value, 2, 1, 6, 1)
|
||||||
|
|
||||||
grid.setRowStretch(1, 1)
|
grid.setRowStretch(1, 1)
|
||||||
|
@ -172,7 +178,7 @@ class _DDSWidget(_MoninjWidget):
|
||||||
|
|
||||||
def set_value(self, ftw):
|
def set_value(self, ftw):
|
||||||
frequency = ftw*self.sysclk()/2**32
|
frequency = ftw*self.sysclk()/2**32
|
||||||
self.value.setText("<font size=\"5\">{:.7f} MHz</font>"
|
self.value.setText("<font size=\"4\">{:.7f}</font><font size=\"2\"> MHz</font>"
|
||||||
.format(frequency/1e6))
|
.format(frequency/1e6))
|
||||||
|
|
||||||
def sort_key(self):
|
def sort_key(self):
|
||||||
|
|
|
@ -55,7 +55,7 @@ def main():
|
||||||
|
|
||||||
object_map, kernel_library, _, _ = \
|
object_map, kernel_library, _, _ = \
|
||||||
core.compile(exp.run, [exp_inst], {},
|
core.compile(exp.run, [exp_inst], {},
|
||||||
with_attr_writeback=False)
|
attribute_writeback=False)
|
||||||
except CompileError as error:
|
except CompileError as error:
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
#!/usr/bin/env python3.5
|
||||||
|
|
||||||
|
# This script makes the following assumptions:
|
||||||
|
# * miniconda is installed remotely at ~/miniconda
|
||||||
|
# * misoc and artiq are installed remotely via conda
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
import socket
|
||||||
|
import select
|
||||||
|
import threading
|
||||||
|
import paramiko
|
||||||
|
|
||||||
|
from artiq.tools import verbosity_args, init_logger, logger
|
||||||
|
from random import Random
|
||||||
|
|
||||||
|
|
||||||
|
def get_argparser():
|
||||||
|
parser = argparse.ArgumentParser(description="ARTIQ core device "
|
||||||
|
"development tool")
|
||||||
|
|
||||||
|
verbosity_args(parser)
|
||||||
|
|
||||||
|
parser.add_argument("--host", nargs=1, metavar="HOST",
|
||||||
|
type=str, default="lab.m-labs.hk",
|
||||||
|
help="SSH host where the development board is located")
|
||||||
|
parser.add_argument("--serial", nargs=1, metavar="SERIAL",
|
||||||
|
type=str, default="/dev/ttyUSB0",
|
||||||
|
help="TTY device corresponding to the development board")
|
||||||
|
parser.add_argument("--ip", nargs=1, metavar="IP",
|
||||||
|
type=str, default="kc705.lab.m-labs.hk",
|
||||||
|
help="IP address corresponding to the development board")
|
||||||
|
|
||||||
|
parser.add_argument("actions", metavar="ACTION",
|
||||||
|
type=str, default=[], nargs="+",
|
||||||
|
help="actions to perform (sequence of: build boot connect)")
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = get_argparser().parse_args()
|
||||||
|
init_logger(args)
|
||||||
|
|
||||||
|
ssh = None
|
||||||
|
def get_ssh():
|
||||||
|
nonlocal ssh
|
||||||
|
if ssh is not None:
|
||||||
|
return ssh
|
||||||
|
ssh = paramiko.SSHClient()
|
||||||
|
ssh.load_system_host_keys()
|
||||||
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
ssh.connect(args.host)
|
||||||
|
return ssh
|
||||||
|
|
||||||
|
sftp = None
|
||||||
|
def get_sftp():
|
||||||
|
nonlocal sftp
|
||||||
|
if sftp is not None:
|
||||||
|
return sftp
|
||||||
|
sftp = get_ssh().open_sftp()
|
||||||
|
return sftp
|
||||||
|
|
||||||
|
rng = Random()
|
||||||
|
tmp = "artiq" + "".join([rng.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") for _ in range(6)])
|
||||||
|
env = "bash -c 'export PATH=$HOME/miniconda/bin:$PATH; exec $0 $*' "
|
||||||
|
|
||||||
|
def run_command(cmd):
|
||||||
|
logger.info("Executing {}".format(cmd))
|
||||||
|
chan = get_ssh().get_transport().open_session()
|
||||||
|
chan.set_combine_stderr(True)
|
||||||
|
chan.exec_command(cmd.format(tmp=tmp, env=env, serial=args.serial, ip=args.ip))
|
||||||
|
return chan.makefile()
|
||||||
|
|
||||||
|
def drain(chan):
|
||||||
|
while True:
|
||||||
|
char = chan.read(1)
|
||||||
|
if char == b"":
|
||||||
|
break
|
||||||
|
sys.stderr.write(char.decode("utf-8"))
|
||||||
|
|
||||||
|
for action in args.actions:
|
||||||
|
if action == "build":
|
||||||
|
logger.info("Building runtime")
|
||||||
|
try:
|
||||||
|
subprocess.check_call(["python3", "-m", "artiq.gateware.targets.kc705",
|
||||||
|
"-H", "nist_clock",
|
||||||
|
"--no-compile-gateware",
|
||||||
|
"--output-dir", "/tmp/kc705"])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
logger.error("Build failed")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
elif action == "boot":
|
||||||
|
logger.info("Uploading runtime")
|
||||||
|
get_sftp().mkdir("/tmp/{tmp}".format(tmp=tmp))
|
||||||
|
get_sftp().put("/tmp/kc705/software/runtime/runtime.bin",
|
||||||
|
"/tmp/{tmp}/runtime.bin".format(tmp=tmp))
|
||||||
|
|
||||||
|
logger.info("Booting runtime")
|
||||||
|
flterm = run_command(
|
||||||
|
"{env} python3 flterm.py {serial} " +
|
||||||
|
"--kernel /tmp/{tmp}/runtime.bin --upload-only")
|
||||||
|
artiq_flash = run_command(
|
||||||
|
"{env} artiq_flash start")
|
||||||
|
drain(flterm)
|
||||||
|
|
||||||
|
elif action == "connect":
|
||||||
|
def forwarder(port):
|
||||||
|
listener = socket.socket()
|
||||||
|
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
listener.bind(('localhost', port))
|
||||||
|
listener.listen(1)
|
||||||
|
while True:
|
||||||
|
local_stream, peer_addr = listener.accept()
|
||||||
|
logger.info("Accepting %s:%s and opening SSH channel to %s:%s",
|
||||||
|
*peer_addr, args.ip, port)
|
||||||
|
remote_stream = get_ssh().get_transport() \
|
||||||
|
.open_channel('direct-tcpip', (args.ip, port), peer_addr)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r, w, x = select.select([local_stream, remote_stream], [], [])
|
||||||
|
if local_stream in r:
|
||||||
|
data = local_stream.recv(1024)
|
||||||
|
if data == b"":
|
||||||
|
break
|
||||||
|
remote_stream.send(data)
|
||||||
|
if remote_stream in r:
|
||||||
|
data = remote_stream.recv(1024)
|
||||||
|
if data == b"":
|
||||||
|
break
|
||||||
|
local_stream.send(data)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("Forward error on port %s", port)
|
||||||
|
local_stream.close()
|
||||||
|
remote_stream.close()
|
||||||
|
|
||||||
|
for port in (1381, 1382):
|
||||||
|
thread = threading.Thread(target=forwarder, args=(port,),
|
||||||
|
name="port-{}".format(port), daemon=True)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
logger.info("Connecting to device")
|
||||||
|
flterm = run_command(
|
||||||
|
"{env} python3 flterm.py {serial} --output-only")
|
||||||
|
drain(flterm)
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.error("Unknown action {}".format(action))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -73,8 +73,7 @@ class LLVMIRRunner(FileRunner):
|
||||||
with open(self.file, "r") as f:
|
with open(self.file, "r") as f:
|
||||||
llmodule = llvm.parse_assembly(f.read())
|
llmodule = llvm.parse_assembly(f.read())
|
||||||
llmodule.verify()
|
llmodule.verify()
|
||||||
return self.target.link([self.target.assemble(llmodule)],
|
return self.target.link([self.target.assemble(llmodule)])
|
||||||
init_fn="__modinit__")
|
|
||||||
|
|
||||||
|
|
||||||
class LLVMBitcodeRunner(FileRunner):
|
class LLVMBitcodeRunner(FileRunner):
|
||||||
|
@ -82,8 +81,7 @@ class LLVMBitcodeRunner(FileRunner):
|
||||||
with open(self.file, "rb") as f:
|
with open(self.file, "rb") as f:
|
||||||
llmodule = llvm.parse_bitcode(f.read())
|
llmodule = llvm.parse_bitcode(f.read())
|
||||||
llmodule.verify()
|
llmodule.verify()
|
||||||
return self.target.link([self.target.assemble(llmodule)],
|
return self.target.link([self.target.assemble(llmodule)])
|
||||||
init_fn="__modinit__")
|
|
||||||
|
|
||||||
|
|
||||||
class DummyScheduler:
|
class DummyScheduler:
|
||||||
|
|
|
@ -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=0x40400000,
|
exec_address=0x40800000,
|
||||||
main_mem_origin=0x40000000,
|
main_mem_origin=0x40000000,
|
||||||
l2_size=8192):
|
l2_size=8192):
|
||||||
self._reset = CSRStorage(reset=1)
|
self._reset = CSRStorage(reset=1)
|
||||||
|
|
|
@ -12,10 +12,10 @@ class Mailbox(Module):
|
||||||
values = Array([Signal(32) for _ in range(size)])
|
values = Array([Signal(32) for _ in range(size)])
|
||||||
for i in self.i1, self.i2:
|
for i in self.i1, self.i2:
|
||||||
self.sync += [
|
self.sync += [
|
||||||
i.dat_r.eq(values[i.adr]),
|
i.dat_r.eq(values[i.adr[:bits_for(size-1)]]),
|
||||||
i.ack.eq(0),
|
i.ack.eq(0),
|
||||||
If(i.cyc & i.stb & ~i.ack,
|
If(i.cyc & i.stb & ~i.ack,
|
||||||
i.ack.eq(1),
|
i.ack.eq(1),
|
||||||
If(i.we, values[i.adr].eq(i.dat_w))
|
If(i.we, values[i.adr[:bits_for(size-1)]].eq(i.dat_w))
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,10 +24,8 @@ class _GrayCodeTransfer(Module):
|
||||||
self.sync.rtio += value_gray_rtio.eq(self.i ^ self.i[1:])
|
self.sync.rtio += value_gray_rtio.eq(self.i ^ self.i[1:])
|
||||||
# transfer to system clock domain
|
# transfer to system clock domain
|
||||||
value_gray_sys = Signal(width)
|
value_gray_sys = Signal(width)
|
||||||
self.specials += [
|
value_gray_rtio.attr.add("no_retiming")
|
||||||
NoRetiming(value_gray_rtio),
|
self.specials += MultiReg(value_gray_rtio, value_gray_sys)
|
||||||
MultiReg(value_gray_rtio, value_gray_sys)
|
|
||||||
]
|
|
||||||
# convert back to binary
|
# convert back to binary
|
||||||
value_sys = Signal(width)
|
value_sys = Signal(width)
|
||||||
self.comb += value_sys[-1].eq(value_gray_sys[-1])
|
self.comb += value_sys[-1].eq(value_gray_sys[-1])
|
||||||
|
|
|
@ -8,7 +8,6 @@ from migen.genlib.cdc import MultiReg
|
||||||
from migen.build.generic_platform import *
|
from migen.build.generic_platform import *
|
||||||
from migen.build.xilinx.vivado import XilinxVivadoToolchain
|
from migen.build.xilinx.vivado import XilinxVivadoToolchain
|
||||||
from migen.build.xilinx.ise import XilinxISEToolchain
|
from migen.build.xilinx.ise import XilinxISEToolchain
|
||||||
from migen.fhdl.specials import Keep
|
|
||||||
from migen.genlib.io import DifferentialInput
|
from migen.genlib.io import DifferentialInput
|
||||||
|
|
||||||
from jesd204b.common import (JESD204BTransportSettings,
|
from jesd204b.common import (JESD204BTransportSettings,
|
||||||
|
@ -149,10 +148,10 @@ class _NIST_Ions(MiniSoC, AMPSoC):
|
||||||
self.register_kernel_cpu_csrdevice("i2c")
|
self.register_kernel_cpu_csrdevice("i2c")
|
||||||
self.config["I2C_BUS_COUNT"] = 1
|
self.config["I2C_BUS_COUNT"] = 1
|
||||||
|
|
||||||
def add_rtio(self, rtio_channels, rtio_crg=None):
|
self.config["HAS_DDS"] = None
|
||||||
if rtio_crg is None:
|
|
||||||
rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk)
|
def add_rtio(self, rtio_channels):
|
||||||
self.submodules.rtio_crg = rtio_crg
|
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk)
|
||||||
self.csr_devices.append("rtio_crg")
|
self.csr_devices.append("rtio_crg")
|
||||||
self.submodules.rtio = rtio.RTIO(rtio_channels)
|
self.submodules.rtio = rtio.RTIO(rtio_channels)
|
||||||
self.register_kernel_cpu_csrdevice("rtio")
|
self.register_kernel_cpu_csrdevice("rtio")
|
||||||
|
@ -160,22 +159,11 @@ class _NIST_Ions(MiniSoC, AMPSoC):
|
||||||
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
self.csr_devices.append("rtio_moninj")
|
self.csr_devices.append("rtio_moninj")
|
||||||
|
|
||||||
self.specials += [
|
self.rtio_crg.cd_rtio.clk.attr.add("keep")
|
||||||
Keep(self.rtio.cd_rsys.clk),
|
|
||||||
Keep(self.rtio_crg.cd_rtio.clk),
|
|
||||||
Keep(self.ethphy.crg.cd_eth_rx.clk),
|
|
||||||
Keep(self.ethphy.crg.cd_eth_tx.clk),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.platform.add_period_constraint(self.rtio.cd_rsys.clk, 8.)
|
|
||||||
self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.)
|
self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.)
|
||||||
self.platform.add_period_constraint(self.ethphy.crg.cd_eth_rx.clk, 8.)
|
|
||||||
self.platform.add_period_constraint(self.ethphy.crg.cd_eth_tx.clk, 8.)
|
|
||||||
self.platform.add_false_path_constraints(
|
self.platform.add_false_path_constraints(
|
||||||
self.rtio.cd_rsys.clk,
|
self.crg.cd_sys.clk,
|
||||||
self.rtio_crg.cd_rtio.clk,
|
self.rtio_crg.cd_rtio.clk)
|
||||||
self.ethphy.crg.cd_eth_rx.clk,
|
|
||||||
self.ethphy.crg.cd_eth_tx.clk)
|
|
||||||
|
|
||||||
self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio,
|
self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio,
|
||||||
self.get_native_sdram_if())
|
self.get_native_sdram_if())
|
||||||
|
@ -223,7 +211,7 @@ class NIST_QC1(_NIST_Ions):
|
||||||
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
||||||
self.config["RTIO_DDS_COUNT"] = 1
|
self.config["RTIO_DDS_COUNT"] = 1
|
||||||
self.config["DDS_CHANNELS_PER_BUS"] = 8
|
self.config["DDS_CHANNELS_PER_BUS"] = 8
|
||||||
self.config["DDS_AD9858"] = True
|
self.config["DDS_AD9858"] = None
|
||||||
phy = dds.AD9858(platform.request("dds"), 8)
|
phy = dds.AD9858(platform.request("dds"), 8)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy,
|
rtio_channels.append(rtio.Channel.from_phy(phy,
|
||||||
|
@ -297,8 +285,8 @@ class NIST_CLOCK(_NIST_Ions):
|
||||||
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
||||||
self.config["RTIO_DDS_COUNT"] = 1
|
self.config["RTIO_DDS_COUNT"] = 1
|
||||||
self.config["DDS_CHANNELS_PER_BUS"] = 11
|
self.config["DDS_CHANNELS_PER_BUS"] = 11
|
||||||
self.config["DDS_AD9914"] = True
|
self.config["DDS_AD9914"] = None
|
||||||
self.config["DDS_ONEHOT_SEL"] = True
|
self.config["DDS_ONEHOT_SEL"] = None
|
||||||
phy = dds.AD9914(platform.request("dds"), 11, onehot=True)
|
phy = dds.AD9914(platform.request("dds"), 11, onehot=True)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy,
|
rtio_channels.append(rtio.Channel.from_phy(phy,
|
||||||
|
@ -375,8 +363,8 @@ class NIST_QC2(_NIST_Ions):
|
||||||
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
||||||
self.config["RTIO_DDS_COUNT"] = 2
|
self.config["RTIO_DDS_COUNT"] = 2
|
||||||
self.config["DDS_CHANNELS_PER_BUS"] = 12
|
self.config["DDS_CHANNELS_PER_BUS"] = 12
|
||||||
self.config["DDS_AD9914"] = True
|
self.config["DDS_AD9914"] = None
|
||||||
self.config["DDS_ONEHOT_SEL"] = True
|
self.config["DDS_ONEHOT_SEL"] = None
|
||||||
for backplane_offset in range(2):
|
for backplane_offset in range(2):
|
||||||
phy = dds.AD9914(
|
phy = dds.AD9914(
|
||||||
platform.request("dds", backplane_offset), 12, onehot=True)
|
platform.request("dds", backplane_offset), 12, onehot=True)
|
||||||
|
@ -394,11 +382,10 @@ class NIST_QC2(_NIST_Ions):
|
||||||
|
|
||||||
|
|
||||||
class _PhaserCRG(Module, AutoCSR):
|
class _PhaserCRG(Module, AutoCSR):
|
||||||
def __init__(self, platform, rtio_internal_clk):
|
def __init__(self, platform, refclk):
|
||||||
self._clock_sel = CSRStorage()
|
self._clock_sel = CSRStorage()
|
||||||
self._pll_reset = CSRStorage(reset=1)
|
self._pll_reset = CSRStorage(reset=1)
|
||||||
self._pll_locked = CSRStatus()
|
self._pll_locked = CSRStatus()
|
||||||
self.refclk = Signal()
|
|
||||||
self.clock_domains.cd_rtio = ClockDomain()
|
self.clock_domains.cd_rtio = ClockDomain()
|
||||||
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
|
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
|
||||||
|
|
||||||
|
@ -411,7 +398,7 @@ class _PhaserCRG(Module, AutoCSR):
|
||||||
|
|
||||||
p_REF_JITTER1=0.01, p_REF_JITTER2=0.01,
|
p_REF_JITTER1=0.01, p_REF_JITTER2=0.01,
|
||||||
p_CLKIN1_PERIOD=4.0, p_CLKIN2_PERIOD=4.0,
|
p_CLKIN1_PERIOD=4.0, p_CLKIN2_PERIOD=4.0,
|
||||||
i_CLKIN1=0, i_CLKIN2=self.refclk,
|
i_CLKIN1=0, i_CLKIN2=refclk,
|
||||||
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
||||||
i_CLKINSEL=~self._clock_sel.storage,
|
i_CLKINSEL=~self._clock_sel.storage,
|
||||||
|
|
||||||
|
@ -431,6 +418,8 @@ class _PhaserCRG(Module, AutoCSR):
|
||||||
MultiReg(pll_locked | ~self._clock_sel.storage,
|
MultiReg(pll_locked | ~self._clock_sel.storage,
|
||||||
self._pll_locked.status)
|
self._pll_locked.status)
|
||||||
]
|
]
|
||||||
|
self.cd_rtio.clk.attr.add("keep")
|
||||||
|
platform.add_period_constraint(self.cd_rtio.clk, 8.)
|
||||||
|
|
||||||
|
|
||||||
class AD9154JESD(Module, AutoCSR):
|
class AD9154JESD(Module, AutoCSR):
|
||||||
|
@ -444,28 +433,29 @@ class AD9154JESD(Module, AutoCSR):
|
||||||
|
|
||||||
sync_pads = platform.request("ad9154_sync")
|
sync_pads = platform.request("ad9154_sync")
|
||||||
self.jsync = Signal()
|
self.jsync = Signal()
|
||||||
self.refclk = Signal()
|
|
||||||
self.specials += DifferentialInput(
|
self.specials += DifferentialInput(
|
||||||
sync_pads.p, sync_pads.n, self.jsync)
|
sync_pads.p, sync_pads.n, self.jsync)
|
||||||
|
|
||||||
|
refclk = Signal()
|
||||||
self.clock_domains.cd_jesd = ClockDomain()
|
self.clock_domains.cd_jesd = ClockDomain()
|
||||||
refclk_pads = platform.request("ad9154_refclk")
|
refclk_pads = platform.request("ad9154_refclk")
|
||||||
platform.add_period_constraint(refclk_pads.p, 1e9/refclk_freq)
|
|
||||||
|
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("IBUFDS_GTE2", i_CEB=0,
|
Instance("IBUFDS_GTE2", i_CEB=0,
|
||||||
i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk),
|
i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=refclk),
|
||||||
Instance("BUFG", i_I=self.refclk, o_O=self.cd_jesd.clk),
|
Instance("BUFG", i_I=refclk, o_O=self.cd_jesd.clk),
|
||||||
AsyncResetSynchronizer(self.cd_jesd, ResetSignal("rio_phy")),
|
AsyncResetSynchronizer(self.cd_jesd, ResetSignal("rio_phy")),
|
||||||
]
|
]
|
||||||
|
self.cd_jesd.clk.attr.add("keep")
|
||||||
platform.add_period_constraint(self.cd_jesd.clk, 1e9/refclk_freq)
|
platform.add_period_constraint(self.cd_jesd.clk, 1e9/refclk_freq)
|
||||||
|
|
||||||
qpll = GTXQuadPLL(self.refclk, refclk_freq, linerate)
|
qpll = GTXQuadPLL(refclk, refclk_freq, linerate)
|
||||||
self.submodules += qpll
|
self.submodules += qpll
|
||||||
phys = []
|
phys = []
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
phy = JESD204BPhyTX(
|
phy = JESD204BPhyTX(
|
||||||
qpll, platform.request("ad9154_jesd", i), fabric_freq)
|
qpll, platform.request("ad9154_jesd", i), fabric_freq)
|
||||||
|
phy.gtx.cd_tx.clk.attr.add("keep")
|
||||||
platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate)
|
platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate)
|
||||||
platform.add_false_path_constraints(self.cd_jesd.clk,
|
platform.add_false_path_constraints(self.cd_jesd.clk,
|
||||||
phy.gtx.cd_tx.clk)
|
phy.gtx.cd_tx.clk)
|
||||||
|
@ -484,16 +474,15 @@ class AD9154JESD(Module, AutoCSR):
|
||||||
|
|
||||||
# blinking leds for transceiver reset status
|
# blinking leds for transceiver reset status
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
led = platform.request("user_led", 4 + i)
|
counter = Signal(max=fabric_freq)
|
||||||
counter = Signal(max=fabric_freq//2 + 1)
|
self.comb += platform.request("user_led", 4 + i).eq(counter[-1])
|
||||||
sync = getattr(self.sync, "phy{}_tx".format(i))
|
sync = getattr(self.sync, "phy{}_tx".format(i))
|
||||||
sync += \
|
sync += [
|
||||||
|
counter.eq(counter - 1),
|
||||||
If(counter == 0,
|
If(counter == 0,
|
||||||
led.eq(~led),
|
counter.eq(fabric_freq - 1)
|
||||||
counter.eq(fabric_freq//2)
|
|
||||||
).Else(
|
|
||||||
counter.eq(counter - 1)
|
|
||||||
)
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class AD9154(Module, AutoCSR):
|
class AD9154(Module, AutoCSR):
|
||||||
|
@ -517,18 +506,43 @@ class AD9154(Module, AutoCSR):
|
||||||
self.sync.jesd += conv.eq(Mux(z, Cat(ch.o[:2]), Cat(ch.o[2:])))
|
self.sync.jesd += conv.eq(Mux(z, Cat(ch.o[:2]), Cat(ch.o[2:])))
|
||||||
|
|
||||||
|
|
||||||
class Phaser(_NIST_Ions):
|
class Phaser(MiniSoC, AMPSoC):
|
||||||
mem_map = {
|
mem_map = {
|
||||||
"ad9154": 0x50000000,
|
"timer_kernel": 0x10000000, # (shadow @0x90000000)
|
||||||
|
"rtio": 0x20000000, # (shadow @0xa0000000)
|
||||||
|
"i2c": 0x30000000, # (shadow @0xb0000000)
|
||||||
|
"mailbox": 0x70000000, # (shadow @0xf0000000)
|
||||||
|
"ad9154": 0x50000000,
|
||||||
}
|
}
|
||||||
mem_map.update(_NIST_Ions.mem_map)
|
mem_map.update(MiniSoC.mem_map)
|
||||||
|
|
||||||
def __init__(self, cpu_type="or1k", **kwargs):
|
def __init__(self, cpu_type="or1k", **kwargs):
|
||||||
_NIST_Ions.__init__(self, cpu_type, **kwargs)
|
MiniSoC.__init__(self,
|
||||||
|
cpu_type=cpu_type,
|
||||||
|
sdram_controller_type="minicon",
|
||||||
|
l2_size=128*1024,
|
||||||
|
with_timer=False,
|
||||||
|
ident=artiq_version,
|
||||||
|
**kwargs)
|
||||||
|
AMPSoC.__init__(self)
|
||||||
|
self.platform.toolchain.bitstream_commands.extend([
|
||||||
|
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||||
|
])
|
||||||
|
|
||||||
platform = self.platform
|
platform = self.platform
|
||||||
|
platform.add_extension(_ams101_dac)
|
||||||
platform.add_extension(phaser.fmc_adapter_io)
|
platform.add_extension(phaser.fmc_adapter_io)
|
||||||
|
|
||||||
|
self.submodules.leds = gpio.GPIOOut(Cat(
|
||||||
|
platform.request("user_led", 0),
|
||||||
|
platform.request("user_led", 1)))
|
||||||
|
self.csr_devices.append("leds")
|
||||||
|
|
||||||
|
i2c = platform.request("i2c")
|
||||||
|
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
|
||||||
|
self.register_kernel_cpu_csrdevice("i2c")
|
||||||
|
self.config["I2C_BUS_COUNT"] = 1
|
||||||
|
|
||||||
self.submodules.ad9154 = AD9154(platform)
|
self.submodules.ad9154 = AD9154(platform)
|
||||||
self.register_kernel_cpu_csrdevice("ad9154")
|
self.register_kernel_cpu_csrdevice("ad9154")
|
||||||
self.config["AD9154_DAC_CS"] = 1 << 0
|
self.config["AD9154_DAC_CS"] = 1 << 0
|
||||||
|
@ -566,17 +580,25 @@ class Phaser(_NIST_Ions):
|
||||||
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
|
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
|
||||||
rtio_channels.append(rtio.LogChannel())
|
rtio_channels.append(rtio.LogChannel())
|
||||||
|
|
||||||
# FIXME: dummy
|
|
||||||
self.config["RTIO_FIRST_DDS_CHANNEL"] = 0
|
self.config["RTIO_FIRST_DDS_CHANNEL"] = 0
|
||||||
self.config["RTIO_DDS_COUNT"] = 1
|
self.config["RTIO_DDS_COUNT"] = 1
|
||||||
self.config["DDS_CHANNELS_PER_BUS"] = 1
|
self.config["DDS_CHANNELS_PER_BUS"] = 1
|
||||||
self.config["DDS_AD9914"] = True
|
self.config["DDS_ONEHOT_SEL"] = 1
|
||||||
self.config["DDS_ONEHOT_SEL"] = True
|
self.config["DDS_RTIO_CLK_RATIO"] = 8
|
||||||
self.config["DDS_RTIO_CLK_RATIO"] = 3
|
|
||||||
|
|
||||||
self.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk))
|
self.submodules.rtio_crg = _PhaserCRG(platform, self.ad9154.jesd.cd_jesd.clk)
|
||||||
|
self.csr_devices.append("rtio_crg")
|
||||||
|
self.submodules.rtio = rtio.RTIO(rtio_channels)
|
||||||
|
self.register_kernel_cpu_csrdevice("rtio")
|
||||||
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
self.csr_devices.append("rtio_moninj")
|
||||||
|
self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio,
|
||||||
|
self.get_native_sdram_if())
|
||||||
|
self.csr_devices.append("rtio_analyzer")
|
||||||
|
|
||||||
self.comb += self.rtio_crg.refclk.eq(self.ad9154.jesd.cd_jesd.clk)
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk,
|
||||||
|
self.rtio_crg.cd_rtio.clk)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -206,10 +206,11 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||||
rtio_channels.append(rtio.Channel.from_phy(
|
rtio_channels.append(rtio.Channel.from_phy(
|
||||||
phy, ofifo_depth=64, ififo_depth=64))
|
phy, ofifo_depth=64, ififo_depth=64))
|
||||||
|
|
||||||
|
self.config["HAS_DDS"] = None
|
||||||
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
|
||||||
self.config["RTIO_DDS_COUNT"] = 1
|
self.config["RTIO_DDS_COUNT"] = 1
|
||||||
self.config["DDS_CHANNELS_PER_BUS"] = 8
|
self.config["DDS_CHANNELS_PER_BUS"] = 8
|
||||||
self.config["DDS_AD9858"] = True
|
self.config["DDS_AD9858"] = None
|
||||||
dds_pins = platform.request("dds")
|
dds_pins = platform.request("dds")
|
||||||
self.comb += dds_pins.p.eq(0)
|
self.comb += dds_pins.p.eq(0)
|
||||||
phy = dds.AD9858(dds_pins, 8)
|
phy = dds.AD9858(dds_pins, 8)
|
||||||
|
|
|
@ -7,7 +7,7 @@ from functools import wraps
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["kernel", "portable", "syscall", "host_only",
|
__all__ = ["kernel", "portable", "rpc", "syscall", "host_only",
|
||||||
"set_time_manager", "set_watchdog_factory",
|
"set_time_manager", "set_watchdog_factory",
|
||||||
"TerminationRequested"]
|
"TerminationRequested"]
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ __all__.extend(kernel_globals)
|
||||||
|
|
||||||
|
|
||||||
_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo",
|
_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo",
|
||||||
"core_name function syscall forbidden flags")
|
"core_name portable function syscall forbidden flags")
|
||||||
|
|
||||||
def kernel(arg=None, flags={}):
|
def kernel(arg=None, flags={}):
|
||||||
"""
|
"""
|
||||||
|
@ -53,7 +53,7 @@ def kernel(arg=None, flags={}):
|
||||||
def run_on_core(self, *k_args, **k_kwargs):
|
def run_on_core(self, *k_args, **k_kwargs):
|
||||||
return getattr(self, arg).run(run_on_core, ((self,) + k_args), k_kwargs)
|
return getattr(self, arg).run(run_on_core, ((self,) + k_args), k_kwargs)
|
||||||
run_on_core.artiq_embedded = _ARTIQEmbeddedInfo(
|
run_on_core.artiq_embedded = _ARTIQEmbeddedInfo(
|
||||||
core_name=arg, function=function, syscall=None,
|
core_name=arg, portable=False, function=function, syscall=None,
|
||||||
forbidden=False, flags=set(flags))
|
forbidden=False, flags=set(flags))
|
||||||
return run_on_core
|
return run_on_core
|
||||||
return inner_decorator
|
return inner_decorator
|
||||||
|
@ -83,7 +83,23 @@ def portable(arg=None, flags={}):
|
||||||
return inner_decorator
|
return inner_decorator
|
||||||
else:
|
else:
|
||||||
arg.artiq_embedded = \
|
arg.artiq_embedded = \
|
||||||
_ARTIQEmbeddedInfo(core_name=None, function=arg, syscall=None,
|
_ARTIQEmbeddedInfo(core_name=None, portable=True, function=arg, syscall=None,
|
||||||
|
forbidden=False, flags=set(flags))
|
||||||
|
return arg
|
||||||
|
|
||||||
|
def rpc(arg=None, flags={}):
|
||||||
|
"""
|
||||||
|
This decorator marks a function for execution on the host interpreter.
|
||||||
|
This is also the default behavior of ARTIQ; however, this decorator allows
|
||||||
|
specifying additional flags.
|
||||||
|
"""
|
||||||
|
if arg is None:
|
||||||
|
def inner_decorator(function):
|
||||||
|
return rpc(function, flags)
|
||||||
|
return inner_decorator
|
||||||
|
else:
|
||||||
|
arg.artiq_embedded = \
|
||||||
|
_ARTIQEmbeddedInfo(core_name=None, portable=False, function=arg, syscall=None,
|
||||||
forbidden=False, flags=set(flags))
|
forbidden=False, flags=set(flags))
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
|
@ -101,7 +117,7 @@ def syscall(arg=None, flags={}):
|
||||||
if isinstance(arg, str):
|
if isinstance(arg, str):
|
||||||
def inner_decorator(function):
|
def inner_decorator(function):
|
||||||
function.artiq_embedded = \
|
function.artiq_embedded = \
|
||||||
_ARTIQEmbeddedInfo(core_name=None, function=None,
|
_ARTIQEmbeddedInfo(core_name=None, portable=False, function=None,
|
||||||
syscall=function.__name__, forbidden=False,
|
syscall=function.__name__, forbidden=False,
|
||||||
flags=set(flags))
|
flags=set(flags))
|
||||||
return function
|
return function
|
||||||
|
@ -119,7 +135,7 @@ def host_only(function):
|
||||||
in the host Python interpreter.
|
in the host Python interpreter.
|
||||||
"""
|
"""
|
||||||
function.artiq_embedded = \
|
function.artiq_embedded = \
|
||||||
_ARTIQEmbeddedInfo(core_name=None, function=None, syscall=None,
|
_ARTIQEmbeddedInfo(core_name=None, portable=False, function=None, syscall=None,
|
||||||
forbidden=True, flags={})
|
forbidden=True, flags={})
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from inspect import isclass
|
||||||
|
|
||||||
from artiq.protocols import pyon
|
from artiq.protocols import pyon
|
||||||
from artiq.language import units
|
from artiq.language import units
|
||||||
|
from artiq.language.core import rpc
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["NoDefault",
|
__all__ = ["NoDefault",
|
||||||
|
@ -274,6 +275,7 @@ class HasEnvironment:
|
||||||
kernel_invariants = getattr(self, "kernel_invariants", set())
|
kernel_invariants = getattr(self, "kernel_invariants", set())
|
||||||
self.kernel_invariants = kernel_invariants | {key}
|
self.kernel_invariants = kernel_invariants | {key}
|
||||||
|
|
||||||
|
@rpc(flags={"async"})
|
||||||
def set_dataset(self, key, value,
|
def set_dataset(self, key, value,
|
||||||
broadcast=False, persist=False, save=True):
|
broadcast=False, persist=False, save=True):
|
||||||
"""Sets the contents and handling modes of a dataset.
|
"""Sets the contents and handling modes of a dataset.
|
||||||
|
@ -290,6 +292,7 @@ class HasEnvironment:
|
||||||
"""
|
"""
|
||||||
self.__dataset_mgr.set(key, value, broadcast, persist, save)
|
self.__dataset_mgr.set(key, value, broadcast, persist, save)
|
||||||
|
|
||||||
|
@rpc(flags={"async"})
|
||||||
def mutate_dataset(self, key, index, value):
|
def mutate_dataset(self, key, index, value):
|
||||||
"""Mutate an existing dataset at the given index (e.g. set a value at
|
"""Mutate an existing dataset at the given index (e.g. set a value at
|
||||||
a given position in a NumPy array)
|
a given position in a NumPy array)
|
||||||
|
|
|
@ -13,7 +13,7 @@ crate-type = ["staticlib"]
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
std_artiq = { path = "libstd_artiq" }
|
std_artiq = { path = "libstd_artiq", features = ["alloc"] }
|
||||||
lwip = { path = "liblwip", default-features = false }
|
lwip = { path = "liblwip", default-features = false }
|
||||||
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
||||||
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
|
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
|
||||||
|
|
|
@ -1,4 +1,26 @@
|
||||||
[root]
|
[root]
|
||||||
name = "ksupport"
|
name = "ksupport"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"std_artiq 0.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloc_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "std_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"alloc_artiq 0.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||||
|
|
|
@ -8,6 +8,10 @@ name = "ksupport"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std_artiq = { path = "../libstd_artiq" }
|
||||||
|
byteorder = { version = "0.5", default-features = false }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = 'unwind'
|
panic = 'unwind'
|
||||||
opt-level = 2
|
opt-level = 2
|
||||||
|
|
|
@ -74,7 +74,7 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||||
|
|
||||||
/* libm */
|
/* libm */
|
||||||
api!(sqrt),
|
api!(sqrt),
|
||||||
api!(lround),
|
api!(round),
|
||||||
|
|
||||||
/* exceptions */
|
/* exceptions */
|
||||||
api!(_Unwind_Resume),
|
api!(_Unwind_Resume),
|
||||||
|
@ -91,6 +91,7 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||||
api!(watchdog_clear = ::watchdog_clear),
|
api!(watchdog_clear = ::watchdog_clear),
|
||||||
|
|
||||||
api!(send_rpc = ::send_rpc),
|
api!(send_rpc = ::send_rpc),
|
||||||
|
api!(send_async_rpc = ::send_async_rpc),
|
||||||
api!(recv_rpc = ::recv_rpc),
|
api!(recv_rpc = ::recv_rpc),
|
||||||
|
|
||||||
api!(cache_get = ::cache_get),
|
api!(cache_get = ::cache_get),
|
||||||
|
@ -104,13 +105,16 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||||
api!(rtio_input_timestamp),
|
api!(rtio_input_timestamp),
|
||||||
api!(rtio_input_data),
|
api!(rtio_input_data),
|
||||||
|
|
||||||
// #if ((defined CONFIG_RTIO_DDS_COUNT) && (CONFIG_RTIO_DDS_COUNT > 0))
|
#[cfg(has_dds)]
|
||||||
api!(dds_init),
|
api!(dds_init),
|
||||||
|
#[cfg(has_dds)]
|
||||||
api!(dds_init_sync),
|
api!(dds_init_sync),
|
||||||
|
#[cfg(has_dds)]
|
||||||
api!(dds_batch_enter),
|
api!(dds_batch_enter),
|
||||||
|
#[cfg(has_dds)]
|
||||||
api!(dds_batch_exit),
|
api!(dds_batch_exit),
|
||||||
|
#[cfg(has_dds)]
|
||||||
api!(dds_set),
|
api!(dds_set),
|
||||||
// #endif
|
|
||||||
|
|
||||||
api!(i2c_init),
|
api!(i2c_init),
|
||||||
api!(i2c_start),
|
api!(i2c_start),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use core::{ptr, slice, str};
|
use core::{ptr, slice, str};
|
||||||
use core::slice::SliceExt;
|
|
||||||
use libc::{c_void, c_char, c_int, size_t};
|
use libc::{c_void, c_char, c_int, size_t};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
|
|
@ -1,25 +1,49 @@
|
||||||
#![feature(lang_items, needs_panic_runtime, asm, libc, core_slice_ext)]
|
#![feature(lang_items, needs_panic_runtime, asm, libc, stmt_expr_attributes)]
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![needs_panic_runtime]
|
#![needs_panic_runtime]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std_artiq as std;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
#[path = "../src/board.rs"]
|
#[path = "../src/board.rs"]
|
||||||
mod board;
|
mod board;
|
||||||
#[path = "../src/mailbox.rs"]
|
#[path = "../src/mailbox.rs"]
|
||||||
mod mailbox;
|
mod mailbox;
|
||||||
|
|
||||||
|
#[path = "../src/proto.rs"]
|
||||||
|
mod proto;
|
||||||
#[path = "../src/kernel_proto.rs"]
|
#[path = "../src/kernel_proto.rs"]
|
||||||
mod kernel_proto;
|
mod kernel_proto;
|
||||||
|
#[path = "../src/rpc_proto.rs"]
|
||||||
|
mod rpc_proto;
|
||||||
|
|
||||||
mod dyld;
|
mod dyld;
|
||||||
mod api;
|
mod api;
|
||||||
|
|
||||||
use core::{mem, ptr, slice, str};
|
use core::{mem, ptr, slice, str};
|
||||||
|
use std::io::Cursor;
|
||||||
use libc::{c_char, size_t};
|
use libc::{c_char, size_t};
|
||||||
use kernel_proto::*;
|
use kernel_proto::*;
|
||||||
use dyld::Library;
|
use dyld::Library;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn malloc(_size: usize) -> *mut libc::c_void {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn realloc(_ptr: *mut libc::c_void, _size: usize) -> *mut libc::c_void {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn free(_ptr: *mut libc::c_void) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn send(request: &Message) {
|
fn send(request: &Message) {
|
||||||
unsafe { mailbox::send(request as *const _ as usize) }
|
unsafe { mailbox::send(request as *const _ as usize) }
|
||||||
while !mailbox::acknowledged() {}
|
while !mailbox::acknowledged() {}
|
||||||
|
@ -46,7 +70,7 @@ macro_rules! recv {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => ($crate::send(&Log(format_args!($($arg)*))));
|
($($arg:tt)*) => ($crate::send(&$crate::kernel_proto::Log(format_args!($($arg)*))));
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
|
@ -54,6 +78,9 @@ macro_rules! println {
|
||||||
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[path = "../src/rpc_queue.rs"]
|
||||||
|
mod rpc_queue;
|
||||||
|
|
||||||
#[lang = "panic_fmt"]
|
#[lang = "panic_fmt"]
|
||||||
extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||||
println!("panic at {}:{}: {}", file, line, args);
|
println!("panic at {}:{}: {}", file, line, args);
|
||||||
|
@ -80,14 +107,40 @@ extern fn send_rpc(service: u32, tag: *const u8, data: *const *const ()) {
|
||||||
extern { fn strlen(s: *const c_char) -> size_t; }
|
extern { fn strlen(s: *const c_char) -> size_t; }
|
||||||
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
||||||
|
|
||||||
|
while !rpc_queue::empty() {}
|
||||||
send(&RpcSend {
|
send(&RpcSend {
|
||||||
service: service as u32,
|
async: false,
|
||||||
batch: service == 0,
|
service: service,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern fn send_async_rpc(service: u32, tag: *const u8, data: *const *const ()) {
|
||||||
|
extern { fn strlen(s: *const c_char) -> size_t; }
|
||||||
|
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
||||||
|
|
||||||
|
while rpc_queue::full() {}
|
||||||
|
rpc_queue::enqueue(|mut slice| {
|
||||||
|
let length = {
|
||||||
|
let mut writer = Cursor::new(&mut slice[4..]);
|
||||||
|
try!(rpc_proto::send_args(&mut writer, service, tag, data));
|
||||||
|
writer.position()
|
||||||
|
};
|
||||||
|
proto::write_u32(&mut slice, length as u32)
|
||||||
|
}).unwrap_or_else(|err| {
|
||||||
|
assert!(err.kind() == std::io::ErrorKind::WriteZero);
|
||||||
|
|
||||||
|
while !rpc_queue::empty() {}
|
||||||
|
send(&RpcSend {
|
||||||
|
async: true,
|
||||||
|
service: service,
|
||||||
|
tag: tag,
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
extern fn recv_rpc(slot: *mut ()) -> usize {
|
extern fn recv_rpc(slot: *mut ()) -> usize {
|
||||||
send(&RpcRecvRequest(slot));
|
send(&RpcRecvRequest(slot));
|
||||||
recv!(&RpcRecvReply(ref result) => {
|
recv!(&RpcRecvReply(ref result) => {
|
||||||
|
@ -206,7 +259,7 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
attributes = attributes.offset(1);
|
attributes = attributes.offset(1);
|
||||||
|
|
||||||
if !(*attribute).tag.is_null() {
|
if !(*attribute).tag.is_null() {
|
||||||
send_rpc(0, (*attribute).tag, [
|
send_async_rpc(0, (*attribute).tag, [
|
||||||
&object as *const _ as *const (),
|
&object as *const _ as *const (),
|
||||||
&(*attribute).name as *const _ as *const (),
|
&(*attribute).name as *const _ as *const (),
|
||||||
(object as usize + (*attribute).offset) as *const ()
|
(object as usize + (*attribute).offset) as *const ()
|
||||||
|
|
|
@ -149,6 +149,7 @@ extern {
|
||||||
// nonstandard
|
// nonstandard
|
||||||
pub fn tcp_sndbuf_(pcb: *mut tcp_pcb) -> u16;
|
pub fn tcp_sndbuf_(pcb: *mut tcp_pcb) -> u16;
|
||||||
pub fn tcp_so_options_(pcb: *mut tcp_pcb) -> *mut u8;
|
pub fn tcp_so_options_(pcb: *mut tcp_pcb) -> *mut u8;
|
||||||
|
pub fn tcp_nagle_disable_(pcb: *mut tcp_pcb);
|
||||||
|
|
||||||
pub fn udp_new() -> *mut udp_pcb;
|
pub fn udp_new() -> *mut udp_pcb;
|
||||||
pub fn udp_new_ip_type(type_: ip_addr_type) -> *mut udp_pcb;
|
pub fn udp_new_ip_type(type_: ip_addr_type) -> *mut udp_pcb;
|
||||||
|
|
|
@ -9,7 +9,7 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lwip-sys = { path = "../liblwip-sys" }
|
lwip-sys = { path = "../liblwip-sys" }
|
||||||
std_artiq = { path = "../libstd_artiq" }
|
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["preemption"]
|
default = ["preemption"]
|
||||||
|
|
|
@ -549,6 +549,7 @@ impl TcpStream {
|
||||||
lwip_sys::tcp_recv(raw, Some(recv));
|
lwip_sys::tcp_recv(raw, Some(recv));
|
||||||
lwip_sys::tcp_sent(raw, Some(sent));
|
lwip_sys::tcp_sent(raw, Some(sent));
|
||||||
lwip_sys::tcp_err(raw, Some(err));
|
lwip_sys::tcp_err(raw, Some(err));
|
||||||
|
lwip_sys::tcp_nagle_disable_(raw);
|
||||||
TcpStream { raw: raw, state: state }
|
TcpStream { raw: raw, state: state }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,6 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
alloc_artiq = { path = "../liballoc_artiq" }
|
alloc_artiq = { path = "../liballoc_artiq" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
alloc = []
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
#[cfg(feature="alloc")] use alloc::boxed::Box;
|
||||||
|
#[cfg(not(feature="alloc"))] use ::FakeBox as Box;
|
||||||
use core::convert::Into;
|
use core::convert::Into;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::marker::{Send, Sync};
|
use core::marker::{Send, Sync};
|
||||||
|
@ -62,13 +63,19 @@ pub struct Error {
|
||||||
enum Repr {
|
enum Repr {
|
||||||
Os(i32),
|
Os(i32),
|
||||||
|
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
Custom(Box<Custom>),
|
Custom(Box<Custom>),
|
||||||
|
#[cfg(not(feature="alloc"))]
|
||||||
|
Custom(Custom),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Custom {
|
struct Custom {
|
||||||
kind: ErrorKind,
|
kind: ErrorKind,
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
error: Box<error::Error+Send+Sync>,
|
error: Box<error::Error+Send+Sync>,
|
||||||
|
#[cfg(not(feature="alloc"))]
|
||||||
|
error: &'static str
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list specifying general categories of I/O error.
|
/// A list specifying general categories of I/O error.
|
||||||
|
@ -162,12 +169,21 @@ impl Error {
|
||||||
/// // errors can also be created from other errors
|
/// // errors can also be created from other errors
|
||||||
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
|
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
pub fn new<E>(kind: ErrorKind, error: E) -> Error
|
pub fn new<E>(kind: ErrorKind, error: E) -> Error
|
||||||
where E: Into<Box<error::Error+Send+Sync>>
|
where E: Into<Box<error::Error+Send+Sync>>
|
||||||
{
|
{
|
||||||
Self::_new(kind, error.into())
|
Self::_new(kind, error.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature="alloc"))]
|
||||||
|
pub fn new<E>(kind: ErrorKind, error: E) -> Error
|
||||||
|
where E: Into<&'static str>
|
||||||
|
{
|
||||||
|
Self::_new(kind, error.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
|
fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
|
||||||
Error {
|
Error {
|
||||||
repr: Repr::Custom(Box::new(Custom {
|
repr: Repr::Custom(Box::new(Custom {
|
||||||
|
@ -177,6 +193,16 @@ impl Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature="alloc"))]
|
||||||
|
fn _new(kind: ErrorKind, error: &'static str) -> Error {
|
||||||
|
Error {
|
||||||
|
repr: Repr::Custom(Box::new(Custom {
|
||||||
|
kind: kind,
|
||||||
|
error: error,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new instance of an `Error` from a particular OS error code.
|
/// Creates a new instance of an `Error` from a particular OS error code.
|
||||||
pub fn from_raw_os_error(code: i32) -> Error {
|
pub fn from_raw_os_error(code: i32) -> Error {
|
||||||
Error { repr: Repr::Os(code) }
|
Error { repr: Repr::Os(code) }
|
||||||
|
@ -198,6 +224,7 @@ impl Error {
|
||||||
///
|
///
|
||||||
/// If this `Error` was constructed via `new` then this function will
|
/// If this `Error` was constructed via `new` then this function will
|
||||||
/// return `Some`, otherwise it will return `None`.
|
/// return `Some`, otherwise it will return `None`.
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
|
pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
|
||||||
match self.repr {
|
match self.repr {
|
||||||
Repr::Os(..) => None,
|
Repr::Os(..) => None,
|
||||||
|
@ -210,6 +237,7 @@ impl Error {
|
||||||
///
|
///
|
||||||
/// If this `Error` was constructed via `new` then this function will
|
/// If this `Error` was constructed via `new` then this function will
|
||||||
/// return `Some`, otherwise it will return `None`.
|
/// return `Some`, otherwise it will return `None`.
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
|
pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
|
||||||
match self.repr {
|
match self.repr {
|
||||||
Repr::Os(..) => None,
|
Repr::Os(..) => None,
|
||||||
|
@ -221,6 +249,7 @@ impl Error {
|
||||||
///
|
///
|
||||||
/// If this `Error` was constructed via `new` then this function will
|
/// If this `Error` was constructed via `new` then this function will
|
||||||
/// return `Some`, otherwise it will return `None`.
|
/// return `Some`, otherwise it will return `None`.
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
|
pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
|
||||||
match self.repr {
|
match self.repr {
|
||||||
Repr::Os(..) => None,
|
Repr::Os(..) => None,
|
||||||
|
@ -282,14 +311,24 @@ impl error::Error for Error {
|
||||||
ErrorKind::UnexpectedEof => "unexpected end of file",
|
ErrorKind::UnexpectedEof => "unexpected end of file",
|
||||||
ErrorKind::__Nonexhaustive => unreachable!()
|
ErrorKind::__Nonexhaustive => unreachable!()
|
||||||
},
|
},
|
||||||
Repr::Custom(ref c) => c.error.description(),
|
Repr::Custom(ref c) => {
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
|
{ c.error.description() }
|
||||||
|
#[cfg(not(feature="alloc"))]
|
||||||
|
{ c.error }
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self) -> Option<&error::Error> {
|
fn cause(&self) -> Option<&error::Error> {
|
||||||
match self.repr {
|
match self.repr {
|
||||||
Repr::Os(..) => None,
|
Repr::Os(..) => None,
|
||||||
Repr::Custom(ref c) => c.error.cause(),
|
Repr::Custom(ref _c) => {
|
||||||
|
#[cfg(feature="alloc")]
|
||||||
|
{ _c.error.cause() }
|
||||||
|
#[cfg(not(feature="alloc"))]
|
||||||
|
{ None }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![feature(lang_items, asm, alloc, collections, libc, needs_panic_runtime,
|
#![feature(lang_items, asm, alloc, collections, libc, needs_panic_runtime,
|
||||||
question_mark, unicode, reflect_marker, raw, int_error_internals,
|
question_mark, unicode, reflect_marker, raw, int_error_internals,
|
||||||
try_from, try_borrow, macro_reexport, allow_internal_unstable)]
|
try_from, try_borrow, macro_reexport, allow_internal_unstable,
|
||||||
|
stmt_expr_attributes)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![needs_panic_runtime]
|
#![needs_panic_runtime]
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ extern crate rustc_unicode;
|
||||||
extern crate alloc_artiq;
|
extern crate alloc_artiq;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[macro_reexport(vec)]
|
#[macro_reexport(vec, format)]
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
@ -32,51 +33,12 @@ pub mod prelude {
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
|
||||||
use core::fmt::Write;
|
// Provide Box::new wrapper
|
||||||
|
#[cfg(not(feature="alloc"))]
|
||||||
#[macro_export]
|
struct FakeBox<T>(core::marker::PhantomData<T>);
|
||||||
macro_rules! print {
|
#[cfg(not(feature="alloc"))]
|
||||||
($($arg:tt)*) => ($crate::print_fmt(format_args!($($arg)*)));
|
impl<T> FakeBox<T> {
|
||||||
}
|
fn new(val: T) -> T {
|
||||||
|
val
|
||||||
#[macro_export]
|
|
||||||
macro_rules! println {
|
|
||||||
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
|
||||||
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
|
||||||
}
|
|
||||||
|
|
||||||
extern {
|
|
||||||
fn putchar(c: libc::c_int) -> libc::c_int;
|
|
||||||
fn readchar() -> libc::c_char;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Console;
|
|
||||||
|
|
||||||
impl core::fmt::Write for Console {
|
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
|
||||||
for c in s.bytes() { unsafe { putchar(c as i32); } }
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_fmt(args: self::core::fmt::Arguments) {
|
|
||||||
let _ = Console.write_fmt(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[lang = "panic_fmt"]
|
|
||||||
extern fn panic_fmt(args: self::core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
|
||||||
let _ = write!(Console, "panic at {}:{}: {}\n", file, line, args);
|
|
||||||
let _ = write!(Console, "waiting for debugger...\n");
|
|
||||||
unsafe {
|
|
||||||
let _ = readchar();
|
|
||||||
loop { asm!("l.trap 0") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow linking with crates that are built as -Cpanic=unwind even when the root crate
|
|
||||||
// is built with -Cpanic=abort.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn _Unwind_Resume() -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,6 +12,13 @@ pub fn init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_us() -> u64 {
|
||||||
|
unsafe {
|
||||||
|
csr::timer0::update_value_write(1);
|
||||||
|
(INIT - csr::timer0::value_read()) / (FREQ / 1_000_000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_ms() -> u64 {
|
pub fn get_ms() -> u64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::timer0::update_value_write(1);
|
csr::timer0::update_value_write(1);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use board::csr;
|
use board::csr;
|
||||||
use mailbox;
|
use mailbox;
|
||||||
|
use rpc_queue;
|
||||||
|
|
||||||
use kernel_proto::{KERNELCPU_EXEC_ADDRESS, KERNELCPU_LAST_ADDRESS, KSUPPORT_HEADER_SIZE};
|
use kernel_proto::{KERNELCPU_EXEC_ADDRESS, KERNELCPU_LAST_ADDRESS, KSUPPORT_HEADER_SIZE};
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ pub unsafe fn start() {
|
||||||
ptr::copy_nonoverlapping(ksupport_image.as_ptr(), ksupport_addr, ksupport_image.len());
|
ptr::copy_nonoverlapping(ksupport_image.as_ptr(), ksupport_addr, ksupport_image.len());
|
||||||
|
|
||||||
csr::kernel_cpu::reset_write(0);
|
csr::kernel_cpu::reset_write(0);
|
||||||
|
|
||||||
|
rpc_queue::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop() {
|
pub fn stop() {
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40400000;
|
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800000;
|
||||||
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40440000;
|
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40840000;
|
||||||
pub const KERNELCPU_LAST_ADDRESS: usize = 0x4fffffff;
|
pub const KERNELCPU_LAST_ADDRESS: usize = 0x4fffffff;
|
||||||
pub const KSUPPORT_HEADER_SIZE: usize = 0x80;
|
pub const KSUPPORT_HEADER_SIZE: usize = 0x80;
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ pub enum Message<'a> {
|
||||||
WatchdogClear { id: usize },
|
WatchdogClear { id: usize },
|
||||||
|
|
||||||
RpcSend {
|
RpcSend {
|
||||||
|
async: bool,
|
||||||
service: u32,
|
service: u32,
|
||||||
batch: bool,
|
|
||||||
tag: &'a [u8],
|
tag: &'a [u8],
|
||||||
data: *const *const ()
|
data: *const *const ()
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(libc, const_fn, try_borrow, stmt_expr_attributes, repr_simd, asm)]
|
#![feature(libc, const_fn, try_borrow, stmt_expr_attributes, repr_simd, asm,
|
||||||
|
lang_items)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std_artiq as std;
|
extern crate std_artiq as std;
|
||||||
|
@ -11,13 +12,54 @@ extern crate byteorder;
|
||||||
extern crate fringe;
|
extern crate fringe;
|
||||||
extern crate lwip;
|
extern crate lwip;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
use logger::BufferLogger;
|
use logger::BufferLogger;
|
||||||
|
|
||||||
|
extern {
|
||||||
|
fn putchar(c: libc::c_int) -> libc::c_int;
|
||||||
|
fn readchar() -> libc::c_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ($crate::print_fmt(format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
||||||
|
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Console;
|
||||||
|
|
||||||
|
impl core::fmt::Write for Console {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
||||||
|
for c in s.bytes() { unsafe { putchar(c as i32); } }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_fmt(args: self::core::fmt::Arguments) {
|
||||||
|
let _ = Console.write_fmt(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "panic_fmt"]
|
||||||
|
extern fn panic_fmt(args: self::core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||||
|
let _ = write!(Console, "panic at {}:{}: {}\n", file, line, args);
|
||||||
|
let _ = write!(Console, "waiting for debugger...\n");
|
||||||
|
unsafe {
|
||||||
|
let _ = readchar();
|
||||||
|
loop { asm!("l.trap 0") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod board;
|
mod board;
|
||||||
mod config;
|
mod config;
|
||||||
mod clock;
|
mod clock;
|
||||||
mod rtio_crg;
|
mod rtio_crg;
|
||||||
mod mailbox;
|
mod mailbox;
|
||||||
|
mod rpc_queue;
|
||||||
|
|
||||||
mod urc;
|
mod urc;
|
||||||
mod sched;
|
mod sched;
|
||||||
|
@ -29,10 +71,11 @@ mod kernel_proto;
|
||||||
mod session_proto;
|
mod session_proto;
|
||||||
mod moninj_proto;
|
mod moninj_proto;
|
||||||
mod analyzer_proto;
|
mod analyzer_proto;
|
||||||
|
mod rpc_proto;
|
||||||
|
|
||||||
mod kernel;
|
mod kernel;
|
||||||
mod rpc;
|
|
||||||
mod session;
|
mod session;
|
||||||
|
#[cfg(has_rtio_moninj)]
|
||||||
mod moninj;
|
mod moninj;
|
||||||
#[cfg(has_rtio_analyzer)]
|
#[cfg(has_rtio_analyzer)]
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
|
@ -44,9 +87,17 @@ extern {
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
|
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
|
||||||
|
|
||||||
|
// Allow linking with crates that are built as -Cpanic=unwind even if we use -Cpanic=abort.
|
||||||
|
// This is never called.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn _Unwind_Resume() -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern fn rust_main() {
|
pub unsafe extern fn rust_main() {
|
||||||
static mut LOG_BUFFER: [u8; 4096] = [0; 4096];
|
static mut LOG_BUFFER: [u8; 65536] = [0; 65536];
|
||||||
BufferLogger::new(&mut LOG_BUFFER[..])
|
BufferLogger::new(&mut LOG_BUFFER[..])
|
||||||
.register(move || {
|
.register(move || {
|
||||||
info!("booting ARTIQ...");
|
info!("booting ARTIQ...");
|
||||||
|
@ -59,6 +110,7 @@ pub unsafe extern fn rust_main() {
|
||||||
|
|
||||||
let mut scheduler = sched::Scheduler::new();
|
let mut scheduler = sched::Scheduler::new();
|
||||||
scheduler.spawner().spawn(16384, session::thread);
|
scheduler.spawner().spawn(16384, session::thread);
|
||||||
|
#[cfg(has_rtio_moninj)]
|
||||||
scheduler.spawner().spawn(4096, moninj::thread);
|
scheduler.spawner().spawn(4096, moninj::thread);
|
||||||
#[cfg(has_rtio_analyzer)]
|
#[cfg(has_rtio_analyzer)]
|
||||||
scheduler.spawner().spawn(4096, analyzer::thread);
|
scheduler.spawner().spawn(4096, analyzer::thread);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use core::{mem, ptr};
|
use core::{mem, ptr};
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use log::{self, Log, LogMetadata, LogRecord, LogLevelFilter};
|
use log::{self, Log, LogLevel, LogMetadata, LogRecord, LogLevelFilter};
|
||||||
use log_buffer::LogBuffer;
|
use log_buffer::LogBuffer;
|
||||||
|
use clock;
|
||||||
|
|
||||||
pub struct BufferLogger {
|
pub struct BufferLogger {
|
||||||
buffer: RefCell<LogBuffer<&'static mut [u8]>>
|
buffer: RefCell<LogBuffer<&'static mut [u8]>>
|
||||||
|
@ -57,10 +58,13 @@ impl Log for BufferLogger {
|
||||||
fn log(&self, record: &LogRecord) {
|
fn log(&self, record: &LogRecord) {
|
||||||
if self.enabled(record.metadata()) {
|
if self.enabled(record.metadata()) {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
writeln!(self.buffer.borrow_mut(), "{:>5}({}): {}",
|
writeln!(self.buffer.borrow_mut(),
|
||||||
record.level(), record.target(), record.args()).unwrap();
|
"[{:12}us] {:>5}({}): {}",
|
||||||
println!("{:>5}({}): {}",
|
clock::get_us(), record.level(), record.target(), record.args()).unwrap();
|
||||||
record.level(), record.target(), record.args());
|
if record.level() <= LogLevel::Info {
|
||||||
|
println!("[{:12}us] {:>5}({}): {}",
|
||||||
|
clock::get_us(), record.level(), record.target(), record.args());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,8 @@ pub fn write_bytes(writer: &mut Write, value: &[u8]) -> io::Result<()> {
|
||||||
|
|
||||||
pub fn read_string(reader: &mut Read) -> io::Result<String> {
|
pub fn read_string(reader: &mut Read) -> io::Result<String> {
|
||||||
let bytes = try!(read_bytes(reader));
|
let bytes = try!(read_bytes(reader));
|
||||||
String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
String::from_utf8(bytes)
|
||||||
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_string(writer: &mut Write, value: &str) -> io::Result<()> {
|
pub fn write_string(writer: &mut Write, value: &str) -> io::Result<()> {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::slice;
|
#![allow(dead_code)]
|
||||||
use std::io::{self, Read, Write, BufWriter};
|
|
||||||
|
use core::slice;
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
use proto::*;
|
use proto::*;
|
||||||
use self::tag::{Tag, TagIterator, split_tag};
|
use self::tag::{Tag, TagIterator, split_tag};
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ unsafe fn recv_value(reader: &mut Read, tag: Tag, data: &mut *mut (),
|
||||||
pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (),
|
pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (),
|
||||||
alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> {
|
alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> {
|
||||||
let mut it = TagIterator::new(tag_bytes);
|
let mut it = TagIterator::new(tag_bytes);
|
||||||
|
#[cfg(not(ksupport))]
|
||||||
trace!("recv ...->{}", it);
|
trace!("recv ...->{}", it);
|
||||||
|
|
||||||
let tag = it.next().expect("truncated tag");
|
let tag = it.next().expect("truncated tag");
|
||||||
|
@ -98,7 +101,6 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let writer = &mut BufWriter::new(writer);
|
|
||||||
try!(write_u8(writer, tag.as_u8()));
|
try!(write_u8(writer, tag.as_u8()));
|
||||||
match tag {
|
match tag {
|
||||||
Tag::None => Ok(()),
|
Tag::None => Ok(()),
|
||||||
|
@ -161,14 +163,16 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_args(writer: &mut Write, tag_bytes: &[u8],
|
pub fn send_args(writer: &mut Write, service: u32, tag_bytes: &[u8],
|
||||||
data: *const *const ()) -> io::Result<()> {
|
data: *const *const ()) -> io::Result<()> {
|
||||||
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
|
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
|
||||||
|
|
||||||
let mut args_it = TagIterator::new(arg_tags_bytes);
|
let mut args_it = TagIterator::new(arg_tags_bytes);
|
||||||
let return_it = TagIterator::new(return_tag_bytes);
|
let return_it = TagIterator::new(return_tag_bytes);
|
||||||
trace!("send ({})->{}", args_it, return_it);
|
#[cfg(not(ksupport))]
|
||||||
|
trace!("send<{}>({})->{}", service, args_it, return_it);
|
||||||
|
|
||||||
|
try!(write_u32(writer, service));
|
||||||
for index in 0.. {
|
for index in 0.. {
|
||||||
if let Some(arg_tag) = args_it.next() {
|
if let Some(arg_tag) = args_it.next() {
|
||||||
let mut data = unsafe { *data.offset(index) };
|
let mut data = unsafe { *data.offset(index) };
|
|
@ -0,0 +1,61 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use core::ptr::{read_volatile, write_volatile};
|
||||||
|
use core::slice;
|
||||||
|
use board;
|
||||||
|
|
||||||
|
const SEND_MAILBOX: *mut usize = (board::mem::MAILBOX_BASE + 4) as *mut usize;
|
||||||
|
const RECV_MAILBOX: *mut usize = (board::mem::MAILBOX_BASE + 8) as *mut usize;
|
||||||
|
|
||||||
|
const QUEUE_BEGIN: usize = 0x40400000;
|
||||||
|
const QUEUE_END: usize = 0x407fff80;
|
||||||
|
const QUEUE_CHUNK: usize = 0x1000;
|
||||||
|
|
||||||
|
pub unsafe fn init() {
|
||||||
|
write_volatile(SEND_MAILBOX, QUEUE_BEGIN);
|
||||||
|
write_volatile(RECV_MAILBOX, QUEUE_BEGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(mut addr: usize) -> usize {
|
||||||
|
debug_assert!(addr % QUEUE_CHUNK == 0);
|
||||||
|
debug_assert!(addr >= QUEUE_BEGIN && addr < QUEUE_END);
|
||||||
|
|
||||||
|
addr += QUEUE_CHUNK;
|
||||||
|
if addr >= QUEUE_END { addr = QUEUE_BEGIN }
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> bool {
|
||||||
|
unsafe { read_volatile(SEND_MAILBOX) == read_volatile(RECV_MAILBOX) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn full() -> bool {
|
||||||
|
unsafe { next(read_volatile(SEND_MAILBOX)) == read_volatile(RECV_MAILBOX) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue<T, E, F>(f: F) -> Result<T, E>
|
||||||
|
where F: FnOnce(&mut [u8]) -> Result<T, E> {
|
||||||
|
debug_assert!(!full());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let slice = slice::from_raw_parts_mut(read_volatile(SEND_MAILBOX) as *mut u8, QUEUE_CHUNK);
|
||||||
|
f(slice).and_then(|x| {
|
||||||
|
write_volatile(SEND_MAILBOX, next(read_volatile(SEND_MAILBOX)));
|
||||||
|
Ok(x)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue<T, E, F>(f: F) -> Result<T, E>
|
||||||
|
where F: FnOnce(&mut [u8]) -> Result<T, E> {
|
||||||
|
debug_assert!(!empty());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
board::flush_cpu_dcache();
|
||||||
|
let slice = slice::from_raw_parts_mut(read_volatile(RECV_MAILBOX) as *mut u8, QUEUE_CHUNK);
|
||||||
|
f(slice).and_then(|x| {
|
||||||
|
write_volatile(RECV_MAILBOX, next(read_volatile(RECV_MAILBOX)));
|
||||||
|
Ok(x)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{mem, str};
|
use std::{mem, str};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Write;
|
use std::io::{self, Read, Write, BufWriter};
|
||||||
use std::io::{self, Read};
|
use {config, rtio_crg, clock, mailbox, rpc_queue, kernel};
|
||||||
use {config, rtio_crg, clock, mailbox, kernel};
|
|
||||||
use logger::BufferLogger;
|
use logger::BufferLogger;
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
use urc::Urc;
|
use urc::Urc;
|
||||||
use sched::{ThreadHandle, Waiter, Spawner};
|
use sched::{ThreadHandle, Waiter, Spawner};
|
||||||
use sched::{TcpListener, TcpStream, SocketAddr, IP_ANY};
|
use sched::{TcpListener, TcpStream, SocketAddr, IP_ANY};
|
||||||
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
|
|
||||||
use rpc;
|
use rpc_proto as rpc;
|
||||||
use session_proto as host;
|
use session_proto as host;
|
||||||
use kernel_proto as kern;
|
use kernel_proto as kern;
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ fn host_read(stream: &mut TcpStream) -> io::Result<host::Request> {
|
||||||
Ok(request)
|
Ok(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn host_write(stream: &mut TcpStream, reply: host::Reply) -> io::Result<()> {
|
fn host_write(stream: &mut Write, reply: host::Reply) -> io::Result<()> {
|
||||||
trace!("comm->host {:?}", reply);
|
trace!("comm->host {:?}", reply);
|
||||||
reply.write_to(stream)
|
reply.write_to(stream)
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,8 @@ fn kern_recv_notrace<R, F>(waiter: Waiter, f: F) -> io::Result<R>
|
||||||
where F: FnOnce(&kern::Message) -> io::Result<R> {
|
where F: FnOnce(&kern::Message) -> io::Result<R> {
|
||||||
try!(waiter.until(|| mailbox::receive() != 0));
|
try!(waiter.until(|| mailbox::receive() != 0));
|
||||||
if !kernel::validate(mailbox::receive()) {
|
if !kernel::validate(mailbox::receive()) {
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid kernel CPU pointer"))
|
let message = format!("invalid kernel CPU pointer 0x{:x}", mailbox::receive());
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidData, message))
|
||||||
}
|
}
|
||||||
|
|
||||||
f(unsafe { mem::transmute::<usize, &kern::Message>(mailbox::receive()) })
|
f(unsafe { mem::transmute::<usize, &kern::Message>(mailbox::receive()) })
|
||||||
|
@ -352,6 +353,7 @@ fn process_kern_message(waiter: Waiter,
|
||||||
kern_recv_dotrace(request);
|
kern_recv_dotrace(request);
|
||||||
match request {
|
match request {
|
||||||
&kern::Log(args) => {
|
&kern::Log(args) => {
|
||||||
|
use std::fmt::Write;
|
||||||
try!(session.log_buffer.write_fmt(args)
|
try!(session.log_buffer.write_fmt(args)
|
||||||
.map_err(|_| io_error("cannot append to session log buffer")));
|
.map_err(|_| io_error("cannot append to session log buffer")));
|
||||||
session.flush_log_buffer();
|
session.flush_log_buffer();
|
||||||
|
@ -383,15 +385,14 @@ fn process_kern_message(waiter: Waiter,
|
||||||
kern_acknowledge()
|
kern_acknowledge()
|
||||||
}
|
}
|
||||||
|
|
||||||
&kern::RpcSend { service, batch, tag, data } => {
|
&kern::RpcSend { async, service, tag, data } => {
|
||||||
match stream {
|
match stream {
|
||||||
None => unexpected!("unexpected RPC in flash kernel"),
|
None => unexpected!("unexpected RPC in flash kernel"),
|
||||||
Some(ref mut stream) => {
|
Some(ref mut stream) => {
|
||||||
try!(host_write(stream, host::Reply::RpcRequest {
|
let writer = &mut BufWriter::new(stream);
|
||||||
service: service
|
try!(host_write(writer, host::Reply::RpcRequest { async: async }));
|
||||||
}));
|
try!(rpc::send_args(writer, service, tag, data));
|
||||||
try!(rpc::send_args(stream, tag, data));
|
if !async {
|
||||||
if !batch {
|
|
||||||
session.kernel_state = KernelState::RpcWait
|
session.kernel_state = KernelState::RpcWait
|
||||||
}
|
}
|
||||||
kern_acknowledge()
|
kern_acknowledge()
|
||||||
|
@ -465,12 +466,28 @@ fn process_kern_message(waiter: Waiter,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_kern_queued_rpc(stream: &mut TcpStream,
|
||||||
|
session: &mut Session) -> io::Result<()> {
|
||||||
|
rpc_queue::dequeue(|slice| {
|
||||||
|
trace!("comm<-kern (async RPC)");
|
||||||
|
let length = NetworkEndian::read_u32(slice) as usize;
|
||||||
|
try!(host_write(stream, host::Reply::RpcRequest { async: true }));
|
||||||
|
trace!("{:?}" ,&slice[4..][..length]);
|
||||||
|
try!(stream.write(&slice[4..][..length]));
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn host_kernel_worker(waiter: Waiter,
|
fn host_kernel_worker(waiter: Waiter,
|
||||||
stream: &mut TcpStream,
|
stream: &mut TcpStream,
|
||||||
congress: &mut Congress) -> io::Result<()> {
|
congress: &mut Congress) -> io::Result<()> {
|
||||||
let mut session = Session::new(congress);
|
let mut session = Session::new(congress);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
while !rpc_queue::empty() {
|
||||||
|
try!(process_kern_queued_rpc(stream, &mut session))
|
||||||
|
}
|
||||||
|
|
||||||
if stream.readable() {
|
if stream.readable() {
|
||||||
try!(process_host_message(waiter, stream, &mut session));
|
try!(process_host_message(waiter, stream, &mut session));
|
||||||
}
|
}
|
||||||
|
@ -509,6 +526,10 @@ fn flash_kernel_worker(waiter: Waiter,
|
||||||
try!(kern_run(&mut session));
|
try!(kern_run(&mut session));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if !rpc_queue::empty() {
|
||||||
|
return Err(io_error("unexpected background RPC in flash kernel"))
|
||||||
|
}
|
||||||
|
|
||||||
if mailbox::receive() != 0 {
|
if mailbox::receive() != 0 {
|
||||||
if try!(process_kern_message(waiter, None, &mut session)) {
|
if try!(process_kern_message(waiter, None, &mut session)) {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
|
|
|
@ -107,7 +107,7 @@ pub enum Reply<'a> {
|
||||||
backtrace: &'a [usize]
|
backtrace: &'a [usize]
|
||||||
},
|
},
|
||||||
|
|
||||||
RpcRequest { service: u32 },
|
RpcRequest { async: bool },
|
||||||
|
|
||||||
FlashRead(&'a [u8]),
|
FlashRead(&'a [u8]),
|
||||||
FlashOk,
|
FlashOk,
|
||||||
|
@ -170,9 +170,9 @@ impl<'a> Reply<'a> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::RpcRequest { service } => {
|
Reply::RpcRequest { async } => {
|
||||||
try!(write_u8(writer, 10));
|
try!(write_u8(writer, 10));
|
||||||
try!(write_u32(writer, service));
|
try!(write_u8(writer, async as u8));
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::FlashRead(ref bytes) => {
|
Reply::FlashRead(ref bytes) => {
|
||||||
|
|
|
@ -7,6 +7,8 @@ OBJECTS := flash_storage.o main.o
|
||||||
OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o dds.o i2c.o ad9154.o
|
OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o dds.o i2c.o ad9154.o
|
||||||
|
|
||||||
RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug
|
RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug
|
||||||
|
CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b
|
||||||
|
export CORE_IO_COMMIT
|
||||||
|
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-I$(LIBALLOC_DIRECTORY) \
|
-I$(LIBALLOC_DIRECTORY) \
|
||||||
|
@ -54,6 +56,7 @@ $(RUSTOUT_DIRECTORY)/libksupport.a:
|
||||||
--manifest-path $(realpath $(RUNTIME_DIRECTORY)/../runtime.rs/libksupport/Cargo.toml) \
|
--manifest-path $(realpath $(RUNTIME_DIRECTORY)/../runtime.rs/libksupport/Cargo.toml) \
|
||||||
--target=or1k-unknown-none -- \
|
--target=or1k-unknown-none -- \
|
||||||
$(shell cat $(BUILDINC_DIRECTORY)/generated/rust-cfg) \
|
$(shell cat $(BUILDINC_DIRECTORY)/generated/rust-cfg) \
|
||||||
|
--cfg ksupport \
|
||||||
-C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s \
|
-C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s \
|
||||||
-L../libcompiler-rt
|
-L../libcompiler-rt
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,14 @@ INCLUDE generated/regions.ld
|
||||||
|
|
||||||
/* First 4M of main memory are reserved for runtime
|
/* First 4M of main memory are reserved for runtime
|
||||||
* code/data/heap, then comes kernel memory.
|
* code/data/heap, then comes kernel memory.
|
||||||
|
* Next 4M of main memory are reserved for
|
||||||
|
* the background RPC queue.
|
||||||
* First 256K of kernel memory are for support code.
|
* First 256K of kernel memory are for support code.
|
||||||
|
* Support code is loaded at ORIGIN-0x80 so that ELF headers
|
||||||
|
* are also loaded.
|
||||||
*/
|
*/
|
||||||
MEMORY {
|
MEMORY {
|
||||||
ksupport (RWX) : ORIGIN = 0x40400000, LENGTH = 0x40000
|
ksupport (RWX) : ORIGIN = 0x40800000, LENGTH = 0x40000
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kernel stack is at the end of main RAM. */
|
/* Kernel stack is at the end of main RAM. */
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
void send_to_log(const char *ptr, size_t length);
|
void send_to_log(const char *ptr, size_t length);
|
||||||
|
|
||||||
#define KERNELCPU_EXEC_ADDRESS 0x40400000
|
#define KERNELCPU_EXEC_ADDRESS 0x40800000
|
||||||
#define KERNELCPU_PAYLOAD_ADDRESS 0x40440000
|
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
|
||||||
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
|
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
|
||||||
#define KSUPPORT_HEADER_SIZE 0x80
|
#define KSUPPORT_HEADER_SIZE 0x80
|
||||||
|
|
||||||
|
@ -70,10 +70,33 @@ int dl_iterate_phdr (int (*callback)(struct dl_phdr_info *, size_t, void *), voi
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called by kernel */
|
/* called by kernel */
|
||||||
long lround(double x);
|
double round(double x);
|
||||||
long lround(double x)
|
double round(double x)
|
||||||
{
|
{
|
||||||
return x < 0 ? floor(x) : ceil(x);
|
union {double f; uint64_t i;} u = {x};
|
||||||
|
int e = u.i >> 52 & 0x7ff;
|
||||||
|
double y;
|
||||||
|
|
||||||
|
if (e >= 0x3ff+52)
|
||||||
|
return x;
|
||||||
|
if (u.i >> 63)
|
||||||
|
x = -x;
|
||||||
|
if (e < 0x3ff-1) {
|
||||||
|
/* we don't do it in ARTIQ */
|
||||||
|
/* raise inexact if x!=0 */
|
||||||
|
// FORCE_EVAL(x + 0x1p52);
|
||||||
|
return 0*u.f;
|
||||||
|
}
|
||||||
|
y = (double)(x + 0x1p52) - 0x1p52 - x;
|
||||||
|
if (y > 0.5)
|
||||||
|
y = y + x - 1;
|
||||||
|
else if (y <= -0.5)
|
||||||
|
y = y + x + 1;
|
||||||
|
else
|
||||||
|
y = y + x;
|
||||||
|
if (u.i >> 63)
|
||||||
|
y = -y;
|
||||||
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called by kernel */
|
/* called by kernel */
|
||||||
|
|
|
@ -177,6 +177,10 @@ u8_t* tcp_so_options_(struct tcp_pcb *pcb) {
|
||||||
return &pcb->so_options;
|
return &pcb->so_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tcp_nagle_disable_(struct tcp_pcb *pcb) {
|
||||||
|
tcp_nagle_disable(pcb);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
irq_setmask(0);
|
irq_setmask(0);
|
||||||
|
|
|
@ -124,6 +124,7 @@ unsigned int rtio_input_data(int channel)
|
||||||
|
|
||||||
void rtio_log_va(long long int timestamp, const char *fmt, va_list args)
|
void rtio_log_va(long long int timestamp, const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_RTIO_LOG_CHANNEL
|
||||||
// This executes on the kernel CPU's stack, which is specifically designed
|
// This executes on the kernel CPU's stack, which is specifically designed
|
||||||
// for allocation of this kind of massive buffers.
|
// for allocation of this kind of massive buffers.
|
||||||
int len = vsnprintf(NULL, 0, fmt, args);
|
int len = vsnprintf(NULL, 0, fmt, args);
|
||||||
|
@ -152,6 +153,7 @@ void rtio_log_va(long long int timestamp, const char *fmt, va_list args)
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtio_log(long long int timestamp, const char *fmt, ...)
|
void rtio_log(long long int timestamp, const char *fmt, ...)
|
||||||
|
|
|
@ -74,9 +74,7 @@ SECTIONS
|
||||||
.heap :
|
.heap :
|
||||||
{
|
{
|
||||||
_fheap = .;
|
_fheap = .;
|
||||||
. = ORIGIN(runtime) + LENGTH(runtime)
|
. = ORIGIN(runtime) + LENGTH(runtime);
|
||||||
/* Leave room for ksupport headers. */
|
|
||||||
- 0x1000;
|
|
||||||
_eheap = .;
|
_eheap = .;
|
||||||
} > runtime
|
} > runtime
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,27 @@ class AnnotationTest(ExperimentCase):
|
||||||
exp = self.create(_Annotation)
|
exp = self.create(_Annotation)
|
||||||
self.assertEqual(exp.overflow(1), True)
|
self.assertEqual(exp.overflow(1), True)
|
||||||
|
|
||||||
|
class _Async(EnvExperiment):
|
||||||
|
def build(self):
|
||||||
|
self.setattr_device("core")
|
||||||
|
|
||||||
|
@rpc(flags={"async"})
|
||||||
|
def recv_async(self, data):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def run(self):
|
||||||
|
# fast async path
|
||||||
|
self.recv_async([0]*128)
|
||||||
|
# slow async path
|
||||||
|
self.recv_async([0]*4096)
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncTest(ExperimentCase):
|
||||||
|
def test_args(self):
|
||||||
|
exp = self.create(_RPCTypes)
|
||||||
|
exp.run()
|
||||||
|
|
||||||
|
|
||||||
class _Payload1MB(EnvExperiment):
|
class _Payload1MB(EnvExperiment):
|
||||||
def build(self):
|
def build(self):
|
||||||
|
|
|
@ -450,6 +450,8 @@ class RPCTest(ExperimentCase):
|
||||||
"timings are dependent on CPU load and network conditions")
|
"timings are dependent on CPU load and network conditions")
|
||||||
def test_rpc_timing(self):
|
def test_rpc_timing(self):
|
||||||
self.execute(RPCTiming)
|
self.execute(RPCTiming)
|
||||||
self.assertGreater(self.dataset_mgr.get("rpc_time_mean"), 100*ns)
|
rpc_time_mean = self.dataset_mgr.get("rpc_time_mean")
|
||||||
self.assertLess(self.dataset_mgr.get("rpc_time_mean"), 15*ms)
|
print(rpc_time_mean)
|
||||||
self.assertLess(self.dataset_mgr.get("rpc_time_stddev"), 2*ms)
|
self.assertGreater(rpc_time_mean, 100*ns)
|
||||||
|
self.assertLess(rpc_time_mean, 2*ms)
|
||||||
|
self.assertLess(self.dataset_mgr.get("rpc_time_stddev"), 1*ms)
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t.ll
|
||||||
|
|
||||||
|
from artiq.language.core import *
|
||||||
|
from artiq.language.types import *
|
||||||
|
|
||||||
|
# CHECK: call void @send_async_rpc
|
||||||
|
|
||||||
|
@rpc(flags={"async"})
|
||||||
|
def foo():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
foo()
|
|
@ -0,0 +1,15 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
|
from artiq.language.core import *
|
||||||
|
from artiq.language.types import *
|
||||||
|
|
||||||
|
# CHECK-L: ${LINE:+2}: fatal: functions that return a value cannot be defined as async RPCs
|
||||||
|
@rpc(flags={"async"})
|
||||||
|
def foo() -> TInt32:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
# CHECK-L: ${LINE:+1}: note: function called here
|
||||||
|
foo()
|
|
@ -0,0 +1,26 @@
|
||||||
|
# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t.ll
|
||||||
|
|
||||||
|
from artiq.language.core import *
|
||||||
|
from artiq.language.types import *
|
||||||
|
|
||||||
|
class Class:
|
||||||
|
kernel_invariants = {"foo"}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.foo = True
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def run(self):
|
||||||
|
if self.foo:
|
||||||
|
print("bar")
|
||||||
|
else:
|
||||||
|
# Make sure all the code for this branch will be completely elided:
|
||||||
|
# CHECK-NOT: baz
|
||||||
|
print("baz")
|
||||||
|
|
||||||
|
obj = Class()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
obj.run()
|
|
@ -27,3 +27,27 @@ for x in range(10):
|
||||||
assert False
|
assert False
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
# Verify continue target is reset in else block.
|
||||||
|
cond = False
|
||||||
|
while True:
|
||||||
|
if cond:
|
||||||
|
break
|
||||||
|
cond = True
|
||||||
|
for _ in range(1):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
# Verify for target is reset in else block.
|
||||||
|
while True:
|
||||||
|
for _ in range(1):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
|
@ -29,3 +29,27 @@ while cond:
|
||||||
cond = False
|
cond = False
|
||||||
continue
|
continue
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
# Verify continue target is reset in else block.
|
||||||
|
cond = False
|
||||||
|
while True:
|
||||||
|
if cond:
|
||||||
|
break
|
||||||
|
cond = True
|
||||||
|
while False:
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
# Verify break target is reset in else block.
|
||||||
|
while True:
|
||||||
|
while False:
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
assert False
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
|
@ -18,7 +18,7 @@ requirements:
|
||||||
- binutils-or1k-linux
|
- binutils-or1k-linux
|
||||||
run:
|
run:
|
||||||
- python >=3.5.2
|
- python >=3.5.2
|
||||||
- llvmlite-artiq 0.10.0.dev py35_24
|
- llvmlite-artiq 0.12.0.dev py35_29
|
||||||
- lit
|
- lit
|
||||||
- outputcheck
|
- outputcheck
|
||||||
- scipy
|
- scipy
|
||||||
|
@ -37,7 +37,7 @@ requirements:
|
||||||
- pygit2
|
- pygit2
|
||||||
- aiohttp
|
- aiohttp
|
||||||
- binutils-or1k-linux
|
- binutils-or1k-linux
|
||||||
- pythonparser
|
- pythonparser 1.0
|
||||||
- levenshtein
|
- levenshtein
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
|
|
@ -47,6 +47,19 @@ The Python types correspond to ARTIQ type annotations as follows:
|
||||||
| range | TRange32, TRange64 |
|
| range | TRange32, TRange64 |
|
||||||
+-------------+-------------------------+
|
+-------------+-------------------------+
|
||||||
|
|
||||||
|
Asynchronous RPCs
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
If an RPC returns no value, it can be invoked in a way that does not block until the RPC finishes
|
||||||
|
execution, but only until it is queued. (Submitting asynchronous RPCs too rapidly, as well as
|
||||||
|
submitting asynchronous RPCs with arguments that are too large, can still block until completion.)
|
||||||
|
|
||||||
|
To define an asynchronous RPC, use the ``@rpc`` annotation with a flag: ::
|
||||||
|
|
||||||
|
@rpc(flags={"async"})
|
||||||
|
def record_result(x):
|
||||||
|
self.results.append(x)
|
||||||
|
|
||||||
Additional optimizations
|
Additional optimizations
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -74,7 +87,7 @@ Kernel invariants
|
||||||
|
|
||||||
The compiler attempts to remove or hoist out of loops any redundant memory load operations, as well as propagate known constants into function bodies, which can enable further optimization. However, it must make conservative assumptions about code that it is unable to observe, because such code can change the value of the attribute, making the optimization invalid.
|
The compiler attempts to remove or hoist out of loops any redundant memory load operations, as well as propagate known constants into function bodies, which can enable further optimization. However, it must make conservative assumptions about code that it is unable to observe, because such code can change the value of the attribute, making the optimization invalid.
|
||||||
|
|
||||||
When an attribute is known to never change while the kernel is running, it can be marked as a *kernel invariant* to enable more aggressive optimization for this specific attribute: ::
|
When an attribute is known to never change while the kernel is running, it can be marked as a *kernel invariant* to enable more aggressive optimization for this specific attribute. ::
|
||||||
|
|
||||||
class Converter:
|
class Converter:
|
||||||
kernel_invariants = {"ratio"}
|
kernel_invariants = {"ratio"}
|
||||||
|
@ -86,4 +99,32 @@ When an attribute is known to never change while the kernel is running, it can b
|
||||||
def convert(self, value):
|
def convert(self, value):
|
||||||
return value * self.ratio ** 2
|
return value * self.ratio ** 2
|
||||||
|
|
||||||
In the synthetic example above, the compiler will be able to detect that the result of evaluating ``self.ratio ** 2`` never changes and replace it with a constant, removing an expensive floating-point operation.
|
In the synthetic example above, the compiler will be able to detect that the result of evaluating ``self.ratio ** 2`` never changes and replace it with a constant, removing an expensive floating-point operation. ::
|
||||||
|
|
||||||
|
class Worker:
|
||||||
|
kernel_invariants = {"interval"}
|
||||||
|
|
||||||
|
def __init__(self, interval=1.0*us):
|
||||||
|
self.interval = interval
|
||||||
|
|
||||||
|
def work(self):
|
||||||
|
# something useful
|
||||||
|
|
||||||
|
class Looper:
|
||||||
|
def __init__(self, worker):
|
||||||
|
self.worker = worker
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def loop(self):
|
||||||
|
for _ in range(100):
|
||||||
|
delay(self.worker.interval / 5.0)
|
||||||
|
self.worker.work()
|
||||||
|
|
||||||
|
In the synthetic example above, the compiler will be able to detect that the result of evaluating ``self.interval / 5.0`` never changes, even though it neither knows the value of ``self.worker.interval`` beforehand nor can it see through the ``self.worker.work()`` function call, and hoist the expensive floating-point division out of the loop, transforming the code for ``loop`` into an equivalent of the following: ::
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def loop(self):
|
||||||
|
precomputed_delay_mu = seconds_to_mu(self.worker.interval / 5.0)
|
||||||
|
for _ in range(100):
|
||||||
|
delay_mu(precomputed_delay_mu)
|
||||||
|
self.worker.work()
|
||||||
|
|
|
@ -33,7 +33,7 @@ and the ARTIQ kernels.
|
||||||
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.27.tar.bz2
|
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.27.tar.bz2
|
||||||
$ tar xvf binutils-2.27.tar.bz2
|
$ tar xvf binutils-2.27.tar.bz2
|
||||||
$ cd binutils-2.27
|
$ cd binutils-2.27
|
||||||
$ curl -L 'https://github.com/m-labs/conda-recipes/blob/ece4cefbcce5548c5bd7fd4740d71ecd6930065e/conda/binutils-or1k-linux/fix-R_OR1K_GOTOFF-relocations.patch' | patch -p1
|
$ curl -L https://raw.githubusercontent.com/m-labs/conda-recipes/ece4cefbcce5548c5bd7fd4740d71ecd6930065e/conda/binutils-or1k-linux/fix-R_OR1K_GOTOFF-relocations.patch' | patch -p1
|
||||||
|
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
$ cd build
|
$ cd build
|
||||||
|
@ -62,18 +62,24 @@ and the ARTIQ kernels.
|
||||||
|
|
||||||
$ cd ~/artiq-dev
|
$ cd ~/artiq-dev
|
||||||
$ git clone https://github.com/m-labs/rust
|
$ git clone https://github.com/m-labs/rust
|
||||||
|
$ cd rust
|
||||||
$ git checkout artiq
|
$ git checkout artiq
|
||||||
|
$ git submodule update --init
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
$ cd build
|
$ cd build
|
||||||
$ ../configure --prefix=/usr/local/rust-or1k --llvm-root=/usr/local/llvm-or1k/bin/llvm-config --disable-manage-submodules
|
$ ../configure --prefix=/usr/local/rust-or1k --llvm-root=/usr/local/llvm-or1k --disable-manage-submodules
|
||||||
$ sudo make install -j4
|
$ sudo make install -j4
|
||||||
$ libs="libcore liballoc librustc_unicode libcollections liblibc_mini libunwind libpanic_unwind"
|
|
||||||
|
|
||||||
|
$ libs="libcore liballoc librustc_unicode libcollections liblibc_mini libunwind"
|
||||||
|
$ rustc="/usr/local/rust-or1k/bin/rustc --target or1k-unknown-none -g -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s -L ."
|
||||||
|
$ destdir="/usr/local/rust-or1k/lib/rustlib/or1k-unknown-none/lib/"
|
||||||
$ mkdir ../build-or1k
|
$ mkdir ../build-or1k
|
||||||
$ cd ../build-or1k
|
$ cd ../build-or1k
|
||||||
$ for lib in ${libs}; do /usr/local/rust-or1k/bin/rustc src/${lib}/lib.rs; done
|
$ for lib in ${libs}; do ${rustc} ../src/${lib}/lib.rs; done
|
||||||
$ /usr/local/rust-or1k/bin/rustc -Cpanic=abort src/libpanic_abort/lib.rs
|
$ ${rustc} -Cpanic=abort ../src/libpanic_abort/lib.rs
|
||||||
$ sudo cp * /usr/local/rust-or1k/lib/rustlib/or1k-unknown-none/lib/
|
$ ${rustc} -Cpanic=unwind ../src/libpanic_unwind/lib.rs --cfg llvm_libunwind
|
||||||
|
$ sudo mkdir -p ${destdir}
|
||||||
|
$ sudo cp *.rlib ${destdir}
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Compilation of LLVM can take more than 30 min on some machines. Compilation of Rust can take more than two hours.
|
Compilation of LLVM can take more than 30 min on some machines. Compilation of Rust can take more than two hours.
|
||||||
|
@ -167,7 +173,7 @@ These steps are required to generate gateware bitstream (``.bit``) files, build
|
||||||
|
|
||||||
$ python3.5 -m artiq.gateware.targets.kc705 -H nist_qc1 # or nist_qc2
|
$ python3.5 -m artiq.gateware.targets.kc705 -H nist_qc1 # or nist_qc2
|
||||||
|
|
||||||
.. note:: Add ``--toolchain vivado`` if you wish to use Vivado instead of ISE.
|
.. note:: Add ``--toolchain ise`` if you wish to use ISE instead of Vivado.
|
||||||
|
|
||||||
* Then, gather the binaries and flash them: ::
|
* Then, gather the binaries and flash them: ::
|
||||||
|
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -27,6 +27,7 @@ console_scripts = [
|
||||||
"artiq_coreconfig=artiq.frontend.artiq_coreconfig:main",
|
"artiq_coreconfig=artiq.frontend.artiq_coreconfig:main",
|
||||||
"artiq_corelog=artiq.frontend.artiq_corelog:main",
|
"artiq_corelog=artiq.frontend.artiq_corelog:main",
|
||||||
"artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main",
|
"artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main",
|
||||||
|
"artiq_devtool=artiq.frontend.artiq_devtool:main",
|
||||||
"artiq_influxdb=artiq.frontend.artiq_influxdb:main",
|
"artiq_influxdb=artiq.frontend.artiq_influxdb:main",
|
||||||
"artiq_master=artiq.frontend.artiq_master:main",
|
"artiq_master=artiq.frontend.artiq_master:main",
|
||||||
"artiq_mkfs=artiq.frontend.artiq_mkfs:main",
|
"artiq_mkfs=artiq.frontend.artiq_mkfs:main",
|
||||||
|
|
Loading…
Reference in New Issue