mirror of https://github.com/m-labs/artiq.git
Compare commits
87 Commits
Author | SHA1 | Date |
---|---|---|
Robert Jördens | 9db30ce8dc | |
Robert Jördens | 49a265453d | |
Sebastien Bourdeauducq | e1aafcbb4f | |
Sebastien Bourdeauducq | 2548e9d833 | |
whitequark | b92b00a1c8 | |
Sebastien Bourdeauducq | bfb03fdbba | |
Sebastien Bourdeauducq | 59fe69a4b3 | |
Sebastien Bourdeauducq | 8276c6588b | |
whitequark | aa64b8ad7a | |
whitequark | 6f7771cb01 | |
whitequark | d2e9ea8de6 | |
Robert Jördens | a85fd13c21 | |
Sebastien Bourdeauducq | 5f2256cb25 | |
Sebastien Bourdeauducq | 917477f937 | |
whitequark | 4f3e7af8d5 | |
whitequark | 3b82c585d1 | |
Sebastien Bourdeauducq | a433794483 | |
Sebastien Bourdeauducq | 6641f4c1ac | |
whitequark | 24562d232e | |
whitequark | 40b9a84a2b | |
whitequark | 46218c1fff | |
whitequark | 3ba82cf19c | |
Sebastien Bourdeauducq | e14626e432 | |
Sebastien Bourdeauducq | 4ae93d4fd8 | |
Robert Jördens | 66d1647efd | |
whitequark | e6306b712d | |
Sebastien Bourdeauducq | 14a90e5386 | |
Sebastien Bourdeauducq | 00c9b20d1e | |
Sebastien Bourdeauducq | 8c19d90179 | |
whitequark | 135c138ec3 | |
whitequark | d419ccdeca | |
Sebastien Bourdeauducq | 246a2bb3e1 | |
whitequark | 26dbf0841c | |
whitequark | 7af02787e0 | |
whitequark | 4bda29f863 | |
whitequark | c44d08a826 | |
whitequark | fbf7e70ef8 | |
whitequark | ca48c29a8b | |
whitequark | c9be535ba5 | |
whitequark | 3f8dc0233a | |
whitequark | 30b7bcf362 | |
whitequark | 99bc18dcd7 | |
whitequark | 65204a091f | |
whitequark | 2fd3b3324a | |
whitequark | 7f04e75042 | |
whitequark | e364213b62 | |
whitequark | 99bb1b0b70 | |
whitequark | b72178756e | |
whitequark | 6cbf8786d8 | |
whitequark | 0ede5d8638 | |
whitequark | 231bf77b43 | |
Sebastien Bourdeauducq | df2f0ead4a | |
whitequark | 16d49f38c1 | |
whitequark | 3f0277197f | |
Robert Jördens | e02dc834e6 | |
Robert Jördens | 6cb7f2e8e2 | |
Sebastien Bourdeauducq | 4c2f25e85e | |
Robert Jördens | 2c85597daa | |
Sebastien Bourdeauducq | 76a908c8a9 | |
whitequark | 0e5a5441aa | |
Sebastien Bourdeauducq | 45f510bcdc | |
Sebastien Bourdeauducq | 7e5a301a27 | |
Sebastien Bourdeauducq | 14714d3f9d | |
Sebastien Bourdeauducq | 25d3fc1e55 | |
Sebastien Bourdeauducq | f83cf8d1bb | |
Sebastien Bourdeauducq | 8ebca38323 | |
Sebastien Bourdeauducq | 0c47f83634 | |
whitequark | f0937bde16 | |
whitequark | 3ec1850949 | |
whitequark | 0d79b7d292 | |
whitequark | 3e96e0b10d | |
Sebastien Bourdeauducq | 6902868d58 | |
whitequark | 89b7c9e091 | |
Sebastien Bourdeauducq | 52e331204e | |
Robert Jördens | 8edb6a135a | |
Robert Jördens | cd0d73a1a2 | |
Sebastien Bourdeauducq | a6cd42c4aa | |
whitequark | 45c6ca96f8 | |
whitequark | db8300c990 | |
whitequark | ce7e30edfe | |
whitequark | a06f04dfbe | |
whitequark | 1521231b1b | |
whitequark | 67997d8955 | |
Sebastien Bourdeauducq | a49bb2bc50 | |
Sebastien Bourdeauducq | d500e61d89 | |
Sebastien Bourdeauducq | 04a9a0ce95 | |
Sebastien Bourdeauducq | ac28b377c7 |
|
@ -3,13 +3,39 @@
|
||||||
Release notes
|
Release notes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
3.4
|
||||||
|
---
|
||||||
|
|
||||||
|
No further notes.
|
||||||
|
|
||||||
|
|
||||||
|
3.3
|
||||||
|
---
|
||||||
|
|
||||||
|
No further notes.
|
||||||
|
|
||||||
|
|
||||||
|
3.2
|
||||||
|
---
|
||||||
|
|
||||||
|
* To accommodate larger runtimes, the flash layout as changed. As a result, the
|
||||||
|
contents of the flash storage will be lost when upgrading. Set the values back
|
||||||
|
(IP, MAC address, startup kernel, etc.) after the upgrade.
|
||||||
|
|
||||||
|
|
||||||
|
3.1
|
||||||
|
---
|
||||||
|
|
||||||
|
No further notes.
|
||||||
|
|
||||||
|
|
||||||
3.0
|
3.0
|
||||||
---
|
---
|
||||||
|
|
||||||
* The --embed option of applets is replaced with the environment variable
|
* The ``--embed`` option of applets is replaced with the environment variable
|
||||||
``ARTIQ_APPLET_EMBED``. The GUI sets this enviroment variable itself and the
|
``ARTIQ_APPLET_EMBED``. The GUI sets this enviroment variable itself and the
|
||||||
user simply needs to remove the ``--embed`` argument.
|
user simply needs to remove the ``--embed`` argument.
|
||||||
* EnvExperiment's prepare calls prepare for all its children.
|
* ``EnvExperiment``'s ``prepare`` calls ``prepare`` for all its children.
|
||||||
* Dynamic ``__getattr__``'s returning RPC target methods are not supported anymore.
|
* Dynamic ``__getattr__``'s returning RPC target methods are not supported anymore.
|
||||||
Controller driver classes must define all their methods intended for RPC as
|
Controller driver classes must define all their methods intended for RPC as
|
||||||
members.
|
members.
|
||||||
|
@ -22,7 +48,7 @@ Release notes
|
||||||
* The DDS class names and setup options have changed, this requires an update of
|
* The DDS class names and setup options have changed, this requires an update of
|
||||||
the device database.
|
the device database.
|
||||||
* ``int(a, width=b)`` has been removed. Use ``int32(a)`` and ``int64(a)``.
|
* ``int(a, width=b)`` has been removed. Use ``int32(a)`` and ``int64(a)``.
|
||||||
* The kc705 gateware target has been renamed kc705_dds.
|
* The KC705 gateware target has been renamed ``kc705_dds``.
|
||||||
* ``artiq.coredevice.comm_tcp`` has been renamed ``artiq.coredevice.comm_kernel``,
|
* ``artiq.coredevice.comm_tcp`` has been renamed ``artiq.coredevice.comm_kernel``,
|
||||||
and ``Comm`` has been renamed ``CommKernel``.
|
and ``Comm`` has been renamed ``CommKernel``.
|
||||||
* The "collision" and "busy" RTIO errors are reported through the log instead of
|
* The "collision" and "busy" RTIO errors are reported through the log instead of
|
||||||
|
@ -38,8 +64,8 @@ Release notes
|
||||||
identifiers (``true``, ``null``, ...) with their Python equivalents
|
identifiers (``true``, ``null``, ...) with their Python equivalents
|
||||||
(``True``, ``None`` ...).
|
(``True``, ``None`` ...).
|
||||||
* Controllers are now named ``aqctl_XXX`` instead of ``XXX_controller``.
|
* Controllers are now named ``aqctl_XXX`` instead of ``XXX_controller``.
|
||||||
* In the device database, the "comm" device has been folded into the "core" device.
|
* In the device database, the ``comm`` device has been folded into the ``core`` device.
|
||||||
Move the "host" argument into the "core" device, and remove the "comm" device.
|
Move the "host" argument into the ``core`` device, and remove the ``comm`` device.
|
||||||
* The core device log now contains important information about events such as
|
* The core device log now contains important information about events such as
|
||||||
RTIO collisions. A new controller ``aqctl_corelog`` must be running to forward
|
RTIO collisions. A new controller ``aqctl_corelog`` must be running to forward
|
||||||
those logs to the master. See the example device databases to see how to
|
those logs to the master. See the example device databases to see how to
|
||||||
|
@ -52,8 +78,15 @@ Release notes
|
||||||
at https://github.com/m-labs/pdq. All SPI/USB driver layers, Mediator,
|
at https://github.com/m-labs/pdq. All SPI/USB driver layers, Mediator,
|
||||||
CompoundPDQ and examples/documentation has been moved.
|
CompoundPDQ and examples/documentation has been moved.
|
||||||
* The master now rotates log files at midnight, rather than based on log size.
|
* The master now rotates log files at midnight, rather than based on log size.
|
||||||
* The results keys start_time and run_time are now stored as doubles of UNIX time,
|
* The results keys ``start_time`` and ``run_time`` are now stored as doubles of UNIX time,
|
||||||
rather than ints. The file names are still based on local time.
|
rather than ints. The file names are still based on local time.
|
||||||
|
* Packages are no longer available for 32-bit Windows.
|
||||||
|
|
||||||
|
|
||||||
|
2.5
|
||||||
|
---
|
||||||
|
|
||||||
|
No further notes.
|
||||||
|
|
||||||
|
|
||||||
2.4
|
2.4
|
||||||
|
@ -62,7 +95,6 @@ Release notes
|
||||||
No further notes.
|
No further notes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2.3
|
2.3
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -216,8 +216,12 @@ class Target:
|
||||||
filename, line = location.rsplit(":", 1)
|
filename, line = location.rsplit(":", 1)
|
||||||
if filename == "??" or filename == "<synthesized>":
|
if filename == "??" or filename == "<synthesized>":
|
||||||
continue
|
continue
|
||||||
|
if line == "?":
|
||||||
|
line = -1
|
||||||
|
else:
|
||||||
|
line = int(line)
|
||||||
# can't get column out of addr2line D:
|
# can't get column out of addr2line D:
|
||||||
backtrace.append((filename, int(line), -1, function, address))
|
backtrace.append((filename, line, -1, function, address))
|
||||||
return backtrace
|
return backtrace
|
||||||
|
|
||||||
def demangle(self, names):
|
def demangle(self, names):
|
||||||
|
|
|
@ -1289,6 +1289,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
return self.append(ir.Select(cond,
|
return self.append(ir.Select(cond,
|
||||||
ir.Constant(False, builtins.TBool()),
|
ir.Constant(False, builtins.TBool()),
|
||||||
ir.Constant(True, builtins.TBool())))
|
ir.Constant(True, builtins.TBool())))
|
||||||
|
elif isinstance(node.op, ast.Invert):
|
||||||
|
operand = self.visit(node.operand)
|
||||||
|
return self.append(ir.Arith(ast.BitXor(loc=None),
|
||||||
|
ir.Constant(-1, operand.type), operand))
|
||||||
elif isinstance(node.op, ast.USub):
|
elif isinstance(node.op, ast.USub):
|
||||||
operand = self.visit(node.operand)
|
operand = self.visit(node.operand)
|
||||||
return self.append(ir.Arith(ast.Sub(loc=None),
|
return self.append(ir.Arith(ast.Sub(loc=None),
|
||||||
|
@ -1319,7 +1323,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
lambda: self.alloc_exn(builtins.TException("ValueError"),
|
lambda: self.alloc_exn(builtins.TException("ValueError"),
|
||||||
ir.Constant("shift amount must be nonnegative", builtins.TStr())),
|
ir.Constant("shift amount must be nonnegative", builtins.TStr())),
|
||||||
loc=node.right.loc)
|
loc=node.right.loc)
|
||||||
elif isinstance(node.op, (ast.Div, ast.FloorDiv)):
|
elif isinstance(node.op, (ast.Div, ast.FloorDiv, ast.Mod)):
|
||||||
self._make_check(
|
self._make_check(
|
||||||
self.append(ir.Compare(ast.NotEq(loc=None), rhs, ir.Constant(0, rhs.type))),
|
self.append(ir.Compare(ast.NotEq(loc=None), rhs, ir.Constant(0, rhs.type))),
|
||||||
lambda: self.alloc_exn(builtins.TException("ZeroDivisionError"),
|
lambda: self.alloc_exn(builtins.TException("ZeroDivisionError"),
|
||||||
|
@ -1721,7 +1725,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
self.polymorphic_print([self.visit(prefix)],
|
self.polymorphic_print([self.visit(prefix)],
|
||||||
separator=" ", suffix="\x1E", as_rtio=True)
|
separator=" ", suffix="\x1E", as_rtio=True)
|
||||||
self.polymorphic_print([self.visit(arg) for arg in args],
|
self.polymorphic_print([self.visit(arg) for arg in args],
|
||||||
separator=" ", suffix="\n\x1D", as_rtio=True)
|
separator=" ", suffix="\x1D", as_rtio=True)
|
||||||
return ir.Constant(None, builtins.TNone())
|
return ir.Constant(None, builtins.TNone())
|
||||||
elif types.is_builtin(typ, "delay"):
|
elif types.is_builtin(typ, "delay"):
|
||||||
if len(node.args) == 1 and len(node.keywords) == 0:
|
if len(node.args) == 1 and len(node.keywords) == 0:
|
||||||
|
@ -1808,7 +1812,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
|
|
||||||
assert None not in args
|
assert None not in args
|
||||||
|
|
||||||
if self.unwind_target is None:
|
if self.unwind_target is None or \
|
||||||
|
types.is_c_function(callee.type) and "nounwind" in callee.type.flags:
|
||||||
insn = self.append(ir.Call(func, args, arg_exprs))
|
insn = self.append(ir.Call(func, args, arg_exprs))
|
||||||
else:
|
else:
|
||||||
after_invoke = self.add_block("invoke")
|
after_invoke = self.add_block("invoke")
|
||||||
|
|
|
@ -682,6 +682,11 @@ class Inferencer(algorithm.Visitor):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
diagnose(valid_forms())
|
diagnose(valid_forms())
|
||||||
|
elif types.is_builtin(typ, "str"):
|
||||||
|
diag = diagnostic.Diagnostic("error",
|
||||||
|
"strings currently cannot be constructed", {},
|
||||||
|
node.loc)
|
||||||
|
self.engine.process(diag)
|
||||||
elif types.is_builtin(typ, "list") or types.is_builtin(typ, "array"):
|
elif types.is_builtin(typ, "list") or types.is_builtin(typ, "array"):
|
||||||
if types.is_builtin(typ, "list"):
|
if types.is_builtin(typ, "list"):
|
||||||
valid_forms = lambda: [
|
valid_forms = lambda: [
|
||||||
|
|
|
@ -22,7 +22,7 @@ llptr = ll.IntType(8).as_pointer()
|
||||||
llptrptr = ll.IntType(8).as_pointer().as_pointer()
|
llptrptr = ll.IntType(8).as_pointer().as_pointer()
|
||||||
llslice = ll.LiteralStructType([llptr, lli32])
|
llslice = ll.LiteralStructType([llptr, lli32])
|
||||||
llsliceptr = ll.LiteralStructType([llptr, lli32]).as_pointer()
|
llsliceptr = ll.LiteralStructType([llptr, lli32]).as_pointer()
|
||||||
llmetadata = ll.MetaData()
|
llmetadata = ll.MetaDataType()
|
||||||
|
|
||||||
|
|
||||||
def memoize(generator):
|
def memoize(generator):
|
||||||
|
@ -270,7 +270,7 @@ class LLVMIRGenerator:
|
||||||
sanitized_str = re.sub(rb"[^a-zA-Z0-9_.]", b"", as_bytes[:20]).decode('ascii')
|
sanitized_str = re.sub(rb"[^a-zA-Z0-9_.]", b"", as_bytes[:20]).decode('ascii')
|
||||||
name = self.llmodule.get_unique_name("S.{}".format(sanitized_str))
|
name = self.llmodule.get_unique_name("S.{}".format(sanitized_str))
|
||||||
|
|
||||||
llstr = self.llmodule.get_global(name)
|
llstr = self.llmodule.globals.get(name)
|
||||||
if llstr is None:
|
if llstr is None:
|
||||||
llstrty = ll.ArrayType(lli8, len(as_bytes))
|
llstrty = ll.ArrayType(lli8, len(as_bytes))
|
||||||
llstr = ll.GlobalVariable(self.llmodule, llstrty, name)
|
llstr = ll.GlobalVariable(self.llmodule, llstrty, name)
|
||||||
|
@ -306,7 +306,7 @@ class LLVMIRGenerator:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
def llbuiltin(self, name):
|
def llbuiltin(self, name):
|
||||||
llglobal = self.llmodule.get_global(name)
|
llglobal = self.llmodule.globals.get(name)
|
||||||
if llglobal is not None:
|
if llglobal is not None:
|
||||||
return llglobal
|
return llglobal
|
||||||
|
|
||||||
|
@ -326,6 +326,12 @@ class LLVMIRGenerator:
|
||||||
llty = ll.FunctionType(llptr, [])
|
llty = ll.FunctionType(llptr, [])
|
||||||
elif name == "llvm.stackrestore":
|
elif name == "llvm.stackrestore":
|
||||||
llty = ll.FunctionType(llvoid, [llptr])
|
llty = ll.FunctionType(llvoid, [llptr])
|
||||||
|
elif name == "__py_modsi3":
|
||||||
|
llty = ll.FunctionType(lli32, [lli32, lli32])
|
||||||
|
elif name == "__py_moddi3":
|
||||||
|
llty = ll.FunctionType(lli64, [lli64, lli64])
|
||||||
|
elif name == "__py_moddf3":
|
||||||
|
llty = ll.FunctionType(lldouble, [lldouble, lldouble])
|
||||||
elif name == self.target.print_function:
|
elif name == self.target.print_function:
|
||||||
llty = ll.FunctionType(llvoid, [llptr], var_arg=True)
|
llty = ll.FunctionType(llvoid, [llptr], var_arg=True)
|
||||||
elif name == "rtio_log":
|
elif name == "rtio_log":
|
||||||
|
@ -363,13 +369,96 @@ class LLVMIRGenerator:
|
||||||
"watchdog_set", "watchdog_clear",
|
"watchdog_set", "watchdog_clear",
|
||||||
self.target.print_function):
|
self.target.print_function):
|
||||||
llglobal.attributes.add("nounwind")
|
llglobal.attributes.add("nounwind")
|
||||||
|
if name.find("__py_") == 0:
|
||||||
|
llglobal.linkage = 'linkonce_odr'
|
||||||
|
self.emit_intrinsic(name, llglobal)
|
||||||
else:
|
else:
|
||||||
llglobal = ll.GlobalVariable(self.llmodule, llty, name)
|
llglobal = ll.GlobalVariable(self.llmodule, llty, name)
|
||||||
|
|
||||||
return llglobal
|
return llglobal
|
||||||
|
|
||||||
|
def emit_intrinsic(self, name, llfun):
|
||||||
|
llbuilder = ll.IRBuilder()
|
||||||
|
llbuilder.position_at_end(llfun.append_basic_block("entry"))
|
||||||
|
|
||||||
|
if name == "__py_modsi3" or name == "__py_moddi3":
|
||||||
|
if name == "__py_modsi3":
|
||||||
|
llty = lli32
|
||||||
|
elif name == "__py_moddi3":
|
||||||
|
llty = lli64
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
"""
|
||||||
|
Reference Objects/intobject.c
|
||||||
|
xdivy = x / y;
|
||||||
|
xmody = (long)(x - (unsigned long)xdivy * y);
|
||||||
|
/* If the signs of x and y differ, and the remainder is non-0,
|
||||||
|
* C89 doesn't define whether xdivy is now the floor or the
|
||||||
|
* ceiling of the infinitely precise quotient. We want the floor,
|
||||||
|
* and we have it iff the remainder's sign matches y's.
|
||||||
|
*/
|
||||||
|
if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) {
|
||||||
|
xmody += y;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
llx, lly = llfun.args
|
||||||
|
llxdivy = llbuilder.sdiv(llx, lly)
|
||||||
|
llxremy = llbuilder.srem(llx, lly)
|
||||||
|
|
||||||
|
llxmodynonzero = llbuilder.icmp_signed('!=', llxremy, ll.Constant(llty, 0))
|
||||||
|
lldiffsign = llbuilder.icmp_signed('<', llbuilder.xor(llx, lly), ll.Constant(llty, 0))
|
||||||
|
|
||||||
|
llcond = llbuilder.and_(llxmodynonzero, lldiffsign)
|
||||||
|
with llbuilder.if_then(llcond):
|
||||||
|
llbuilder.ret(llbuilder.add(llxremy, lly))
|
||||||
|
llbuilder.ret(llxremy)
|
||||||
|
elif name == "__py_moddf3":
|
||||||
|
"""
|
||||||
|
Reference Objects/floatobject.c
|
||||||
|
mod = fmod(vx, wx);
|
||||||
|
/* fmod is typically exact, so vx-mod is *mathematically* an
|
||||||
|
exact multiple of wx. But this is fp arithmetic, and fp
|
||||||
|
vx - mod is an approximation; the result is that div may
|
||||||
|
not be an exact integral value after the division, although
|
||||||
|
it will always be very close to one.
|
||||||
|
*/
|
||||||
|
// ...
|
||||||
|
if (mod) {
|
||||||
|
/* ensure the remainder has the same sign as the denominator */
|
||||||
|
if ((wx < 0) != (mod < 0)) {
|
||||||
|
mod += wx;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* the remainder is zero, and in the presence of signed zeroes
|
||||||
|
fmod returns different results across platforms; ensure
|
||||||
|
it has the same sign as the denominator; we'd like to do
|
||||||
|
"mod = wx * 0.0", but that may get optimized away */
|
||||||
|
mod *= mod; /* hide "mod = +0" from optimizer */
|
||||||
|
if (wx < 0.0)
|
||||||
|
mod = -mod;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
llv, llw = llfun.args
|
||||||
|
llrem = llbuilder.frem(llv, llw)
|
||||||
|
|
||||||
|
llremnonzero = llbuilder.fcmp_unordered('!=', llrem, ll.Constant(lldouble, 0.0))
|
||||||
|
llwltzero = llbuilder.fcmp_ordered('<', llw, ll.Constant(lldouble, 0.0))
|
||||||
|
llremltzero = llbuilder.fcmp_ordered('<', llrem, ll.Constant(lldouble, 0.0))
|
||||||
|
lldiffsign = llbuilder.icmp_unsigned('!=', llwltzero, llremltzero)
|
||||||
|
|
||||||
|
llcond = llbuilder.and_(llremnonzero, lldiffsign)
|
||||||
|
with llbuilder.if_then(llcond):
|
||||||
|
llbuilder.ret(llbuilder.fadd(llrem, llw))
|
||||||
|
llbuilder.ret(llrem)
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
def get_function(self, typ, name):
|
def get_function(self, typ, name):
|
||||||
llfun = self.llmodule.get_global(name)
|
llfun = self.llmodule.globals.get(name)
|
||||||
if llfun is None:
|
if llfun is None:
|
||||||
llfunty = self.llty_of_type(typ, bare=True)
|
llfunty = self.llty_of_type(typ, bare=True)
|
||||||
llfun = ll.Function(self.llmodule, llfunty, name)
|
llfun = ll.Function(self.llmodule, llfunty, name)
|
||||||
|
@ -410,7 +499,7 @@ class LLVMIRGenerator:
|
||||||
llobjects = defaultdict(lambda: [])
|
llobjects = defaultdict(lambda: [])
|
||||||
|
|
||||||
for obj_id, obj_ref, obj_typ in self.embedding_map.iter_objects():
|
for obj_id, obj_ref, obj_typ in self.embedding_map.iter_objects():
|
||||||
llobject = self.llmodule.get_global("O.{}".format(obj_id))
|
llobject = self.llmodule.globals.get("O.{}".format(obj_id))
|
||||||
if llobject is not None:
|
if llobject is not None:
|
||||||
llobjects[obj_typ].append(llobject.bitcast(llptr))
|
llobjects[obj_typ].append(llobject.bitcast(llptr))
|
||||||
|
|
||||||
|
@ -905,22 +994,15 @@ class LLVMIRGenerator:
|
||||||
return self.llbuilder.sdiv(self.map(insn.lhs()), self.map(insn.rhs()),
|
return self.llbuilder.sdiv(self.map(insn.lhs()), self.map(insn.rhs()),
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
elif isinstance(insn.op, ast.Mod):
|
elif isinstance(insn.op, ast.Mod):
|
||||||
# Python only has the modulo operator, LLVM only has the remainder
|
|
||||||
if builtins.is_float(insn.type):
|
|
||||||
llvalue = self.llbuilder.frem(self.map(insn.lhs()), self.map(insn.rhs()))
|
|
||||||
self.add_fast_math_flags(llvalue)
|
|
||||||
return self.llbuilder.call(self.llbuiltin("llvm.copysign.f64"),
|
|
||||||
[llvalue, self.map(insn.rhs())],
|
|
||||||
name=insn.name)
|
|
||||||
else:
|
|
||||||
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
||||||
llxorsign = self.llbuilder.and_(self.llbuilder.xor(lllhs, llrhs),
|
if builtins.is_float(insn.type):
|
||||||
ll.Constant(lllhs.type, 1 << lllhs.type.width - 1))
|
intrinsic = "__py_moddf3"
|
||||||
llnegate = self.llbuilder.icmp_unsigned('!=',
|
elif builtins.is_int32(insn.type):
|
||||||
llxorsign, ll.Constant(llxorsign.type, 0))
|
intrinsic = "__py_modsi3"
|
||||||
llvalue = self.llbuilder.srem(lllhs, llrhs)
|
elif builtins.is_int64(insn.type):
|
||||||
llnegvalue = self.llbuilder.sub(ll.Constant(llvalue.type, 0), llvalue)
|
intrinsic = "__py_moddi3"
|
||||||
return self.llbuilder.select(llnegate, llnegvalue, llvalue)
|
return self.llbuilder.call(self.llbuiltin(intrinsic), [lllhs, llrhs],
|
||||||
|
name=insn.name)
|
||||||
elif isinstance(insn.op, ast.Pow):
|
elif isinstance(insn.op, ast.Pow):
|
||||||
if builtins.is_float(insn.type):
|
if builtins.is_float(insn.type):
|
||||||
return self.llbuilder.call(self.llbuiltin("llvm.pow.f64"),
|
return self.llbuilder.call(self.llbuiltin("llvm.pow.f64"),
|
||||||
|
@ -1127,7 +1209,7 @@ class LLVMIRGenerator:
|
||||||
llargs.append(llarg)
|
llargs.append(llarg)
|
||||||
|
|
||||||
llfunname = insn.target_function().type.name
|
llfunname = insn.target_function().type.name
|
||||||
llfun = self.llmodule.get_global(llfunname)
|
llfun = self.llmodule.globals.get(llfunname)
|
||||||
if llfun is None:
|
if llfun is None:
|
||||||
llretty = self.llty_of_type(insn.type, for_return=True)
|
llretty = self.llty_of_type(insn.type, for_return=True)
|
||||||
if self.needs_sret(llretty):
|
if self.needs_sret(llretty):
|
||||||
|
@ -1366,9 +1448,8 @@ class LLVMIRGenerator:
|
||||||
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
|
|
||||||
# See the comment in process_Call.
|
# The !tbaa metadata is not legal to use with the invoke instruction,
|
||||||
if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags:
|
# so unlike process_Call, we do not set it here.
|
||||||
llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
|
|
||||||
|
|
||||||
return llcall
|
return llcall
|
||||||
|
|
||||||
|
@ -1561,7 +1642,7 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
llclauseexnname = self.llconst_of_const(
|
llclauseexnname = self.llconst_of_const(
|
||||||
ir.Constant(exnname, builtins.TStr()))
|
ir.Constant(exnname, builtins.TStr()))
|
||||||
llclauseexnnameptr = self.llmodule.get_global("exn.{}".format(exnname))
|
llclauseexnnameptr = self.llmodule.globals.get("exn.{}".format(exnname))
|
||||||
if llclauseexnnameptr is None:
|
if llclauseexnnameptr is None:
|
||||||
llclauseexnnameptr = ll.GlobalVariable(self.llmodule, llclauseexnname.type,
|
llclauseexnnameptr = ll.GlobalVariable(self.llmodule, llclauseexnname.type,
|
||||||
name="exn.{}".format(exnname))
|
name="exn.{}".format(exnname))
|
||||||
|
|
|
@ -298,8 +298,8 @@ class EscapeValidator(algorithm.Visitor):
|
||||||
# and exceptions can only refer to strings, so we don't actually check
|
# and exceptions can only refer to strings, so we don't actually check
|
||||||
# this property. But we will need to, if string operations are ever added.
|
# this property. But we will need to, if string operations are ever added.
|
||||||
|
|
||||||
def visit_assignment(self, target, value, is_aug_assign=False):
|
def visit_assignment(self, target, value):
|
||||||
value_region = self._region_of(value) if not is_aug_assign else self.youngest_region
|
value_region = self._region_of(value)
|
||||||
|
|
||||||
# If this is a variable, we might need to contract the live range.
|
# If this is a variable, we might need to contract the live range.
|
||||||
if isinstance(value_region, Region):
|
if isinstance(value_region, Region):
|
||||||
|
@ -316,19 +316,11 @@ class EscapeValidator(algorithm.Visitor):
|
||||||
target_regions = [self._region_of(name) for name in target_names]
|
target_regions = [self._region_of(name) for name in target_names]
|
||||||
for target_region in target_regions:
|
for target_region in target_regions:
|
||||||
if not Region.outlives(value_region, target_region):
|
if not Region.outlives(value_region, target_region):
|
||||||
if is_aug_assign:
|
|
||||||
target_desc = "the assignment target, allocated here,"
|
|
||||||
else:
|
|
||||||
target_desc = "the assignment target"
|
|
||||||
note = diagnostic.Diagnostic("note",
|
|
||||||
"this expression has type {type}",
|
|
||||||
{"type": types.TypePrinter().name(value.type)},
|
|
||||||
value.loc)
|
|
||||||
diag = diagnostic.Diagnostic("error",
|
diag = diagnostic.Diagnostic("error",
|
||||||
"the assigned value does not outlive the assignment target", {},
|
"the assigned value does not outlive the assignment target", {},
|
||||||
value.loc, [target.loc],
|
value.loc, [target.loc],
|
||||||
notes=self._diagnostics_for(target_region, target.loc,
|
notes=self._diagnostics_for(target_region, target.loc,
|
||||||
target_desc) +
|
"the assignment target") +
|
||||||
self._diagnostics_for(value_region, value.loc,
|
self._diagnostics_for(value_region, value.loc,
|
||||||
"the assigned value"))
|
"the assigned value"))
|
||||||
self.engine.process(diag)
|
self.engine.process(diag)
|
||||||
|
@ -339,9 +331,19 @@ class EscapeValidator(algorithm.Visitor):
|
||||||
|
|
||||||
def visit_AugAssign(self, node):
|
def visit_AugAssign(self, node):
|
||||||
if builtins.is_allocated(node.target.type):
|
if builtins.is_allocated(node.target.type):
|
||||||
# If the target is mutable, op-assignment will allocate
|
note = diagnostic.Diagnostic("note",
|
||||||
# in the youngest region.
|
"try using `{lhs} = {lhs} {op} {rhs}` instead",
|
||||||
self.visit_assignment(node.target, node.value, is_aug_assign=True)
|
{"lhs": node.target.loc.source(),
|
||||||
|
"rhs": node.value.loc.source(),
|
||||||
|
"op": node.op.loc.source()[:-1]},
|
||||||
|
node.loc)
|
||||||
|
diag = diagnostic.Diagnostic("error",
|
||||||
|
"values cannot be mutated in-place", {},
|
||||||
|
node.op.loc, [node.target.loc],
|
||||||
|
notes=[note])
|
||||||
|
self.engine.process(diag)
|
||||||
|
|
||||||
|
self.visit_assignment(node.target, node.value)
|
||||||
|
|
||||||
def visit_Return(self, node):
|
def visit_Return(self, node):
|
||||||
region = self._region_of(node.value)
|
region = self._region_of(node.value)
|
||||||
|
|
|
@ -32,7 +32,7 @@ class Config:
|
||||||
Exposes the configurable quantities of a single SAWG channel.
|
Exposes the configurable quantities of a single SAWG channel.
|
||||||
|
|
||||||
Access to the configuration registers for a SAWG channel can not
|
Access to the configuration registers for a SAWG channel can not
|
||||||
be concurrent. There must be at least :attr:_rtio_interval` machine
|
be concurrent. There must be at least :attr:`_rtio_interval` machine
|
||||||
units of delay between accesses. Replacement is not supported and will be
|
units of delay between accesses. Replacement is not supported and will be
|
||||||
lead to an ``RTIOCollision`` as this is likely a programming error.
|
lead to an ``RTIOCollision`` as this is likely a programming error.
|
||||||
All methods therefore advance the timeline by the duration of one
|
All methods therefore advance the timeline by the duration of one
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# The RTIO channel numbers here are for NIST CLOCK on KC705.
|
# The RTIO channel numbers here are for NIST CLOCK on KC705.
|
||||||
# The list of devices here is not exhaustive.
|
# The list of devices here is not exhaustive.
|
||||||
|
|
||||||
core_addr = "kc705.lab.m-labs.hk"
|
core_addr = "kc705-1.lab.m-labs.hk"
|
||||||
|
|
||||||
device_db = {
|
device_db = {
|
||||||
"core": {
|
"core": {
|
||||||
|
@ -33,7 +33,7 @@ device_db = {
|
||||||
"class": "DDSGroupAD9914",
|
"class": "DDSGroupAD9914",
|
||||||
"arguments": {
|
"arguments": {
|
||||||
"sysclk": 3e9,
|
"sysclk": 3e9,
|
||||||
"first_dds_bus_channel": 26,
|
"first_dds_bus_channel": 27,
|
||||||
"dds_bus_count": 2,
|
"dds_bus_count": 2,
|
||||||
"dds_channel_count": 3
|
"dds_channel_count": 3
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
[root]
|
|
||||||
name = "std_artiq"
|
|
||||||
version = "0.0.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloc_list"
|
name = "alloc_list"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -17,23 +13,28 @@ dependencies = [
|
||||||
"board 0.0.0",
|
"board 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "board"
|
name = "board"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "build_artiq"
|
name = "build_artiq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.0.0"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -41,7 +42,7 @@ name = "compiler_builtins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568#631b5687b24af413fdbffa4c2644484e60660b00"
|
source = "git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568#631b5687b24af413fdbffa4c2644484e60660b00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -55,8 +56,8 @@ name = "drtioaux"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"board 0.0.0",
|
"board 0.0.0",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"std_artiq 0.0.0",
|
"std_artiq 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -69,12 +70,12 @@ name = "fringe"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "git+https://github.com/m-labs/libfringe?rev=bd23494#bd2349467157969324ca7da5d2ae033c7ffac0c0"
|
source = "git+https://github.com/m-labs/libfringe?rev=bd23494#bd2349467157969324ca7da5d2ae033c7ffac0c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gcc"
|
name = "gcc"
|
||||||
version = "0.3.42"
|
version = "0.3.54"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -94,7 +95,7 @@ dependencies = [
|
||||||
"amp 0.0.0",
|
"amp 0.0.0",
|
||||||
"board 0.0.0",
|
"board 0.0.0",
|
||||||
"build_artiq 0.0.0",
|
"build_artiq 0.0.0",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dyld 0.0.0",
|
"dyld 0.0.0",
|
||||||
"proto 0.0.0",
|
"proto 0.0.0",
|
||||||
|
@ -103,12 +104,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.18"
|
version = "0.2.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.3.6"
|
version = "0.3.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -121,23 +122,23 @@ name = "logger_artiq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"board 0.0.0",
|
"board 0.0.0",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "managed"
|
name = "managed"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proto"
|
name = "proto"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dyld 0.0.0",
|
"dyld 0.0.0",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"std_artiq 0.0.0",
|
"std_artiq 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -147,17 +148,18 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloc_list 0.0.0",
|
"alloc_list 0.0.0",
|
||||||
"amp 0.0.0",
|
"amp 0.0.0",
|
||||||
|
"backtrace_artiq 0.0.0",
|
||||||
"board 0.0.0",
|
"board 0.0.0",
|
||||||
"build_artiq 0.0.0",
|
"build_artiq 0.0.0",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"drtioaux 0.0.0",
|
"drtioaux 0.0.0",
|
||||||
"fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)",
|
"fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"logger_artiq 0.0.0",
|
"logger_artiq 0.0.0",
|
||||||
"proto 0.0.0",
|
"proto 0.0.0",
|
||||||
"smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=6f5ae33)",
|
"smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)",
|
||||||
"std_artiq 0.0.0",
|
"std_artiq 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -166,6 +168,15 @@ name = "rustc-cfg"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "satman"
|
name = "satman"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -175,7 +186,7 @@ dependencies = [
|
||||||
"build_artiq 0.0.0",
|
"build_artiq 0.0.0",
|
||||||
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
||||||
"drtioaux 0.0.0",
|
"drtioaux 0.0.0",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"logger_artiq 0.0.0",
|
"logger_artiq 0.0.0",
|
||||||
"std_artiq 0.0.0",
|
"std_artiq 0.0.0",
|
||||||
]
|
]
|
||||||
|
@ -183,19 +194,24 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smoltcp"
|
name = "smoltcp"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/m-labs/smoltcp?rev=6f5ae33#6f5ae33501827d57926469c6f1a860205a24f7ae"
|
source = "git+https://github.com/m-labs/smoltcp?rev=181083f#181083f18c977b8a0463a67e360e4db20594fa21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"managed 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "std_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "1.0.3"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -210,18 +226,19 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
|
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||||
"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "<none>"
|
"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "<none>"
|
||||||
"checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
"checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
||||||
"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "<none>"
|
"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "<none>"
|
||||||
"checksum gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0"
|
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
|
"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0"
|
||||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||||
"checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493"
|
"checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493"
|
||||||
"checksum managed 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d48e8c30a4363e2981fe4db20527f6ab0f32a243bbc75379dea5a64f60dae4"
|
"checksum managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "786bd3519bdfb0e1a57146a74b7584555dd6c4f1b6e1137c70e177d60dde8186"
|
||||||
"checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704"
|
"checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704"
|
||||||
"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=6f5ae33)" = "<none>"
|
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
||||||
"checksum walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd7c16466ecc507c7cb5988db03e6eab4aaeab89a5c37a29251fcfd3ac9b7afe"
|
"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "<none>"
|
||||||
|
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
|
||||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["runtime", "ksupport", "satman"]
|
members = ["runtime", "ksupport", "satman"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
debug = 1 # either 0 or 2 cause an LLVM ICE
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
[package]
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
name = "bootloader"
|
||||||
|
version = "0.0.0"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "bootloader"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
path = "main.rs"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
build_misoc = { path = "../libbuild_misoc" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
byteorder = { version = "1.0", default-features = false }
|
||||||
|
crc = { version = "1.7", default-features = false }
|
||||||
|
board = { path = "../libboard", features = ["uart_console", "smoltcp"] }
|
||||||
|
|
||||||
|
[dependencies.smoltcp]
|
||||||
|
git = "https://github.com/m-labs/smoltcp"
|
||||||
|
rev = "181083f"
|
||||||
|
default-features = false
|
||||||
|
features = ["proto-ipv4", "socket-tcp"]
|
|
@ -5,7 +5,6 @@ CFLAGS += \
|
||||||
-I$(LIBUNWIND_DIRECTORY) \
|
-I$(LIBUNWIND_DIRECTORY) \
|
||||||
-I$(LIBUNWIND_DIRECTORY)/../unwinder/include \
|
-I$(LIBUNWIND_DIRECTORY)/../unwinder/include \
|
||||||
-I$(MISOC_DIRECTORY)/software/include/dyld
|
-I$(MISOC_DIRECTORY)/software/include/dyld
|
||||||
CFLAGS += -DNDEBUG
|
|
||||||
|
|
||||||
LDFLAGS += --eh-frame-hdr \
|
LDFLAGS += --eh-frame-hdr \
|
||||||
-L../libcompiler-rt \
|
-L../libcompiler-rt \
|
||||||
|
@ -15,22 +14,15 @@ LDFLAGS += --eh-frame-hdr \
|
||||||
|
|
||||||
RUSTFLAGS += -Cpanic=unwind
|
RUSTFLAGS += -Cpanic=unwind
|
||||||
|
|
||||||
all: ksupport.elf
|
all:: ksupport.elf
|
||||||
|
|
||||||
.PHONY: $(RUSTOUT)/libksupport.a
|
.PHONY: $(RUSTOUT)/libksupport.a
|
||||||
$(RUSTOUT)/libksupport.a:
|
$(RUSTOUT)/libksupport.a:
|
||||||
$(cargo) --manifest-path $(KSUPPORT_DIRECTORY)/Cargo.toml
|
$(cargo) --manifest-path $(KSUPPORT_DIRECTORY)/Cargo.toml
|
||||||
|
|
||||||
ksupport.elf: $(RUSTOUT)/libksupport.a glue.o
|
ksupport.elf: $(RUSTOUT)/libksupport.a glue.o
|
||||||
$(LD) $(LDFLAGS) -T $(KSUPPORT_DIRECTORY)/ksupport.ld -o $@ $^ \
|
$(link) -T $(KSUPPORT_DIRECTORY)/ksupport.ld \
|
||||||
-lunwind -lcompiler-rt -lbase -lm
|
-lunwind-elf -lcompiler-rt -lbase -lm
|
||||||
@chmod -x $@
|
|
||||||
|
|
||||||
%.o: $(KSUPPORT_DIRECTORY)/%.c
|
%.o: $(KSUPPORT_DIRECTORY)/%.c
|
||||||
$(compile)
|
$(compile)
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) *.o ksupport.elf
|
|
||||||
$(RM) -rf cargo
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ extern fn rpc_recv(slot: *mut ()) -> usize {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminate(exception: &eh::Exception, mut backtrace: &mut [usize]) -> ! {
|
fn terminate(exception: &eh::Exception, backtrace: &mut [usize]) -> ! {
|
||||||
let mut cursor = 0;
|
let mut cursor = 0;
|
||||||
for index in 0..backtrace.len() {
|
for index in 0..backtrace.len() {
|
||||||
if backtrace[index] > kernel_proto::KERNELCPU_PAYLOAD_ADDRESS {
|
if backtrace[index] > kernel_proto::KERNELCPU_PAYLOAD_ADDRESS {
|
||||||
|
@ -333,7 +333,7 @@ extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, wor
|
||||||
if DMA_RECORDER.buffer.len() - DMA_RECORDER.data_len < length {
|
if DMA_RECORDER.buffer.len() - DMA_RECORDER.data_len < length {
|
||||||
dma_record_flush()
|
dma_record_flush()
|
||||||
}
|
}
|
||||||
let mut dst = &mut DMA_RECORDER.buffer[DMA_RECORDER.data_len..
|
let dst = &mut DMA_RECORDER.buffer[DMA_RECORDER.data_len..
|
||||||
DMA_RECORDER.data_len + length];
|
DMA_RECORDER.data_len + length];
|
||||||
dst[..header_length].copy_from_slice(&header[..]);
|
dst[..header_length].copy_from_slice(&header[..]);
|
||||||
dst[header_length..].copy_from_slice(&data[..]);
|
dst[header_length..].copy_from_slice(&data[..]);
|
||||||
|
|
|
@ -140,18 +140,19 @@ pub fn log(timestamp: i64, data: &[u8]) {
|
||||||
for i in 0..data.len() {
|
for i in 0..data.len() {
|
||||||
word <<= 8;
|
word <<= 8;
|
||||||
word |= data[i] as u32;
|
word |= data[i] as u32;
|
||||||
if i % 4 == 0 {
|
if i % 4 == 3 {
|
||||||
rtio_o_data_write(0, word);
|
rtio_o_data_write(0, word);
|
||||||
csr::rtio::o_we_write(1);
|
csr::rtio::o_we_write(1);
|
||||||
word = 0;
|
word = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
word <<= 8;
|
if word != 0 {
|
||||||
rtio_o_data_write(0, word);
|
rtio_o_data_write(0, word);
|
||||||
csr::rtio::o_we_write(1);
|
csr::rtio::o_we_write(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(has_rtio_log))]
|
#[cfg(not(has_rtio_log))]
|
||||||
pub fn log(_timestamp: i64, _data: &[u8]) {}
|
pub fn log(_timestamp: i64, _data: &[u8]) {}
|
||||||
|
|
|
@ -104,19 +104,17 @@ unsafe impl<'a> Alloc for &'a ListAlloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oom(&mut self, err: AllocErr) -> ! {
|
fn oom(&mut self, err: AllocErr) -> ! {
|
||||||
panic!("cannot allocate: {:?}", err)
|
panic!("heap view: {}\ncannot allocate: {:?}", self, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListAlloc {
|
impl fmt::Display for ListAlloc {
|
||||||
pub fn debug_dump(&self, f: &mut fmt::Write) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut total_busy = 0;
|
let mut total_busy = 0;
|
||||||
let mut total_idle = 0;
|
let mut total_idle = 0;
|
||||||
let mut total_meta = 0;
|
let mut total_meta = 0;
|
||||||
|
|
||||||
write!(f, "Heap view:\n")?;
|
|
||||||
|
|
||||||
let mut curr = self.root;
|
let mut curr = self.root;
|
||||||
while !curr.is_null() {
|
while !curr.is_null() {
|
||||||
total_meta += mem::size_of::<Header>();
|
total_meta += mem::size_of::<Header>();
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
name = "backtrace_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "backtrace_artiq"
|
||||||
|
path = "lib.rs"
|
|
@ -0,0 +1,30 @@
|
||||||
|
#![feature(libc, panic_unwind)]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate unwind;
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
use unwind as uw;
|
||||||
|
use libc::c_void;
|
||||||
|
|
||||||
|
pub fn backtrace<F>(mut f: F) -> Result<(), uw::_Unwind_Reason_Code>
|
||||||
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
|
extern fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void)
|
||||||
|
-> uw::_Unwind_Reason_Code
|
||||||
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let step_fn = &mut *(arg as *mut F);
|
||||||
|
step_fn(uw::_Unwind_GetIP(context));
|
||||||
|
uw::_URC_NO_REASON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
match uw::_Unwind_Backtrace(trace::<F>, &mut f as *mut _ as *mut c_void) {
|
||||||
|
uw::_URC_NO_REASON => Ok(()),
|
||||||
|
err => Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ name = "board"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
byteorder = { version = "1.0", default-features = false }
|
||||||
log = { version = "0.3", default-features = false }
|
log = { version = "0.3", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
#[cfg(has_spiflash)]
|
||||||
|
mod imp {
|
||||||
|
use core::str;
|
||||||
|
use byteorder::{ByteOrder, BigEndian};
|
||||||
|
use cache;
|
||||||
|
use spiflash;
|
||||||
|
|
||||||
|
// One flash sector immediately before the firmware.
|
||||||
|
const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::SECTOR_SIZE;
|
||||||
|
const SIZE: usize = spiflash::SECTOR_SIZE;
|
||||||
|
|
||||||
|
mod lock {
|
||||||
|
use core::slice;
|
||||||
|
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||||
|
|
||||||
|
static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||||
|
|
||||||
|
pub struct Lock;
|
||||||
|
|
||||||
|
impl Lock {
|
||||||
|
pub fn take() -> Result<Lock, ()> {
|
||||||
|
if LOCKED.swap(1, Ordering::SeqCst) != 0 {
|
||||||
|
Err(()) // already locked
|
||||||
|
} else {
|
||||||
|
Ok(Lock) // locked now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data(&self) -> &'static [u8] {
|
||||||
|
unsafe { slice::from_raw_parts(super::ADDR as *const u8, super::SIZE) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Lock {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
LOCKED.store(0, Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use self::lock::Lock;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Iter<'a> {
|
||||||
|
data: &'a [u8],
|
||||||
|
offset: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iter<'a> {
|
||||||
|
fn new(data: &'a [u8]) -> Iter<'a> {
|
||||||
|
Iter { data: data, offset: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for Iter<'a> {
|
||||||
|
type Item = Result<(&'a [u8], &'a [u8]), ()>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let data = &self.data[self.offset..];
|
||||||
|
|
||||||
|
if data.len() < 4 {
|
||||||
|
error!("offset {}: truncated record", self.offset);
|
||||||
|
return Some(Err(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
let record_size = BigEndian::read_u32(data) as usize;
|
||||||
|
if record_size == !0 /* all ones; erased flash */ {
|
||||||
|
return None
|
||||||
|
} else if record_size < 4 || record_size > data.len() {
|
||||||
|
error!("offset {}: invalid record size {}", self.offset, record_size);
|
||||||
|
return Some(Err(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
let record_body = &data[4..record_size];
|
||||||
|
match record_body.iter().position(|&x| x == 0) {
|
||||||
|
None => {
|
||||||
|
error!("offset {}: missing separator", self.offset);
|
||||||
|
Some(Err(()))
|
||||||
|
}
|
||||||
|
Some(pos) => {
|
||||||
|
self.offset += record_size;
|
||||||
|
|
||||||
|
let (key, zero_and_value) = record_body.split_at(pos);
|
||||||
|
Some(Ok((key, &zero_and_value[1..])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<F: FnOnce(Result<&[u8], ()>) -> R, R>(key: &str, f: F) -> R {
|
||||||
|
f(Lock::take().and_then(|lock| {
|
||||||
|
let mut iter = Iter::new(lock.data());
|
||||||
|
let mut value = &[][..];
|
||||||
|
while let Some(result) = iter.next() {
|
||||||
|
let (record_key, record_value) = result?;
|
||||||
|
if key.as_bytes() == record_key {
|
||||||
|
// last write wins
|
||||||
|
value = record_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(value)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_str<F: FnOnce(Result<&str, ()>) -> R, R>(key: &str, f: F) -> R {
|
||||||
|
read(key, |result| {
|
||||||
|
f(result.and_then(|value| str::from_utf8(value).map_err(|_| ())))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn append_at<'a>(mut data: &'a [u8], key: &[u8], value: &[u8]) -> Result<&'a [u8], ()> {
|
||||||
|
let record_size = 4 + key.len() + 1 + value.len();
|
||||||
|
if data.len() < record_size {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut record_size_bytes = [0u8; 4];
|
||||||
|
BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32);
|
||||||
|
|
||||||
|
spiflash::write(data.as_ptr() as usize, &record_size_bytes[..]);
|
||||||
|
data = &data[record_size_bytes.len()..];
|
||||||
|
|
||||||
|
spiflash::write(data.as_ptr() as usize, key);
|
||||||
|
data = &data[key.len()..];
|
||||||
|
|
||||||
|
spiflash::write(data.as_ptr() as usize, &[0]);
|
||||||
|
data = &data[1..];
|
||||||
|
|
||||||
|
spiflash::write(data.as_ptr() as usize, value);
|
||||||
|
data = &data[value.len()..];
|
||||||
|
|
||||||
|
cache::flush_l2_cache();
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compact() -> Result<(), ()> {
|
||||||
|
let lock = Lock::take()?;
|
||||||
|
|
||||||
|
static mut OLD_DATA: [u8; SIZE] = [0; SIZE];
|
||||||
|
let old_data = unsafe {
|
||||||
|
OLD_DATA.copy_from_slice(lock.data());
|
||||||
|
&OLD_DATA[..]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut data = lock.data();
|
||||||
|
unsafe { spiflash::erase_sector(data.as_ptr() as usize) };
|
||||||
|
|
||||||
|
// This is worst-case quadratic, but we're limited by a small SPI flash sector size,
|
||||||
|
// so it does not really matter.
|
||||||
|
let mut iter = Iter::new(old_data);
|
||||||
|
while let Some(result) = iter.next() {
|
||||||
|
let (key, mut value) = result?;
|
||||||
|
|
||||||
|
let mut next_iter = iter.clone();
|
||||||
|
while let Some(next_result) = next_iter.next() {
|
||||||
|
let (next_key, next_value) = next_result?;
|
||||||
|
if key == next_key {
|
||||||
|
value = next_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data = unsafe { append_at(data, key, value)? };
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append(key: &str, value: &[u8]) -> Result<(), ()> {
|
||||||
|
let lock = Lock::take()?;
|
||||||
|
|
||||||
|
let free = {
|
||||||
|
let mut iter = Iter::new(lock.data());
|
||||||
|
while let Some(result) = iter.next() {
|
||||||
|
let _ = result?;
|
||||||
|
}
|
||||||
|
&iter.data[iter.offset..]
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe { append_at(free, key.as_bytes(), value)? };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(key: &str, value: &[u8]) -> Result<(), ()> {
|
||||||
|
match append(key, value) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(()) => {
|
||||||
|
compact()?;
|
||||||
|
append(key, value)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(key: &str) -> Result<(), ()> {
|
||||||
|
write(key, &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn erase() -> Result<(), ()> {
|
||||||
|
let lock = Lock::take()?;
|
||||||
|
|
||||||
|
unsafe { spiflash::erase_sector(lock.data().as_ptr() as usize) };
|
||||||
|
cache::flush_l2_cache();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(has_spiflash))]
|
||||||
|
mod imp {
|
||||||
|
pub fn read<F: FnOnce(Result<&[u8], ()>) -> R, R>(_key: &str, f: F) -> R {
|
||||||
|
f(Err(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_str<F: FnOnce(Result<&str, ()>) -> R, R>(_key: &str, f: F) -> R {
|
||||||
|
f(Err(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(_key: &str, _value: &[u8]) -> Result<(), ()> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(_key: &str) -> Result<(), ()> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn erase() -> Result<(), ()> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::imp::*;
|
|
@ -1,6 +1,7 @@
|
||||||
#![feature(asm, lang_items)]
|
#![feature(asm, lang_items)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ pub mod uart_console;
|
||||||
|
|
||||||
#[cfg(has_spiflash)]
|
#[cfg(has_spiflash)]
|
||||||
pub mod spiflash;
|
pub mod spiflash;
|
||||||
|
pub mod config;
|
||||||
|
|
||||||
pub mod i2c;
|
pub mod i2c;
|
||||||
pub mod spi;
|
pub mod spi;
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use csr;
|
use csr;
|
||||||
|
|
||||||
|
pub const SECTOR_SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize;
|
||||||
|
pub const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize;
|
||||||
|
|
||||||
|
const PAGE_MASK: usize = PAGE_SIZE - 1;
|
||||||
|
|
||||||
const CMD_PP: u8 = 0x02;
|
const CMD_PP: u8 = 0x02;
|
||||||
const CMD_WRDI: u8 = 0x04;
|
const CMD_WRDI: u8 = 0x04;
|
||||||
const CMD_RDSR: u8 = 0x05;
|
const CMD_RDSR: u8 = 0x05;
|
||||||
|
@ -15,8 +20,7 @@ const PIN_DQ_I: u8 = 1 << 3;
|
||||||
|
|
||||||
const SR_WIP: u8 = 1;
|
const SR_WIP: u8 = 1;
|
||||||
|
|
||||||
fn write_byte(mut byte: u8) {
|
unsafe fn write_byte(mut byte: u8) {
|
||||||
unsafe {
|
|
||||||
csr::spiflash::bitbang_write(0);
|
csr::spiflash::bitbang_write(0);
|
||||||
for _ in 0..8 {
|
for _ in 0..8 {
|
||||||
csr::spiflash::bitbang_write((byte & 0x80) >> 7);
|
csr::spiflash::bitbang_write((byte & 0x80) >> 7);
|
||||||
|
@ -25,10 +29,8 @@ fn write_byte(mut byte: u8) {
|
||||||
}
|
}
|
||||||
csr::spiflash::bitbang_write(0);
|
csr::spiflash::bitbang_write(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn write_addr(mut addr: usize) {
|
unsafe fn write_addr(mut addr: usize) {
|
||||||
unsafe {
|
|
||||||
csr::spiflash::bitbang_write(0);
|
csr::spiflash::bitbang_write(0);
|
||||||
for _ in 0..24 {
|
for _ in 0..24 {
|
||||||
csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8);
|
csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8);
|
||||||
|
@ -37,7 +39,6 @@ fn write_addr(mut addr: usize) {
|
||||||
}
|
}
|
||||||
csr::spiflash::bitbang_write(0);
|
csr::spiflash::bitbang_write(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn wait_until_ready() {
|
fn wait_until_ready() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -59,8 +60,7 @@ fn wait_until_ready() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_sector(addr: usize) {
|
pub unsafe fn erase_sector(addr: usize) {
|
||||||
unsafe {
|
|
||||||
let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1);
|
let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1);
|
||||||
|
|
||||||
csr::spiflash::bitbang_en_write(1);
|
csr::spiflash::bitbang_en_write(1);
|
||||||
|
@ -78,10 +78,8 @@ pub fn erase_sector(addr: usize) {
|
||||||
|
|
||||||
csr::spiflash::bitbang_en_write(0);
|
csr::spiflash::bitbang_en_write(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn write_page(addr: usize, data: &[u8]) {
|
unsafe fn write_page(addr: usize, data: &[u8]) {
|
||||||
unsafe {
|
|
||||||
csr::spiflash::bitbang_en_write(1);
|
csr::spiflash::bitbang_en_write(1);
|
||||||
|
|
||||||
wait_until_ready();
|
wait_until_ready();
|
||||||
|
@ -101,12 +99,8 @@ fn write_page(addr: usize, data: &[u8]) {
|
||||||
|
|
||||||
csr::spiflash::bitbang_en_write(0);
|
csr::spiflash::bitbang_en_write(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize;
|
pub unsafe fn write(mut addr: usize, mut data: &[u8]) {
|
||||||
const PAGE_MASK: usize = PAGE_SIZE - 1;
|
|
||||||
|
|
||||||
pub fn write(mut addr: usize, mut data: &[u8]) {
|
|
||||||
if addr & PAGE_MASK != 0 {
|
if addr & PAGE_MASK != 0 {
|
||||||
let size = cmp::min((PAGE_SIZE - (addr & PAGE_MASK)) as usize, data.len());
|
let size = cmp::min((PAGE_SIZE - (addr & PAGE_MASK)) as usize, data.len());
|
||||||
write_page(addr, &data[..size]);
|
write_page(addr, &data[..size]);
|
||||||
|
|
|
@ -19,6 +19,7 @@ log = { version = "0.3", default-features = false }
|
||||||
alloc_list = { path = "../liballoc_list" }
|
alloc_list = { path = "../liballoc_list" }
|
||||||
std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] }
|
std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] }
|
||||||
logger_artiq = { path = "../liblogger_artiq" }
|
logger_artiq = { path = "../liblogger_artiq" }
|
||||||
|
backtrace_artiq = { path = "../libbacktrace_artiq" }
|
||||||
board = { path = "../libboard", features = ["uart_console"] }
|
board = { path = "../libboard", features = ["uart_console"] }
|
||||||
proto = { path = "../libproto", features = ["log"] }
|
proto = { path = "../libproto", features = ["log"] }
|
||||||
amp = { path = "../libamp" }
|
amp = { path = "../libamp" }
|
||||||
|
@ -37,6 +38,6 @@ features = ["alloc"]
|
||||||
|
|
||||||
[dependencies.smoltcp]
|
[dependencies.smoltcp]
|
||||||
git = "https://github.com/m-labs/smoltcp"
|
git = "https://github.com/m-labs/smoltcp"
|
||||||
rev = "6f5ae33"
|
rev = "181083f"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["alloc", "log"]
|
features = ["alloc", "log", "proto-ipv4", "socket-tcp"]
|
||||||
|
|
|
@ -1,32 +1,30 @@
|
||||||
include ../include/generated/variables.mak
|
include ../include/generated/variables.mak
|
||||||
include $(MISOC_DIRECTORY)/software/common.mak
|
include $(MISOC_DIRECTORY)/software/common.mak
|
||||||
|
|
||||||
LDFLAGS += -L../libbase
|
CFLAGS += \
|
||||||
|
-I$(LIBUNWIND_DIRECTORY) \
|
||||||
|
-I$(LIBUNWIND_DIRECTORY)/../unwinder/include
|
||||||
|
|
||||||
RUSTFLAGS += -Cpanic=abort
|
LDFLAGS += -L../libbase \
|
||||||
|
-L../libunwind
|
||||||
|
|
||||||
all: runtime.bin runtime.fbi
|
RUSTFLAGS += -Cpanic=unwind
|
||||||
|
|
||||||
|
all:: runtime.bin runtime.fbi
|
||||||
|
|
||||||
.PHONY: $(RUSTOUT)/libruntime.a
|
.PHONY: $(RUSTOUT)/libruntime.a
|
||||||
$(RUSTOUT)/libruntime.a:
|
$(RUSTOUT)/libruntime.a:
|
||||||
$(cargo) --manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml
|
$(cargo) --manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml
|
||||||
|
|
||||||
runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o
|
runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o
|
||||||
$(LD) $(LDFLAGS) -T $(RUNTIME_DIRECTORY)/runtime.ld -o $@ $^
|
$(link) -T $(RUNTIME_DIRECTORY)/runtime.ld \
|
||||||
@chmod -x $@
|
-lunwind-bare
|
||||||
|
|
||||||
ksupport_data.o: ../ksupport/ksupport.elf
|
ksupport_data.o: ../ksupport/ksupport.elf
|
||||||
$(LD) -r -b binary -o $@ $<
|
$(LD) -r -b binary -o $@ $<
|
||||||
|
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
$(OBJCOPY) -O binary $< $@
|
$(objcopy) -O binary
|
||||||
@chmod -x $@
|
|
||||||
|
|
||||||
%.fbi: %.bin
|
%.fbi: %.bin
|
||||||
@echo " MSCIMG " $@ && $(PYTHON) -m misoc.tools.mkmscimg -f -o $@ $<
|
$(mscimg) -f
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) *.o runtime.elf runtime.bin runtime.fbi
|
|
||||||
$(RM) -rf cargo
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
|
|
|
@ -1,192 +0,0 @@
|
||||||
use core::str;
|
|
||||||
use std::btree_map::BTreeMap;
|
|
||||||
use byteorder::{ByteOrder, BigEndian};
|
|
||||||
use board::{mem, csr, cache, spiflash};
|
|
||||||
|
|
||||||
const ADDR: usize = mem::FLASH_BOOT_ADDRESS + 0x80000 /* max runtime size */;
|
|
||||||
const SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize;
|
|
||||||
|
|
||||||
mod lock {
|
|
||||||
use core::slice;
|
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
|
|
||||||
static LOCKED: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|
||||||
pub struct Lock;
|
|
||||||
|
|
||||||
impl Lock {
|
|
||||||
pub fn take() -> Result<Lock, ()> {
|
|
||||||
if LOCKED.swap(1, Ordering::SeqCst) != 0 {
|
|
||||||
Err(()) // already locked
|
|
||||||
} else {
|
|
||||||
Ok(Lock) // locked now
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data(&self) -> &'static [u8] {
|
|
||||||
unsafe { slice::from_raw_parts(super::ADDR as *const u8, super::SIZE) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Lock {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
LOCKED.store(0, Ordering::SeqCst)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::lock::Lock;
|
|
||||||
|
|
||||||
struct Iter<'a> {
|
|
||||||
data: &'a [u8],
|
|
||||||
offset: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iter<'a> {
|
|
||||||
fn new(data: &'a [u8]) -> Iter<'a> {
|
|
||||||
Iter { data: data, offset: 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for Iter<'a> {
|
|
||||||
type Item = Result<(&'a [u8], &'a [u8]), ()>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
let data = &self.data[self.offset..];
|
|
||||||
|
|
||||||
if data.len() < 4 {
|
|
||||||
error!("offset {}: truncated record", self.offset);
|
|
||||||
return Some(Err(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
let record_size = BigEndian::read_u32(data) as usize;
|
|
||||||
if record_size < 4 {
|
|
||||||
error!("offset {}: invalid record size", self.offset);
|
|
||||||
return Some(Err(()))
|
|
||||||
}
|
|
||||||
if record_size == !0 /* all ones; erased flash */ {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
let record_body = &data[4..record_size];
|
|
||||||
match record_body.iter().position(|&x| x == 0) {
|
|
||||||
None => {
|
|
||||||
error!("offset {}: missing separator", self.offset);
|
|
||||||
Some(Err(()))
|
|
||||||
}
|
|
||||||
Some(pos) => {
|
|
||||||
self.offset += record_size;
|
|
||||||
|
|
||||||
let (key, zero_and_value) = record_body.split_at(pos);
|
|
||||||
Some(Ok((key, &zero_and_value[1..])))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read<F: FnOnce(Result<&[u8], ()>) -> R, R>(key: &str, f: F) -> R {
|
|
||||||
f(Lock::take().and_then(|lock| {
|
|
||||||
let mut iter = Iter::new(lock.data());
|
|
||||||
let mut value = &[][..];
|
|
||||||
while let Some(result) = iter.next() {
|
|
||||||
let (record_key, record_value) = result?;
|
|
||||||
if key.as_bytes() == record_key {
|
|
||||||
// last write wins
|
|
||||||
value = record_value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(value)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_str<F: FnOnce(Result<&str, ()>) -> R, R>(key: &str, f: F) -> R {
|
|
||||||
read(key, |result| {
|
|
||||||
f(result.and_then(|value| str::from_utf8(value).map_err(|_| ())))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append_at(mut offset: usize, key: &[u8], value: &[u8]) -> Result<usize, ()> {
|
|
||||||
let record_size = 4 + key.len() + 1 + value.len();
|
|
||||||
if offset + record_size > SIZE {
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut record_size_bytes = [0u8; 4];
|
|
||||||
BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32);
|
|
||||||
|
|
||||||
spiflash::write(ADDR + offset, &record_size_bytes[..]);
|
|
||||||
offset += record_size_bytes.len();
|
|
||||||
|
|
||||||
spiflash::write(ADDR + offset, key);
|
|
||||||
offset += key.len();
|
|
||||||
|
|
||||||
spiflash::write(ADDR + offset, &[0]);
|
|
||||||
offset += 1;
|
|
||||||
|
|
||||||
spiflash::write(ADDR + offset, value);
|
|
||||||
offset += value.len();
|
|
||||||
|
|
||||||
cache::flush_l2_cache();
|
|
||||||
Ok(offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compact() -> Result<(), ()> {
|
|
||||||
let lock = Lock::take()?;
|
|
||||||
|
|
||||||
let mut items = BTreeMap::new();
|
|
||||||
{
|
|
||||||
let mut iter = Iter::new(lock.data());
|
|
||||||
while let Some(result) = iter.next() {
|
|
||||||
let (key, value) = result?;
|
|
||||||
items.insert(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spiflash::erase_sector(ADDR);
|
|
||||||
cache::flush_l2_cache();
|
|
||||||
|
|
||||||
let mut offset = 0;
|
|
||||||
for (key, value) in items {
|
|
||||||
offset = append_at(offset, key, value)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append(key: &str, value: &[u8]) -> Result<(), ()> {
|
|
||||||
let lock = Lock::take()?;
|
|
||||||
|
|
||||||
let free_offset = {
|
|
||||||
let mut iter = Iter::new(lock.data());
|
|
||||||
while let Some(result) = iter.next() {
|
|
||||||
let _ = result?;
|
|
||||||
}
|
|
||||||
iter.offset
|
|
||||||
};
|
|
||||||
|
|
||||||
append_at(free_offset, key.as_bytes(), value)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(key: &str, value: &[u8]) -> Result<(), ()> {
|
|
||||||
match append(key, value) {
|
|
||||||
Ok(()) => (),
|
|
||||||
Err(()) => {
|
|
||||||
compact()?;
|
|
||||||
append(key, value)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(key: &str) -> Result<(), ()> {
|
|
||||||
write(key, &[])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn erase() -> Result<(), ()> {
|
|
||||||
let _lock = Lock::take()?;
|
|
||||||
|
|
||||||
spiflash::erase_sector(ADDR);
|
|
||||||
cache::flush_l2_cache();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
pub fn read<F: FnOnce(Result<&[u8], ()>) -> R, R>(_key: &str, f: F) -> R {
|
|
||||||
f(Err(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_str<F: FnOnce(Result<&str, ()>) -> R, R>(_key: &str, f: F) -> R {
|
|
||||||
f(Err(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(_key: &str, _value: &[u8]) -> Result<(), ()> {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(_key: &str) -> Result<(), ()> {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn erase() -> Result<(), ()> {
|
|
||||||
Err(())
|
|
||||||
}
|
|
|
@ -1,88 +1,158 @@
|
||||||
use core::slice;
|
use core::{slice, fmt};
|
||||||
|
use smoltcp::Result;
|
||||||
|
use smoltcp::phy::{self, DeviceCapabilities, Device};
|
||||||
|
|
||||||
use board::{csr, mem};
|
use board::{csr, mem};
|
||||||
use smoltcp::Error;
|
|
||||||
use smoltcp::phy::{DeviceLimits, Device};
|
|
||||||
|
|
||||||
const RX0_BASE: usize = mem::ETHMAC_BASE + 0x0000;
|
const RX_SLOTS: usize = csr::ETHMAC_RX_SLOTS as usize;
|
||||||
const RX1_BASE: usize = mem::ETHMAC_BASE + 0x0800;
|
const TX_SLOTS: usize = csr::ETHMAC_TX_SLOTS as usize;
|
||||||
const RX2_BASE: usize = mem::ETHMAC_BASE + 0x1000;
|
const SLOT_SIZE: usize = csr::ETHMAC_SLOT_SIZE as usize;
|
||||||
const RX3_BASE: usize = mem::ETHMAC_BASE + 0x1800;
|
|
||||||
const TX0_BASE: usize = mem::ETHMAC_BASE + 0x2000;
|
|
||||||
const TX1_BASE: usize = mem::ETHMAC_BASE + 0x2800;
|
|
||||||
const TX2_BASE: usize = mem::ETHMAC_BASE + 0x3000;
|
|
||||||
const TX3_BASE: usize = mem::ETHMAC_BASE + 0x3800;
|
|
||||||
|
|
||||||
const RX_BUFFERS: [*mut u8; 4] = [RX0_BASE as *mut u8, RX1_BASE as *mut u8,
|
fn next_rx_slot() -> Option<usize> {
|
||||||
RX2_BASE as *mut u8, RX3_BASE as *mut u8];
|
|
||||||
const TX_BUFFERS: [*mut u8; 4] = [TX0_BASE as *mut u8, TX1_BASE as *mut u8,
|
|
||||||
TX2_BASE as *mut u8, TX3_BASE as *mut u8];
|
|
||||||
|
|
||||||
pub struct EthernetDevice;
|
|
||||||
|
|
||||||
impl Device for EthernetDevice {
|
|
||||||
type RxBuffer = RxBuffer;
|
|
||||||
type TxBuffer = TxBuffer;
|
|
||||||
|
|
||||||
fn limits(&self) -> DeviceLimits {
|
|
||||||
let mut limits = DeviceLimits::default();
|
|
||||||
limits.max_transmission_unit = 1514;
|
|
||||||
limits.max_burst_size = Some(RX_BUFFERS.len());
|
|
||||||
limits
|
|
||||||
}
|
|
||||||
|
|
||||||
fn receive(&mut self, _timestamp: u64) -> Result<Self::RxBuffer, Error> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if csr::ethmac::sram_writer_ev_pending_read() != 0 {
|
if csr::ethmac::sram_writer_ev_pending_read() == 0 {
|
||||||
let slot = csr::ethmac::sram_writer_slot_read();
|
None
|
||||||
let length = csr::ethmac::sram_writer_length_read();
|
|
||||||
Ok(RxBuffer(slice::from_raw_parts(RX_BUFFERS[slot as usize],
|
|
||||||
length as usize)))
|
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Exhausted)
|
Some(csr::ethmac::sram_writer_slot_read() as usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transmit(&mut self, _timestamp: u64, length: usize) -> Result<Self::TxBuffer, Error> {
|
fn next_tx_slot() -> Option<usize> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if csr::ethmac::sram_reader_ready_read() != 0 {
|
if csr::ethmac::sram_reader_ready_read() == 0 {
|
||||||
let slot = csr::ethmac::sram_reader_slot_read();
|
None
|
||||||
let slot = (slot + 1) % (TX_BUFFERS.len() as u8);
|
} else {
|
||||||
csr::ethmac::sram_reader_slot_write(slot);
|
Some((csr::ethmac::sram_reader_slot_read() as usize + 1) % TX_SLOTS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rx_buffer(slot: usize) -> *const u8 {
|
||||||
|
debug_assert!(slot < RX_SLOTS);
|
||||||
|
(mem::ETHMAC_BASE + SLOT_SIZE * slot) as _
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tx_buffer(slot: usize) -> *mut u8 {
|
||||||
|
debug_assert!(slot < TX_SLOTS);
|
||||||
|
(mem::ETHMAC_BASE + SLOT_SIZE * (RX_SLOTS + slot)) as _
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EthernetDevice(());
|
||||||
|
|
||||||
|
impl EthernetDevice {
|
||||||
|
pub unsafe fn new() -> EthernetDevice {
|
||||||
|
EthernetDevice(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Device<'a> for EthernetDevice {
|
||||||
|
type RxToken = EthernetRxSlot;
|
||||||
|
type TxToken = EthernetTxSlot;
|
||||||
|
|
||||||
|
fn capabilities(&self) -> DeviceCapabilities {
|
||||||
|
let mut caps = DeviceCapabilities::default();
|
||||||
|
caps.max_transmission_unit = 1514;
|
||||||
|
caps.max_burst_size = Some(RX_SLOTS);
|
||||||
|
caps
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||||
|
if let (Some(rx_slot), Some(tx_slot)) = (next_rx_slot(), next_tx_slot()) {
|
||||||
|
Some((EthernetRxSlot(rx_slot), EthernetTxSlot(tx_slot)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmit(&mut self) -> Option<Self::TxToken> {
|
||||||
|
if let Some(tx_slot) = next_tx_slot() {
|
||||||
|
Some(EthernetTxSlot(tx_slot))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EthernetRxSlot(usize);
|
||||||
|
|
||||||
|
impl phy::RxToken for EthernetRxSlot {
|
||||||
|
fn consume<R, F>(self, _timestamp: u64, f: F) -> Result<R>
|
||||||
|
where F: FnOnce(&[u8]) -> Result<R>
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let length = csr::ethmac::sram_writer_length_read() as usize;
|
||||||
|
let result = f(slice::from_raw_parts(rx_buffer(self.0), length));
|
||||||
|
csr::ethmac::sram_writer_ev_pending_write(1);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EthernetTxSlot(usize);
|
||||||
|
|
||||||
|
impl phy::TxToken for EthernetTxSlot {
|
||||||
|
fn consume<R, F>(self, _timestamp: u64, length: usize, f: F) -> Result<R>
|
||||||
|
where F: FnOnce(&mut [u8]) -> Result<R>
|
||||||
|
{
|
||||||
|
debug_assert!(length < SLOT_SIZE);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let result = f(slice::from_raw_parts_mut(tx_buffer(self.0), length))?;
|
||||||
|
csr::ethmac::sram_reader_slot_write(self.0 as u8);
|
||||||
csr::ethmac::sram_reader_length_write(length as u16);
|
csr::ethmac::sram_reader_length_write(length as u16);
|
||||||
Ok(TxBuffer(slice::from_raw_parts_mut(TX_BUFFERS[slot as usize],
|
csr::ethmac::sram_reader_start_write(1);
|
||||||
length as usize)))
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
|
pub struct EthernetStatistics {
|
||||||
|
rx_preamble_errors: u32,
|
||||||
|
rx_crc_errors: u32,
|
||||||
|
rx_dropped: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EthernetStatistics {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
EthernetStatistics {
|
||||||
|
rx_preamble_errors: csr::ethmac::preamble_errors_read(),
|
||||||
|
rx_crc_errors: csr::ethmac::crc_errors_read(),
|
||||||
|
rx_dropped: csr::ethmac::sram_writer_errors_read(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self) -> Option<Self> {
|
||||||
|
let old = self.clone();
|
||||||
|
*self = Self::new();
|
||||||
|
|
||||||
|
let diff = EthernetStatistics {
|
||||||
|
rx_preamble_errors: self.rx_preamble_errors.wrapping_sub(old.rx_preamble_errors),
|
||||||
|
rx_crc_errors: self.rx_crc_errors.wrapping_sub(old.rx_crc_errors),
|
||||||
|
rx_dropped: self.rx_dropped.wrapping_sub(old.rx_dropped),
|
||||||
|
};
|
||||||
|
if diff == EthernetStatistics::default() {
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Exhausted)
|
Some(diff)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RxBuffer(&'static [u8]);
|
impl fmt::Display for EthernetStatistics {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
impl AsRef<[u8]> for RxBuffer {
|
if self.rx_preamble_errors > 0 {
|
||||||
fn as_ref(&self) -> &[u8] { self.0 }
|
write!(f, " rx preamble errors: {}", self.rx_preamble_errors)?
|
||||||
}
|
}
|
||||||
|
if self.rx_crc_errors > 0 {
|
||||||
impl Drop for RxBuffer {
|
write!(f, " rx crc errors: {}", self.rx_crc_errors)?
|
||||||
fn drop(&mut self) {
|
}
|
||||||
unsafe { csr::ethmac::sram_writer_ev_pending_write(1) }
|
if self.rx_dropped > 0 {
|
||||||
}
|
write!(f, " rx dropped: {}", self.rx_dropped)?
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
pub struct TxBuffer(&'static mut [u8]);
|
|
||||||
|
|
||||||
impl AsRef<[u8]> for TxBuffer {
|
|
||||||
fn as_ref(&self) -> &[u8] { self.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsMut<[u8]> for TxBuffer {
|
|
||||||
fn as_mut(&mut self) -> &mut [u8] { self.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for TxBuffer {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe { csr::ethmac::sram_reader_start_write(1) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ extern crate alloc_list;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std_artiq as std;
|
extern crate std_artiq as std;
|
||||||
extern crate logger_artiq;
|
extern crate logger_artiq;
|
||||||
|
extern crate backtrace_artiq;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate board;
|
extern crate board;
|
||||||
extern crate proto;
|
extern crate proto;
|
||||||
|
@ -21,24 +22,12 @@ extern crate amp;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
extern crate drtioaux;
|
extern crate drtioaux;
|
||||||
|
|
||||||
use std::boxed::Box;
|
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
||||||
use smoltcp::wire::{EthernetAddress, IpAddress};
|
|
||||||
|
use board::config;
|
||||||
use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto};
|
use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto};
|
||||||
use amp::{mailbox, rpc_queue};
|
use amp::{mailbox, rpc_queue};
|
||||||
|
|
||||||
macro_rules! borrow_mut {
|
|
||||||
($x:expr) => ({
|
|
||||||
match $x.try_borrow_mut() {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(_) => panic!("cannot borrow mutably at {}:{}", file!(), line!())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_spiflash)]
|
|
||||||
mod config;
|
|
||||||
#[cfg(not(has_spiflash))]
|
|
||||||
#[path="config_dummy.rs"] mod config;
|
|
||||||
mod ethmac;
|
mod ethmac;
|
||||||
mod rtio_mgt;
|
mod rtio_mgt;
|
||||||
|
|
||||||
|
@ -95,7 +84,7 @@ fn startup() {
|
||||||
|
|
||||||
let protocol_addr;
|
let protocol_addr;
|
||||||
match config::read_str("ip", |r| r?.parse()) {
|
match config::read_str("ip", |r| r?.parse()) {
|
||||||
Err(()) | Ok(IpAddress::Unspecified) => {
|
Err(()) => {
|
||||||
protocol_addr = IpAddress::v4(192, 168, 1, 50);
|
protocol_addr = IpAddress::v4(192, 168, 1, 50);
|
||||||
info!("using default IP address {}", protocol_addr);
|
info!("using default IP address {}", protocol_addr);
|
||||||
}
|
}
|
||||||
|
@ -109,15 +98,20 @@ fn startup() {
|
||||||
// where U: smoltcp::wire::pretty_print::PrettyPrint {
|
// where U: smoltcp::wire::pretty_print::PrettyPrint {
|
||||||
// let seconds = timestamp / 1000;
|
// let seconds = timestamp / 1000;
|
||||||
// let micros = timestamp % 1000 * 1000;
|
// let micros = timestamp % 1000 * 1000;
|
||||||
// print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m", seconds, micros, printer)
|
// print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m\n", seconds, micros, printer)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let net_device = ethmac::EthernetDevice;
|
let net_device = unsafe { ethmac::EthernetDevice::new() };
|
||||||
// let net_device = smoltcp::phy::EthernetTracer::new(net_device, _net_trace_writer);
|
// let net_device = smoltcp::phy::EthernetTracer::new(net_device, _net_trace_writer);
|
||||||
let arp_cache = smoltcp::iface::SliceArpCache::new([Default::default(); 8]);
|
let mut neighbor_cache_storage = [None; 8];
|
||||||
let mut interface = smoltcp::iface::EthernetInterface::new(
|
let neighbor_cache =
|
||||||
Box::new(net_device), Box::new(arp_cache) as Box<smoltcp::iface::ArpCache>,
|
smoltcp::iface::NeighborCache::new(&mut neighbor_cache_storage[..]);
|
||||||
hardware_addr, [protocol_addr]);
|
let mut interface =
|
||||||
|
smoltcp::iface::EthernetInterfaceBuilder::new(net_device)
|
||||||
|
.neighbor_cache(neighbor_cache)
|
||||||
|
.ethernet_addr(hardware_addr)
|
||||||
|
.ip_addrs([IpCidr::new(protocol_addr, 0)])
|
||||||
|
.finalize();
|
||||||
|
|
||||||
let mut scheduler = sched::Scheduler::new();
|
let mut scheduler = sched::Scheduler::new();
|
||||||
let io = scheduler.io();
|
let io = scheduler.io();
|
||||||
|
@ -154,14 +148,19 @@ fn startup() {
|
||||||
loop {
|
loop {
|
||||||
scheduler.run();
|
scheduler.run();
|
||||||
|
|
||||||
match interface.poll(&mut *borrow_mut!(scheduler.sockets()),
|
{
|
||||||
board::clock::get_ms()) {
|
let sockets = &mut *scheduler.sockets().borrow_mut();
|
||||||
Ok(_poll_at) => (),
|
loop {
|
||||||
|
match interface.poll(sockets, board::clock::get_ms()) {
|
||||||
|
Ok(true) => (),
|
||||||
|
Ok(false) => break,
|
||||||
Err(smoltcp::Error::Unrecognized) => (),
|
Err(smoltcp::Error::Unrecognized) => (),
|
||||||
Err(err) => warn!("network error: {}", err)
|
Err(err) => warn!("network error: {}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static mut ALLOC: alloc_list::ListAlloc = alloc_list::EMPTY;
|
static mut ALLOC: alloc_list::ListAlloc = alloc_list::EMPTY;
|
||||||
|
@ -189,7 +188,9 @@ pub extern fn exception_handler(vect: u32, _regs: *const u32, pc: u32, ea: u32)
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn abort() {
|
pub extern fn abort() {
|
||||||
panic!("aborted")
|
println!("aborted");
|
||||||
|
|
||||||
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -197,6 +198,12 @@ pub extern fn abort() {
|
||||||
pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
pub 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);
|
||||||
|
|
||||||
|
println!("backtrace for software version {}:",
|
||||||
|
include_str!(concat!(env!("OUT_DIR"), "/git-describe")));
|
||||||
|
let _ = backtrace_artiq::backtrace(|ip| {
|
||||||
|
println!("{:#08x}", ip);
|
||||||
|
});
|
||||||
|
|
||||||
if config::read_str("panic_reboot", |r| r == Ok("1")) {
|
if config::read_str("panic_reboot", |r| r == Ok("1")) {
|
||||||
println!("rebooting...");
|
println!("rebooting...");
|
||||||
unsafe { board::boot::reboot() }
|
unsafe { board::boot::reboot() }
|
||||||
|
@ -206,11 +213,3 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 fn _Unwind_Resume() -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use config;
|
use board::{csr, config};
|
||||||
use board::csr;
|
|
||||||
use sched::Io;
|
use sched::Io;
|
||||||
|
|
||||||
#[cfg(has_rtio_crg)]
|
#[cfg(has_rtio_crg)]
|
||||||
|
@ -219,16 +218,25 @@ pub fn startup(io: &Io) {
|
||||||
|
|
||||||
let clk = config::read("startup_clock", |result| {
|
let clk = config::read("startup_clock", |result| {
|
||||||
match result {
|
match result {
|
||||||
Ok(b"i") => RtioClock::Internal,
|
Ok(b"i") => {
|
||||||
Ok(b"e") => RtioClock::External,
|
info!("using internal startup RTIO clock");
|
||||||
_ => {
|
RtioClock::Internal
|
||||||
error!("unrecognized startup_clock configuration entry");
|
},
|
||||||
|
Ok(b"e") => {
|
||||||
|
info!("using external startup RTIO clock");
|
||||||
|
RtioClock::External
|
||||||
|
},
|
||||||
|
Err(()) => {
|
||||||
|
info!("using internal startup RTIO clock (by default)");
|
||||||
|
RtioClock::Internal
|
||||||
|
},
|
||||||
|
Ok(_) => {
|
||||||
|
error!("unrecognized startup_clock configuration entry, using internal RTIO clock");
|
||||||
RtioClock::Internal
|
RtioClock::Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("startup RTIO clock: {:?}", clk);
|
|
||||||
if !crg::switch_clock(clk as u8) {
|
if !crg::switch_clock(clk as u8) {
|
||||||
error!("startup RTIO clock failed");
|
error!("startup RTIO clock failed");
|
||||||
warn!("this may cause the system initialization to fail");
|
warn!("this may cause the system initialization to fail");
|
||||||
|
|
|
@ -20,6 +20,21 @@ SECTIONS
|
||||||
_etext = .;
|
_etext = .;
|
||||||
} > runtime
|
} > runtime
|
||||||
|
|
||||||
|
.eh_frame :
|
||||||
|
{
|
||||||
|
__eh_frame_start = .;
|
||||||
|
KEEP(*(.eh_frame))
|
||||||
|
__eh_frame_end = .;
|
||||||
|
} > runtime
|
||||||
|
|
||||||
|
.eh_frame_hdr :
|
||||||
|
{
|
||||||
|
KEEP(*(.eh_frame_hdr))
|
||||||
|
} > runtime
|
||||||
|
|
||||||
|
__eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
|
||||||
|
__eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
|
||||||
|
|
||||||
/* https://sourceware.org/bugzilla/show_bug.cgi?id=20475 */
|
/* https://sourceware.org/bugzilla/show_bug.cgi?id=20475 */
|
||||||
.got :
|
.got :
|
||||||
{
|
{
|
||||||
|
@ -79,10 +94,4 @@ SECTIONS
|
||||||
. = ORIGIN(runtime) + LENGTH(runtime);
|
. = ORIGIN(runtime) + LENGTH(runtime);
|
||||||
_eheap = .;
|
_eheap = .;
|
||||||
} > runtime
|
} > runtime
|
||||||
|
|
||||||
/DISCARD/ :
|
|
||||||
{
|
|
||||||
*(.eh_frame)
|
|
||||||
*(.gcc_except_table)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::cell::{Cell, RefCell, RefMut};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use std::io::{Read, Write, Result, Error, ErrorKind};
|
use std::io::{Read, Write, Result, Error, ErrorKind};
|
||||||
use fringe::OwnedStack;
|
use fringe::OwnedStack;
|
||||||
use fringe::generator::{Generator, Yielder, State as GeneratorState};
|
use fringe::generator::{Generator, Yielder, State as GeneratorState};
|
||||||
|
|
||||||
use smoltcp::wire::IpEndpoint;
|
use smoltcp::wire::IpEndpoint;
|
||||||
use smoltcp::socket::{AsSocket, SocketHandle};
|
use smoltcp::socket::{SocketHandle, SocketRef};
|
||||||
type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>;
|
|
||||||
|
|
||||||
use board;
|
use board;
|
||||||
use urc::Urc;
|
use urc::Urc;
|
||||||
|
|
||||||
|
type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct WaitRequest {
|
struct WaitRequest {
|
||||||
event: Option<*const (Fn() -> bool + 'static)>,
|
event: Option<*const (Fn() -> bool + 'static)>,
|
||||||
|
@ -123,7 +124,7 @@ impl Scheduler {
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
self.sockets.borrow_mut().prune();
|
self.sockets.borrow_mut().prune();
|
||||||
|
|
||||||
self.threads.append(&mut *borrow_mut!(self.spawned));
|
self.threads.append(&mut *self.spawned.borrow_mut());
|
||||||
if self.threads.len() == 0 { return }
|
if self.threads.len() == 0 { return }
|
||||||
|
|
||||||
let now = board::clock::get_ms();
|
let now = board::clock::get_ms();
|
||||||
|
@ -132,7 +133,7 @@ impl Scheduler {
|
||||||
self.run_idx = (self.run_idx + 1) % self.threads.len();
|
self.run_idx = (self.run_idx + 1) % self.threads.len();
|
||||||
|
|
||||||
let result = {
|
let result = {
|
||||||
let mut thread = borrow_mut!(self.threads[self.run_idx].0);
|
let mut thread = self.threads[self.run_idx].0.borrow_mut();
|
||||||
match thread.waiting_for {
|
match thread.waiting_for {
|
||||||
_ if thread.interrupted => {
|
_ if thread.interrupted => {
|
||||||
thread.interrupted = false;
|
thread.interrupted = false;
|
||||||
|
@ -163,7 +164,7 @@ impl Scheduler {
|
||||||
},
|
},
|
||||||
Some(wait_request) => {
|
Some(wait_request) => {
|
||||||
// The thread has suspended itself.
|
// The thread has suspended itself.
|
||||||
let mut thread = borrow_mut!(self.threads[self.run_idx].0);
|
let mut thread = self.threads[self.run_idx].0.borrow_mut();
|
||||||
thread.waiting_for = wait_request
|
thread.waiting_for = wait_request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,7 +189,7 @@ impl<'a> Io<'a> {
|
||||||
pub fn spawn<F>(&self, stack_size: usize, f: F) -> ThreadHandle
|
pub fn spawn<F>(&self, stack_size: usize, f: F) -> ThreadHandle
|
||||||
where F: 'static + FnOnce(Io) + Send {
|
where F: 'static + FnOnce(Io) + Send {
|
||||||
let handle = unsafe { Thread::new(self, stack_size, f) };
|
let handle = unsafe { Thread::new(self, stack_size, f) };
|
||||||
borrow_mut!(self.spawned).push(handle.clone());
|
self.spawned.borrow_mut().push(handle.clone());
|
||||||
handle
|
handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,87 +241,18 @@ macro_rules! until {
|
||||||
($socket:expr, $ty:ty, |$var:ident| $cond:expr) => ({
|
($socket:expr, $ty:ty, |$var:ident| $cond:expr) => ({
|
||||||
let (sockets, handle) = ($socket.io.sockets.clone(), $socket.handle);
|
let (sockets, handle) = ($socket.io.sockets.clone(), $socket.handle);
|
||||||
$socket.io.until(move || {
|
$socket.io.until(move || {
|
||||||
let mut sockets = borrow_mut!(sockets);
|
let mut sockets = sockets.borrow_mut();
|
||||||
let $var: &mut $ty = sockets.get_mut(handle).as_socket();
|
let $var = sockets.get::<$ty>(handle);
|
||||||
$cond
|
$cond
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
use ::smoltcp::Error as ErrorLower;
|
use ::smoltcp::Error as ErrorLower;
|
||||||
// https://github.com/rust-lang/rust/issues/44057
|
// https://github.com/rust-lang/rust/issues/44057
|
||||||
// type ErrorLower = ::smoltcp::Error;
|
// type ErrorLower = ::smoltcp::Error;
|
||||||
|
|
||||||
type UdpPacketBuffer = ::smoltcp::socket::UdpPacketBuffer<'static>;
|
|
||||||
type UdpSocketBuffer = ::smoltcp::socket::UdpSocketBuffer<'static, 'static>;
|
|
||||||
type UdpSocketLower = ::smoltcp::socket::UdpSocket<'static, 'static>;
|
|
||||||
|
|
||||||
pub struct UdpSocket<'a> {
|
|
||||||
io: &'a Io<'a>,
|
|
||||||
handle: SocketHandle
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> UdpSocket<'a> {
|
|
||||||
pub fn new(io: &'a Io<'a>, buffer_depth: usize, buffer_width: usize) -> UdpSocket<'a> {
|
|
||||||
let mut rx_buffer = vec![];
|
|
||||||
let mut tx_buffer = vec![];
|
|
||||||
for _ in 0..buffer_depth {
|
|
||||||
rx_buffer.push(UdpPacketBuffer::new(vec![0; buffer_width]));
|
|
||||||
tx_buffer.push(UdpPacketBuffer::new(vec![0; buffer_width]));
|
|
||||||
}
|
|
||||||
let handle = borrow_mut!(io.sockets)
|
|
||||||
.add(UdpSocketLower::new(
|
|
||||||
UdpSocketBuffer::new(rx_buffer),
|
|
||||||
UdpSocketBuffer::new(tx_buffer)));
|
|
||||||
UdpSocket {
|
|
||||||
io: io,
|
|
||||||
handle: handle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_lower<'b>(&'b self) -> RefMut<'b, UdpSocketLower> {
|
|
||||||
RefMut::map(borrow_mut!(self.io.sockets),
|
|
||||||
|sockets| sockets.get_mut(self.handle).as_socket())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bind<T: Into<IpEndpoint>>(&self, endpoint: T) -> Result<()> {
|
|
||||||
match self.as_lower().bind(endpoint) {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(ErrorLower::Illegal) =>
|
|
||||||
Err(Error::new(ErrorKind::Other, "already listening")),
|
|
||||||
Err(ErrorLower::Unaddressable) =>
|
|
||||||
Err(Error::new(ErrorKind::AddrNotAvailable, "port cannot be zero")),
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint)> {
|
|
||||||
until!(self, UdpSocketLower, |s| s.can_recv())?;
|
|
||||||
match self.as_lower().recv_slice(buf) {
|
|
||||||
Ok(result) => Ok(result),
|
|
||||||
Err(_) => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_to(&self, buf: &[u8], addr: IpEndpoint) -> Result<()> {
|
|
||||||
until!(self, UdpSocketLower, |s| s.can_send())?;
|
|
||||||
match self.as_lower().send_slice(buf, addr) {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(ErrorLower::Unaddressable) =>
|
|
||||||
Err(Error::new(ErrorKind::AddrNotAvailable, "unaddressable destination")),
|
|
||||||
Err(ErrorLower::Truncated) =>
|
|
||||||
Err(Error::new(ErrorKind::Other, "packet does not fit in buffer")),
|
|
||||||
Err(_) => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for UdpSocket<'a> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
borrow_mut!(self.io.sockets).release(self.handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TcpSocketBuffer = ::smoltcp::socket::TcpSocketBuffer<'static>;
|
type TcpSocketBuffer = ::smoltcp::socket::TcpSocketBuffer<'static>;
|
||||||
type TcpSocketLower = ::smoltcp::socket::TcpSocket<'static>;
|
type TcpSocketLower = ::smoltcp::socket::TcpSocket<'static>;
|
||||||
|
|
||||||
|
@ -337,7 +269,8 @@ impl<'a> TcpListener<'a> {
|
||||||
fn new_lower(io: &'a Io<'a>, buffer_size: usize) -> SocketHandle {
|
fn new_lower(io: &'a Io<'a>, buffer_size: usize) -> SocketHandle {
|
||||||
let rx_buffer = vec![0; buffer_size];
|
let rx_buffer = vec![0; buffer_size];
|
||||||
let tx_buffer = vec![0; buffer_size];
|
let tx_buffer = vec![0; buffer_size];
|
||||||
borrow_mut!(io.sockets)
|
io.sockets
|
||||||
|
.borrow_mut()
|
||||||
.add(TcpSocketLower::new(
|
.add(TcpSocketLower::new(
|
||||||
TcpSocketBuffer::new(rx_buffer),
|
TcpSocketBuffer::new(rx_buffer),
|
||||||
TcpSocketBuffer::new(tx_buffer)))
|
TcpSocketBuffer::new(tx_buffer)))
|
||||||
|
@ -352,35 +285,41 @@ impl<'a> TcpListener<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_lower<'b>(&'b self) -> RefMut<'b, TcpSocketLower> {
|
fn with_lower<F, R>(&self, f: F) -> R
|
||||||
RefMut::map(borrow_mut!(self.io.sockets),
|
where F: FnOnce(SocketRef<TcpSocketLower>) -> R {
|
||||||
|sockets| sockets.get_mut(self.handle.get()).as_socket())
|
let mut sockets = self.io.sockets.borrow_mut();
|
||||||
|
let result = f(sockets.get(self.handle.get()));
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_open(&self) -> bool {
|
pub fn is_open(&self) -> bool {
|
||||||
self.as_lower().is_open()
|
self.with_lower(|s| s.is_open())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_accept(&self) -> bool {
|
pub fn can_accept(&self) -> bool {
|
||||||
self.as_lower().is_active()
|
self.with_lower(|s| s.is_active())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_endpoint(&self) -> IpEndpoint {
|
pub fn local_endpoint(&self) -> IpEndpoint {
|
||||||
self.as_lower().local_endpoint()
|
self.with_lower(|s| s.local_endpoint())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen<T: Into<IpEndpoint>>(&self, endpoint: T) -> Result<()> {
|
pub fn listen<T: Into<IpEndpoint>>(&self, endpoint: T) -> Result<()> {
|
||||||
let endpoint = endpoint.into();
|
let endpoint = endpoint.into();
|
||||||
match self.as_lower().listen(endpoint) {
|
self.with_lower(|mut s| s.listen(endpoint))
|
||||||
Ok(()) => Ok(()),
|
.map(|()| {
|
||||||
Err(ErrorLower::Illegal) =>
|
|
||||||
Err(Error::new(ErrorKind::Other, "already listening")),
|
|
||||||
Err(ErrorLower::Unaddressable) =>
|
|
||||||
Err(Error::new(ErrorKind::InvalidInput, "port cannot be zero")),
|
|
||||||
_ => unreachable!()
|
|
||||||
}?;
|
|
||||||
self.endpoint.set(endpoint);
|
self.endpoint.set(endpoint);
|
||||||
Ok(())
|
()
|
||||||
|
})
|
||||||
|
.map_err(|err| {
|
||||||
|
match err {
|
||||||
|
ErrorLower::Illegal =>
|
||||||
|
Error::new(ErrorKind::Other, "already listening"),
|
||||||
|
ErrorLower::Unaddressable =>
|
||||||
|
Error::new(ErrorKind::InvalidInput, "port cannot be zero"),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(&self) -> Result<TcpStream<'a>> {
|
pub fn accept(&self) -> Result<TcpStream<'a>> {
|
||||||
|
@ -389,8 +328,8 @@ impl<'a> TcpListener<'a> {
|
||||||
// that still counts as accepting even though nothing may be sent.
|
// that still counts as accepting even though nothing may be sent.
|
||||||
let (sockets, handle) = (self.io.sockets.clone(), self.handle.get());
|
let (sockets, handle) = (self.io.sockets.clone(), self.handle.get());
|
||||||
self.io.until(move || {
|
self.io.until(move || {
|
||||||
let mut sockets = borrow_mut!(sockets);
|
let mut sockets = sockets.borrow_mut();
|
||||||
let socket: &mut TcpSocketLower = sockets.get_mut(handle).as_socket();
|
let socket = sockets.get::<TcpSocketLower>(handle);
|
||||||
socket.may_send() || socket.may_recv()
|
socket.may_send() || socket.may_recv()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -407,14 +346,14 @@ impl<'a> TcpListener<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&self) {
|
pub fn close(&self) {
|
||||||
self.as_lower().close()
|
self.with_lower(|mut s| s.close())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for TcpListener<'a> {
|
impl<'a> Drop for TcpListener<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.as_lower().close();
|
self.with_lower(|mut s| s.close());
|
||||||
borrow_mut!(self.io.sockets).release(self.handle.get())
|
self.io.sockets.borrow_mut().release(self.handle.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,57 +376,59 @@ impl<'a> TcpStream<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_lower<'b>(&'b self) -> RefMut<'b, TcpSocketLower> {
|
fn with_lower<F, R>(&self, f: F) -> R
|
||||||
RefMut::map(borrow_mut!(self.io.sockets),
|
where F: FnOnce(SocketRef<TcpSocketLower>) -> R {
|
||||||
|sockets| sockets.get_mut(self.handle).as_socket())
|
let mut sockets = self.io.sockets.borrow_mut();
|
||||||
|
let result = f(sockets.get(self.handle));
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_open(&self) -> bool {
|
pub fn is_open(&self) -> bool {
|
||||||
self.as_lower().is_open()
|
self.with_lower(|s| s.is_open())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn may_send(&self) -> bool {
|
pub fn may_send(&self) -> bool {
|
||||||
self.as_lower().may_send()
|
self.with_lower(|s| s.may_send())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn may_recv(&self) -> bool {
|
pub fn may_recv(&self) -> bool {
|
||||||
self.as_lower().may_recv()
|
self.with_lower(|s| s.may_recv())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_send(&self) -> bool {
|
pub fn can_send(&self) -> bool {
|
||||||
self.as_lower().can_send()
|
self.with_lower(|s| s.can_send())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_recv(&self) -> bool {
|
pub fn can_recv(&self) -> bool {
|
||||||
self.as_lower().can_recv()
|
self.with_lower(|s| s.can_recv())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_endpoint(&self) -> IpEndpoint {
|
pub fn local_endpoint(&self) -> IpEndpoint {
|
||||||
self.as_lower().local_endpoint()
|
self.with_lower(|s| s.local_endpoint())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remote_endpoint(&self) -> IpEndpoint {
|
pub fn remote_endpoint(&self) -> IpEndpoint {
|
||||||
self.as_lower().remote_endpoint()
|
self.with_lower(|s| s.remote_endpoint())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn timeout(&self) -> Option<u64> {
|
pub fn timeout(&self) -> Option<u64> {
|
||||||
self.as_lower().timeout()
|
self.with_lower(|s| s.timeout())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_timeout(&self, value: Option<u64>) {
|
pub fn set_timeout(&self, value: Option<u64>) {
|
||||||
self.as_lower().set_timeout(value)
|
self.with_lower(|mut s| s.set_timeout(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keep_alive(&self) -> Option<u64> {
|
pub fn keep_alive(&self) -> Option<u64> {
|
||||||
self.as_lower().keep_alive()
|
self.with_lower(|s| s.keep_alive())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keep_alive(&self, value: Option<u64>) {
|
pub fn set_keep_alive(&self, value: Option<u64>) {
|
||||||
self.as_lower().set_keep_alive(value)
|
self.with_lower(|mut s| s.set_keep_alive(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&self) -> Result<()> {
|
pub fn close(&self) -> Result<()> {
|
||||||
self.as_lower().close();
|
self.with_lower(|mut s| s.close());
|
||||||
until!(self, TcpSocketLower, |s| !s.is_open())?;
|
until!(self, TcpSocketLower, |s| !s.is_open())?;
|
||||||
// right now the socket may be in TIME-WAIT state. if we don't give it a chance to send
|
// right now the socket may be in TIME-WAIT state. if we don't give it a chance to send
|
||||||
// a packet, and the user code executes a loop { s.listen(); s.read(); s.close(); }
|
// a packet, and the user code executes a loop { s.listen(); s.read(); s.close(); }
|
||||||
|
@ -499,12 +440,12 @@ impl<'a> TcpStream<'a> {
|
||||||
impl<'a> Read for TcpStream<'a> {
|
impl<'a> Read for TcpStream<'a> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
// Only borrow the underlying socket for the span of the next statement.
|
// Only borrow the underlying socket for the span of the next statement.
|
||||||
let result = self.as_lower().recv_slice(buf);
|
let result = self.with_lower(|mut s| s.recv_slice(buf));
|
||||||
match result {
|
match result {
|
||||||
// Slow path: we need to block until buffer is non-empty.
|
// Slow path: we need to block until buffer is non-empty.
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
until!(self, TcpSocketLower, |s| s.can_recv() || !s.may_recv())?;
|
until!(self, TcpSocketLower, |s| s.can_recv() || !s.may_recv())?;
|
||||||
match self.as_lower().recv_slice(buf) {
|
match self.with_lower(|mut s| s.recv_slice(buf)) {
|
||||||
Ok(length) => Ok(length),
|
Ok(length) => Ok(length),
|
||||||
Err(ErrorLower::Illegal) => Ok(0),
|
Err(ErrorLower::Illegal) => Ok(0),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
|
@ -523,12 +464,12 @@ impl<'a> Read for TcpStream<'a> {
|
||||||
impl<'a> Write for TcpStream<'a> {
|
impl<'a> Write for TcpStream<'a> {
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
// Only borrow the underlying socket for the span of the next statement.
|
// Only borrow the underlying socket for the span of the next statement.
|
||||||
let result = self.as_lower().send_slice(buf);
|
let result = self.with_lower(|mut s| s.send_slice(buf));
|
||||||
match result {
|
match result {
|
||||||
// Slow path: we need to block until buffer is non-full.
|
// Slow path: we need to block until buffer is non-full.
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
until!(self, TcpSocketLower, |s| s.can_send() || !s.may_send())?;
|
until!(self, TcpSocketLower, |s| s.can_send() || !s.may_send())?;
|
||||||
match self.as_lower().send_slice(buf) {
|
match self.with_lower(|mut s| s.send_slice(buf)) {
|
||||||
Ok(length) => Ok(length),
|
Ok(length) => Ok(length),
|
||||||
Err(ErrorLower::Illegal) => Ok(0),
|
Err(ErrorLower::Illegal) => Ok(0),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
|
@ -545,7 +486,7 @@ impl<'a> Write for TcpStream<'a> {
|
||||||
|
|
||||||
fn flush(&mut self) -> Result<()> {
|
fn flush(&mut self) -> Result<()> {
|
||||||
until!(self, TcpSocketLower, |s| s.send_queue() == 0 || !s.may_send())?;
|
until!(self, TcpSocketLower, |s| s.send_queue() == 0 || !s.may_send())?;
|
||||||
if self.as_lower().send_queue() == 0 {
|
if self.with_lower(|s| s.send_queue()) == 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new(ErrorKind::ConnectionAborted, "connection aborted"))
|
Err(Error::new(ErrorKind::ConnectionAborted, "connection aborted"))
|
||||||
|
@ -555,7 +496,7 @@ impl<'a> Write for TcpStream<'a> {
|
||||||
|
|
||||||
impl<'a> Drop for TcpStream<'a> {
|
impl<'a> Drop for TcpStream<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.as_lower().close();
|
self.with_lower(|mut s| s.close());
|
||||||
borrow_mut!(self.io.sockets).release(self.handle)
|
self.io.sockets.borrow_mut().release(self.handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@ use std::{mem, str};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use {config, rtio_mgt, mailbox, rpc_queue, kernel};
|
use {rtio_mgt, mailbox, rpc_queue, kernel};
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
use rtio_dma::Manager as DmaManager;
|
use rtio_dma::Manager as DmaManager;
|
||||||
use urc::Urc;
|
use urc::Urc;
|
||||||
use sched::{ThreadHandle, Io};
|
use sched::{ThreadHandle, Io};
|
||||||
use sched::{TcpListener, TcpStream};
|
use sched::{TcpListener, TcpStream};
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
use board;
|
use board::{self, config};
|
||||||
|
|
||||||
use rpc_proto as rpc;
|
use rpc_proto as rpc;
|
||||||
use session_proto as host;
|
use session_proto as host;
|
||||||
|
@ -615,7 +615,7 @@ pub fn thread(io: Io) {
|
||||||
{
|
{
|
||||||
let congress = congress.clone();
|
let congress = congress.clone();
|
||||||
respawn(&io, &mut kernel_thread, move |io| {
|
respawn(&io, &mut kernel_thread, move |io| {
|
||||||
let mut congress = borrow_mut!(congress);
|
let mut congress = congress.borrow_mut();
|
||||||
info!("running startup kernel");
|
info!("running startup kernel");
|
||||||
match flash_kernel_worker(&io, &mut congress, "startup_kernel") {
|
match flash_kernel_worker(&io, &mut congress, "startup_kernel") {
|
||||||
Ok(()) => info!("startup kernel finished"),
|
Ok(()) => info!("startup kernel finished"),
|
||||||
|
@ -650,7 +650,7 @@ pub fn thread(io: Io) {
|
||||||
let congress = congress.clone();
|
let congress = congress.clone();
|
||||||
let stream = stream.into_handle();
|
let stream = stream.into_handle();
|
||||||
respawn(&io, &mut kernel_thread, move |io| {
|
respawn(&io, &mut kernel_thread, move |io| {
|
||||||
let mut congress = borrow_mut!(congress);
|
let mut congress = congress.borrow_mut();
|
||||||
let mut stream = TcpStream::from_handle(&io, stream);
|
let mut stream = TcpStream::from_handle(&io, stream);
|
||||||
match host_kernel_worker(&io, &mut stream, &mut *congress) {
|
match host_kernel_worker(&io, &mut stream, &mut *congress) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
|
@ -673,7 +673,7 @@ pub fn thread(io: Io) {
|
||||||
|
|
||||||
let congress = congress.clone();
|
let congress = congress.clone();
|
||||||
respawn(&io, &mut kernel_thread, move |io| {
|
respawn(&io, &mut kernel_thread, move |io| {
|
||||||
let mut congress = borrow_mut!(congress);
|
let mut congress = congress.borrow_mut();
|
||||||
match flash_kernel_worker(&io, &mut *congress, "idle_kernel") {
|
match flash_kernel_worker(&io, &mut *congress, "idle_kernel") {
|
||||||
Ok(()) =>
|
Ok(()) =>
|
||||||
info!("idle kernel finished, standing by"),
|
info!("idle kernel finished, standing by"),
|
||||||
|
|
|
@ -5,25 +5,17 @@ LDFLAGS += -L../libbase
|
||||||
|
|
||||||
RUSTFLAGS += -Cpanic=abort
|
RUSTFLAGS += -Cpanic=abort
|
||||||
|
|
||||||
all: satman.bin satman.fbi
|
all:: satman.bin satman.fbi
|
||||||
|
|
||||||
.PHONY: $(RUSTOUT)/libsatman.a
|
.PHONY: $(RUSTOUT)/libsatman.a
|
||||||
$(RUSTOUT)/libsatman.a:
|
$(RUSTOUT)/libsatman.a:
|
||||||
$(cargo) --manifest-path $(SATMAN_DIRECTORY)/Cargo.toml
|
$(cargo) --manifest-path $(SATMAN_DIRECTORY)/Cargo.toml
|
||||||
|
|
||||||
satman.elf: $(RUSTOUT)/libsatman.a
|
satman.elf: $(RUSTOUT)/libsatman.a
|
||||||
$(LD) $(LDFLAGS) -T $(SATMAN_DIRECTORY)/satman.ld -o $@ $^
|
$(link) -T $(SATMAN_DIRECTORY)/satman.ld
|
||||||
@chmod -x $@
|
|
||||||
|
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
$(OBJCOPY) -O binary $< $@
|
$(objcopy) -O binary
|
||||||
@chmod -x $@
|
|
||||||
|
|
||||||
%.fbi: %.bin
|
%.fbi: %.bin
|
||||||
@echo " MSCIMG " $@ && $(PYTHON) -m misoc.tools.mkmscimg -f -o $@ $<
|
$(mscimg) -f
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) satman.elf satman.bin satman.fbi
|
|
||||||
$(RM) -rf cargo
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
|
|
|
@ -51,6 +51,10 @@ Prerequisites:
|
||||||
help="target adapter, default: %(default)s")
|
help="target adapter, default: %(default)s")
|
||||||
parser.add_argument("--target-file", default=None,
|
parser.add_argument("--target-file", default=None,
|
||||||
help="use alternative OpenOCD target file")
|
help="use alternative OpenOCD target file")
|
||||||
|
parser.add_argument("-I", "--preinit-command", default=[], action="append",
|
||||||
|
help="add a pre-initialization OpenOCD command. "
|
||||||
|
"Useful for selecting a development board "
|
||||||
|
"when several are connected.")
|
||||||
parser.add_argument("-f", "--storage", help="write file to storage area")
|
parser.add_argument("-f", "--storage", help="write file to storage area")
|
||||||
parser.add_argument("-d", "--dir", help="look for files in this directory")
|
parser.add_argument("-d", "--dir", help="look for files in this directory")
|
||||||
parser.add_argument("action", metavar="ACTION", nargs="*",
|
parser.add_argument("action", metavar="ACTION", nargs="*",
|
||||||
|
@ -69,8 +73,8 @@ def main():
|
||||||
"start": "xc7_program xc7.tap",
|
"start": "xc7_program xc7.tap",
|
||||||
"gateware": 0x000000,
|
"gateware": 0x000000,
|
||||||
"bios": 0xaf0000,
|
"bios": 0xaf0000,
|
||||||
"runtime": 0xb00000,
|
"storage": 0xb30000,
|
||||||
"storage": 0xb80000,
|
"runtime": 0xb40000,
|
||||||
},
|
},
|
||||||
}[opts.target]
|
}[opts.target]
|
||||||
|
|
||||||
|
@ -84,6 +88,7 @@ def main():
|
||||||
conv = False
|
conv = False
|
||||||
|
|
||||||
prog = []
|
prog = []
|
||||||
|
prog.extend(opts.preinit_command)
|
||||||
prog.append("init")
|
prog.append("init")
|
||||||
for action in opts.action:
|
for action in opts.action:
|
||||||
if action == "proxy":
|
if action == "proxy":
|
||||||
|
|
|
@ -94,6 +94,7 @@ class DBWriter(TaskObject):
|
||||||
"too many pending updates", k)
|
"too many pending updates", k)
|
||||||
|
|
||||||
async def _do(self):
|
async def _do(self):
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
while True:
|
while True:
|
||||||
k, v, t = await self._queue.get()
|
k, v, t = await self._queue.get()
|
||||||
url = self.base_url + "/write"
|
url = self.base_url + "/write"
|
||||||
|
@ -102,8 +103,7 @@ class DBWriter(TaskObject):
|
||||||
data = "{},dataset={} {} {}".format(
|
data = "{},dataset={} {} {}".format(
|
||||||
self.table, k, format_influxdb(v), round(t*1e3))
|
self.table, k, format_influxdb(v), round(t*1e3))
|
||||||
try:
|
try:
|
||||||
response = await aiohttp.request(
|
response = await session.post(url, params=params, data=data)
|
||||||
"POST", url, params=params, data=data)
|
|
||||||
except:
|
except:
|
||||||
logger.warning("got exception trying to update '%s'",
|
logger.warning("got exception trying to update '%s'",
|
||||||
k, exc_info=True)
|
k, exc_info=True)
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
# * tcpdump has CAP_NET_RAW capabilities set
|
# * tcpdump has CAP_NET_RAW capabilities set
|
||||||
# use # setcap cap_net_raw+eip /usr/sbin/tcpdump
|
# use # setcap cap_net_raw+eip /usr/sbin/tcpdump
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
import os
|
||||||
|
import argparse
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from artiq.tools import verbosity_args, init_logger, logger, SSHClient
|
from artiq.tools import verbosity_args, init_logger, logger, SSHClient
|
||||||
|
@ -49,7 +49,6 @@ def main():
|
||||||
subprocess.check_call(args.command)
|
subprocess.check_call(args.command)
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
logger.error("Command failed")
|
logger.error("Command failed")
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
tcpdump.close()
|
tcpdump.close()
|
||||||
sftp.get("{tmp}/trace.pcap".format(tmp=client.tmp),
|
sftp.get("{tmp}/trace.pcap".format(tmp=client.tmp),
|
||||||
|
|
|
@ -208,9 +208,11 @@ class SPIMaster(Module):
|
||||||
|
|
||||||
clk_t = TSTriple()
|
clk_t = TSTriple()
|
||||||
self.specials += clk_t.get_tristate(pads.clk)
|
self.specials += clk_t.get_tristate(pads.clk)
|
||||||
self.comb += [
|
self.comb += clk_t.oe.eq(~config.offline),
|
||||||
clk_t.oe.eq(~config.offline),
|
self.sync += [
|
||||||
clk_t.o.eq((spi.cg.clk & spi.cs) ^ config.clk_polarity),
|
If(spi.cg.ce & spi.cg.edge,
|
||||||
|
clk_t.o.eq((~spi.cg.clk & spi.cs_next) ^ config.clk_polarity)
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
mosi_t = TSTriple()
|
mosi_t = TSTriple()
|
||||||
|
|
|
@ -157,7 +157,6 @@ class Phaser(MiniSoC, AMPSoC):
|
||||||
"rtio": 0x20000000,
|
"rtio": 0x20000000,
|
||||||
"rtio_dma": 0x30000000,
|
"rtio_dma": 0x30000000,
|
||||||
"mailbox": 0x70000000,
|
"mailbox": 0x70000000,
|
||||||
"ad9154": 0x50000000,
|
|
||||||
}
|
}
|
||||||
mem_map.update(MiniSoC.mem_map)
|
mem_map.update(MiniSoC.mem_map)
|
||||||
|
|
|
@ -12,17 +12,17 @@
|
||||||
version="1.1"
|
version="1.1"
|
||||||
x="0px"
|
x="0px"
|
||||||
y="0px"
|
y="0px"
|
||||||
width="360.147"
|
width="323.49704"
|
||||||
height="432.04401"
|
height="432.04401"
|
||||||
viewBox="0 0 360.147 432.04401"
|
viewBox="0 0 323.49704 432.04401"
|
||||||
enable-background="new 0 0 800 800"
|
enable-background="new 0 0 800 800"
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
id="svg2"
|
id="svg2"
|
||||||
inkscape:version="0.91 r13725"
|
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
||||||
sodipodi:docname="logo_ver.svg"><metadata
|
sodipodi:docname="logo_ver.svg"><metadata
|
||||||
id="metadata548"><rdf:RDF><cc:Work
|
id="metadata548"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
id="defs546" /><sodipodi:namedview
|
id="defs546" /><sodipodi:namedview
|
||||||
pagecolor="#ffffff"
|
pagecolor="#ffffff"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1156"
|
inkscape:window-height="1124"
|
||||||
id="namedview544"
|
id="namedview544"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
fit-margin-top="0"
|
fit-margin-top="0"
|
||||||
|
@ -41,12 +41,12 @@
|
||||||
fit-margin-right="0"
|
fit-margin-right="0"
|
||||||
fit-margin-bottom="0"
|
fit-margin-bottom="0"
|
||||||
inkscape:zoom="0.834386"
|
inkscape:zoom="0.834386"
|
||||||
inkscape:cx="-244.98179"
|
inkscape:cx="-466.10247"
|
||||||
inkscape:cy="163.75581"
|
inkscape:cy="163.7558"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="0"
|
||||||
inkscape:window-y="44"
|
inkscape:window-y="0"
|
||||||
inkscape:window-maximized="1"
|
inkscape:window-maximized="1"
|
||||||
inkscape:current-layer="svg2" /><path
|
inkscape:current-layer="text3371" /><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path381"
|
id="path381"
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path383"
|
id="path383"
|
||||||
d="m 53.761,135.723 10.609,9.812 c 0.215,-0.162 0.461,-0.348 0.689,-0.549 20.543,-18.001 43.98,-33.619 69.662,-46.423 32.912,-16.404 60.969,-25.002 88.295,-27.058 2.504,-0.188 4.811,-0.279 7.051,-0.279 9.105,0 16.873,1.591 23.744,4.864 7.635,3.636 11.473,9.741 11.404,18.146 -0.053,6.609 -1.955,13.229 -5.812,20.239 -2.68,4.868 -5.713,9.68 -8.646,14.332 -1.248,1.979 -2.502,3.969 -3.744,5.982 l 10.135,9.65 c 8.092,-10.235 16.82,-22.731 20.846,-38.001 0.467,-1.765 0.861,-3.586 1.244,-5.348 0.174,-0.804 0.348,-1.606 0.529,-2.408 l 0,-8.887 c -0.049,-0.148 -0.102,-0.297 -0.154,-0.444 -0.141,-0.387 -0.285,-0.787 -0.357,-1.216 -2.037,-12.213 -8.967,-20.778 -21.184,-26.186 -7.824,-3.462 -16.289,-4.355 -23.535,-4.772 -2.264,-0.13 -4.576,-0.196 -6.877,-0.196 -11.945,0 -24.328,1.727 -37.859,5.278 -46.736,12.272 -90.896,35.554 -131.252,69.197 -1.098,0.917 -2.182,1.903 -3.332,2.947 -0.465,0.425 -0.948,0.863 -1.456,1.32 z" /><path
|
d="m 53.761,135.723 10.609,9.812 c 0.215,-0.162 0.461,-0.348 0.689,-0.549 20.543,-18.001 43.98,-33.619 69.662,-46.423 32.912,-16.404 60.969,-25.002 88.295,-27.058 2.504,-0.188 4.811,-0.279 7.051,-0.279 9.105,0 16.873,1.591 23.744,4.864 7.635,3.636 11.473,9.741 11.404,18.146 -0.053,6.609 -1.955,13.229 -5.812,20.239 -2.68,4.868 -5.713,9.68 -8.646,14.332 -1.248,1.979 -2.502,3.969 -3.744,5.982 l 10.135,9.65 c 8.092,-10.235 16.82,-22.731 20.846,-38.001 0.467,-1.765 0.861,-3.586 1.244,-5.348 0.174,-0.804 0.348,-1.606 0.529,-2.408 v -8.887 c -0.049,-0.148 -0.102,-0.297 -0.154,-0.444 -0.141,-0.387 -0.285,-0.787 -0.357,-1.216 -2.037,-12.213 -8.967,-20.778 -21.184,-26.186 -7.824,-3.462 -16.289,-4.355 -23.535,-4.772 -2.264,-0.13 -4.576,-0.196 -6.877,-0.196 -11.945,0 -24.328,1.727 -37.859,5.278 -46.736,12.272 -90.896,35.554 -131.252,69.197 -1.098,0.917 -2.182,1.903 -3.332,2.947 -0.465,0.425 -0.948,0.863 -1.456,1.32 z" /><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path385"
|
id="path385"
|
||||||
|
@ -82,11 +82,11 @@
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path397"
|
id="path397"
|
||||||
d="m 180.738,111.632 c -0.625,-4.189 -1.227,-8.218 -1.867,-12.238 -0.326,-2.036 -5.861,-6.224 -8.229,-6.224 -0.156,0 -0.291,0.02 -0.402,0.058 -4.172,1.46 -8.242,3.096 -12.551,4.827 -1.42,0.57 -2.855,1.146 -4.316,1.727 l 28,16.088 -0.635,-4.238 z" /><path
|
d="m 180.738,111.632 c -0.625,-4.189 -1.227,-8.218 -1.867,-12.238 -0.326,-2.036 -5.861,-6.224 -8.229,-6.224 -0.156,0 -0.291,0.02 -0.402,0.058 -4.172,1.46 -8.242,3.096 -12.551,4.827 -1.42,0.57 -2.855,1.146 -4.316,1.727 l 28,16.088 z" /><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path399"
|
id="path399"
|
||||||
d="m 90.154,136.545 c -0.338,0.264 -0.668,0.525 -1,0.788 -0.463,0.366 -0.936,0.736 -1.393,1.099 -2.838,2.248 -5.516,4.371 -8.346,6.353 -2.75,1.927 -3.779,4.095 -3.336,7.03 0.102,0.675 0.096,1.436 0.09,2.17 -0.01,1.219 -0.02,2.479 0.488,2.946 3.336,3.059 6.891,5.851 10.654,8.807 0.605,0.477 1.227,0.968 1.842,1.452 0.334,0.264 0.664,0.523 1,0.789 0.188,0.148 0.369,0.29 0.557,0.439 l 0,-32.312 c -0.189,0.148 -0.369,0.291 -0.556,0.439 z" /><path
|
d="m 90.154,136.545 c -0.338,0.264 -0.668,0.525 -1,0.788 -0.463,0.366 -0.936,0.736 -1.393,1.099 -2.838,2.248 -5.516,4.371 -8.346,6.353 -2.75,1.927 -3.779,4.095 -3.336,7.03 0.102,0.675 0.096,1.436 0.09,2.17 -0.01,1.219 -0.02,2.479 0.488,2.946 3.336,3.059 6.891,5.851 10.654,8.807 0.605,0.477 1.227,0.968 1.842,1.452 0.334,0.264 0.664,0.523 1,0.789 0.188,0.148 0.369,0.29 0.557,0.439 v -32.312 c -0.189,0.148 -0.369,0.291 -0.556,0.439 z" /><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path401"
|
id="path401"
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path405"
|
id="path405"
|
||||||
d="M 231.324,171.353 221.01,161.63 c -0.9,2.513 -2.059,14.3 -1.457,19.737 l 11.771,-10.014 z" /><path
|
d="M 231.324,171.353 221.01,161.63 c -0.9,2.513 -2.059,14.3 -1.457,19.737 z" /><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path407"
|
id="path407"
|
||||||
|
@ -117,25 +117,25 @@
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path415"
|
id="path415"
|
||||||
d="m 366.13,593.558 c 7.498,-5.083 10.756,-15.119 7.922,-24.407 -2.773,-9.089 -10.521,-14.536 -20.727,-14.573 l -26.715,0 0,61.202 14.156,0 0,-18.602 9.979,0 10.836,18.602 16.479,0 0,-1.06 -12.725,-20.623 0.795,-0.539 z m -12.801,-8.731 -12.562,0 0,-17.809 1.004,0 c 1.254,0 2.529,-0.01 3.811,-0.02 2.6,-0.021 5.225,-0.041 7.771,0.02 5.328,0.052 7.74,4.621 7.719,8.845 -0.022,4.454 -2.688,8.964 -7.743,8.964 z" /><polygon
|
d="m 366.13,593.558 c 7.498,-5.083 10.756,-15.119 7.922,-24.407 -2.773,-9.089 -10.521,-14.536 -20.727,-14.573 H 326.61 v 61.202 h 14.156 v -18.602 h 9.979 l 10.836,18.602 h 16.479 v -1.06 l -12.725,-20.623 z m -12.801,-8.731 h -12.562 v -17.809 h 1.004 c 1.254,0 2.529,-0.01 3.811,-0.02 2.6,-0.021 5.225,-0.041 7.771,0.02 5.328,0.052 7.74,4.621 7.719,8.845 -0.022,4.454 -2.688,8.964 -7.743,8.964 z" /><polygon
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="polygon417"
|
id="polygon417"
|
||||||
points="432.151,554.577 387.202,554.577 387.202,567.019 402.733,567.019 402.733,615.779 416.71,615.779 416.71,567.019 432.151,567.019 " /><polygon
|
points="387.202,567.019 402.733,567.019 402.733,615.779 416.71,615.779 416.71,567.019 432.151,567.019 432.151,554.577 387.202,554.577 " /><polygon
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="polygon419"
|
id="polygon419"
|
||||||
points="464.571,566.657 471.976,566.657 471.976,554.577 443.19,554.577 443.19,566.657 450.595,566.657 450.595,603.608 442.558,603.608 442.558,615.779 472.606,615.779 472.606,603.608 464.571,603.608 " /><path
|
points="471.976,554.577 443.19,554.577 443.19,566.657 450.595,566.657 450.595,603.608 442.558,603.608 442.558,615.779 472.606,615.779 472.606,603.608 464.571,603.608 464.571,566.657 471.976,566.657 " /><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path421"
|
id="path421"
|
||||||
d="m 542.927,603.421 c 3.252,-5.109 4.9,-11.218 4.9,-18.153 0,-21.831 -16.283,-31.774 -31.414,-31.774 -15.129,0 -31.414,9.943 -31.414,31.774 0,21.683 16.174,31.56 31.199,31.56 5.541,0 10.949,-1.321 15.637,-3.82 l 0.885,-0.472 1.725,3.244 14.828,0 0,-0.794 -6.68,-11.039 0.334,-0.526 z m -26.514,0.053 c -8.094,0 -16.805,-5.697 -16.805,-18.206 0,-12.415 8.711,-18.069 16.805,-18.069 8.094,0 16.807,5.654 16.807,18.069 0,12.508 -8.713,18.206 -16.807,18.206 z" /></g><path
|
d="m 542.927,603.421 c 3.252,-5.109 4.9,-11.218 4.9,-18.153 0,-21.831 -16.283,-31.774 -31.414,-31.774 -15.129,0 -31.414,9.943 -31.414,31.774 0,21.683 16.174,31.56 31.199,31.56 5.541,0 10.949,-1.321 15.637,-3.82 l 0.885,-0.472 1.725,3.244 h 14.828 v -0.794 l -6.68,-11.039 z m -26.514,0.053 c -8.094,0 -16.805,-5.697 -16.805,-18.206 0,-12.415 8.711,-18.069 16.805,-18.069 8.094,0 16.807,5.654 16.807,18.069 0,12.508 -8.713,18.206 -16.807,18.206 z" /></g><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path431"
|
id="path431"
|
||||||
d="m 165.162,221.756 0.006,-0.025 C 140.75,212.522 116.912,200.02 94.189,184.475 69.636,167.678 51.56,151.283 37.304,132.879 28.589,121.632 23.536,112.162 20.923,102.174 c -3.068,-11.729 0.105,-20.54 9.178,-25.482 2.277,-1.241 4.834,-2.269 7.596,-3.054 7.576,-2.153 15.721,-2.812 25.201,-2.015 1.244,0.104 2.52,0.217 3.805,0.332 1.402,0.123 2.803,0.242 4.209,0.368 l 3.176,0.281 3.846,-13.919 c -0.947,-0.121 -1.893,-0.245 -2.83,-0.37 -2.537,-0.337 -4.934,-0.656 -7.25,-0.857 -4.689,-0.406 -8.803,-0.604 -12.578,-0.604 -8.74,0 -16.342,1.076 -23.24,3.29 -14.58,4.68 -23.049,13.281 -25.893,26.297 -1.943,8.9 -0.568,18.38 4.328,29.833 6.098,14.267 15.623,27.692 29.977,42.251 31.707,32.162 69.879,56.911 116.699,75.662 3.182,1.274 6.383,2.416 9.771,3.624 1.434,0.511 2.889,1.029 4.369,1.568 l 2.396,-8.365 -8.521,-9.258 z" /><path
|
d="m 165.162,221.756 0.006,-0.025 C 140.75,212.522 116.912,200.02 94.189,184.475 69.636,167.678 51.56,151.283 37.304,132.879 28.589,121.632 23.536,112.162 20.923,102.174 c -3.068,-11.729 0.105,-20.54 9.178,-25.482 2.277,-1.241 4.834,-2.269 7.596,-3.054 7.576,-2.153 15.721,-2.812 25.201,-2.015 1.244,0.104 2.52,0.217 3.805,0.332 1.402,0.123 2.803,0.242 4.209,0.368 l 3.176,0.281 3.846,-13.919 c -0.947,-0.121 -1.893,-0.245 -2.83,-0.37 -2.537,-0.337 -4.934,-0.656 -7.25,-0.857 -4.689,-0.406 -8.803,-0.604 -12.578,-0.604 -8.74,0 -16.342,1.076 -23.24,3.29 -14.58,4.68 -23.049,13.281 -25.893,26.297 -1.943,8.9 -0.568,18.38 4.328,29.833 6.098,14.267 15.623,27.692 29.977,42.251 31.707,32.162 69.879,56.911 116.699,75.662 3.182,1.274 6.383,2.416 9.771,3.624 1.434,0.511 2.889,1.029 4.369,1.568 l 2.396,-8.365 z" /><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path433"
|
id="path433"
|
||||||
d="m 279.656,208.102 c -0.146,-0.262 -0.314,-0.56 -0.359,-0.905 -0.99,-8.005 -3.834,-16.142 -8.688,-24.875 -7.945,-14.297 -18.83,-27.683 -34.252,-42.126 -3.812,-3.572 -7.723,-6.949 -11.863,-10.523 -1.678,-1.448 -3.377,-2.915 -5.096,-4.419 -0.006,0.032 -0.012,0.062 -0.018,0.092 -0.062,0.355 -0.096,0.551 -0.09,0.713 l 0.148,3.794 c 0.176,4.559 0.359,9.272 0.67,13.896 0.047,0.706 0.615,1.672 1.52,2.583 2.135,2.144 4.346,4.286 6.484,6.358 3.807,3.687 7.742,7.5 11.389,11.467 11.611,12.634 19.076,24.245 23.488,36.543 2.049,5.705 2.707,10.802 2.012,15.581 -1.146,7.896 -6.145,13.235 -15.281,16.322 -2.455,0.829 -5.002,1.474 -7.656,1.956 l 9.738,12.6 c 1.551,-0.468 3.08,-0.975 4.574,-1.562 12.387,-4.858 19.754,-12.956 22.521,-24.758 l 0.869,-3.686 0,-8.847 c -0.034,-0.068 -0.071,-0.136 -0.11,-0.204 z" /><g
|
d="m 279.656,208.102 c -0.146,-0.262 -0.314,-0.56 -0.359,-0.905 -0.99,-8.005 -3.834,-16.142 -8.688,-24.875 -7.945,-14.297 -18.83,-27.683 -34.252,-42.126 -3.812,-3.572 -7.723,-6.949 -11.863,-10.523 -1.678,-1.448 -3.377,-2.915 -5.096,-4.419 -0.006,0.032 -0.012,0.062 -0.018,0.092 -0.062,0.355 -0.096,0.551 -0.09,0.713 l 0.148,3.794 c 0.176,4.559 0.359,9.272 0.67,13.896 0.047,0.706 0.615,1.672 1.52,2.583 2.135,2.144 4.346,4.286 6.484,6.358 3.807,3.687 7.742,7.5 11.389,11.467 11.611,12.634 19.076,24.245 23.488,36.543 2.049,5.705 2.707,10.802 2.012,15.581 -1.146,7.896 -6.145,13.235 -15.281,16.322 -2.455,0.829 -5.002,1.474 -7.656,1.956 l 9.738,12.6 c 1.551,-0.468 3.08,-0.975 4.574,-1.562 12.387,-4.858 19.754,-12.956 22.521,-24.758 l 0.869,-3.686 v -8.847 c -0.034,-0.068 -0.071,-0.136 -0.11,-0.204 z" /><g
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="g435"
|
id="g435"
|
||||||
transform="translate(-250.847,-184.784)"><path
|
transform="translate(-250.847,-184.784)"><path
|
||||||
|
@ -146,19 +146,14 @@
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path439"
|
id="path439"
|
||||||
d="m 433.437,425.474 c -2.322,7.348 -4.98,14.184 -8.043,20.678 -3.967,8.416 -9.191,17.993 -17.877,25.219 -9.297,7.733 -19.082,7.701 -28.365,-0.092 -5.934,-4.982 -10.92,-11.633 -15.691,-20.929 -6.629,-12.926 -11.459,-27.311 -15.66,-46.642 l -0.072,-0.342 c -0.174,-0.828 -0.412,-1.962 -0.893,-2.284 -4.152,-2.786 -8.357,-5.448 -12.807,-8.267 -1.068,-0.677 -2.146,-1.359 -3.238,-2.054 0.164,0.969 0.32,1.911 0.475,2.834 0.434,2.596 0.842,5.047 1.303,7.478 4.703,24.702 10.705,42.76 19.463,58.551 7.541,13.604 17.859,28.05 37.209,32.08 l 8.318,0 c 17.949,-3.632 27.887,-16.568 35.24,-28.748 1.953,-3.234 3.717,-6.507 5.244,-9.726 2.389,-5.035 4.557,-10.249 6.533,-15.655 l -11.139,-12.101 z" /></g><path
|
d="m 433.437,425.474 c -2.322,7.348 -4.98,14.184 -8.043,20.678 -3.967,8.416 -9.191,17.993 -17.877,25.219 -9.297,7.733 -19.082,7.701 -28.365,-0.092 -5.934,-4.982 -10.92,-11.633 -15.691,-20.929 -6.629,-12.926 -11.459,-27.311 -15.66,-46.642 l -0.072,-0.342 c -0.174,-0.828 -0.412,-1.962 -0.893,-2.284 -4.152,-2.786 -8.357,-5.448 -12.807,-8.267 -1.068,-0.677 -2.146,-1.359 -3.238,-2.054 0.164,0.969 0.32,1.911 0.475,2.834 0.434,2.596 0.842,5.047 1.303,7.478 4.703,24.702 10.705,42.76 19.463,58.551 7.541,13.604 17.859,28.05 37.209,32.08 h 8.318 c 17.949,-3.632 27.887,-16.568 35.24,-28.748 1.953,-3.234 3.717,-6.507 5.244,-9.726 2.389,-5.035 4.557,-10.249 6.533,-15.655 z" /></g><path
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
id="path493"
|
id="path493"
|
||||||
d="M 28.084,368.98 0,429.872 l 0,1.124 14.16,0 4.202,-8.945 25.208,0 4.195,8.945 14.16,0 0,-1.124 -28.172,-60.892 -5.669,0 z m -5.438,41.259 8.215,-19.134 8.424,19.134 -16.639,0 z" /><g
|
d="M 28.084,368.98 0,429.872 v 1.124 h 14.16 l 4.202,-8.945 H 43.57 l 4.195,8.945 h 14.16 v -1.124 L 33.753,368.98 Z m -5.438,41.259 8.215,-19.134 8.424,19.134 z" /><g
|
||||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:expanded;font-size:45px;line-height:125%;font-family:'Novecento sans wide';-inkscape-font-specification:'Novecento sans wide, Semi-Bold Expanded';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:expanded;font-size:45px;line-height:125%;font-family:'Novecento sans wide';-inkscape-font-specification:'Novecento sans wide, Semi-Bold Expanded';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
id="text3371"><path
|
id="text3371"><path
|
||||||
d="m 318.27705,360.24104 c 2.295,-0.315 4.95,-2.115 4.95,-5.895 0,-3.96 -2.88,-6.57 -8.775,-6.57 -4.635,0 -8.685,1.62 -9.675,6.57 l 4.275,1.17 c 0.27,-1.98 1.395,-3.87 4.95,-3.87 2.925,0 4.635,1.305 4.635,3.51 0,2.295 -1.755,3.555 -4.77,3.555 l -2.475,0 0,3.42 2.655,0 c 2.925,0 4.86,1.215 4.86,3.69 0,2.295 -1.62,4.095 -4.86,4.095 -3.06,0 -5.04,-1.53 -5.625,-4.275 l -4.14,1.17 c 0.9,4.59 4.68,7.155 9.9,7.155 5.715,0 9.315,-3.015 9.315,-7.515 0,-3.69 -2.385,-5.76 -5.22,-6.03 l 0,-0.18 z"
|
d="m 318.27705,360.24104 c 2.295,-0.315 4.95,-2.115 4.95,-5.895 0,-3.96 -2.88,-6.57 -8.775,-6.57 -4.635,0 -8.685,1.62 -9.675,6.57 l 4.275,1.17 c 0.27,-1.98 1.395,-3.87 4.95,-3.87 2.925,0 4.635,1.305 4.635,3.51 0,2.295 -1.755,3.555 -4.77,3.555 h -2.475 v 3.42 h 2.655 c 2.925,0 4.86,1.215 4.86,3.69 0,2.295 -1.62,4.095 -4.86,4.095 -3.06,0 -5.04,-1.53 -5.625,-4.275 l -4.14,1.17 c 0.9,4.59 4.68,7.155 9.9,7.155 5.715,0 9.315,-3.015 9.315,-7.515 0,-3.69 -2.385,-5.76 -5.22,-6.03 z"
|
||||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:expanded;font-size:45px;line-height:125%;font-family:'Novecento sans wide';-inkscape-font-specification:'Novecento sans wide, Semi-Bold Expanded';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff"
|
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:expanded;font-size:45px;line-height:125%;font-family:'Novecento sans wide';-inkscape-font-specification:'Novecento sans wide, Semi-Bold Expanded';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff"
|
||||||
id="path3376" /><path
|
id="path3376"
|
||||||
d="m 330.56416,373.87604 c 1.89,0 2.88,-1.17 2.88,-2.7 0,-1.485 -0.99,-2.655 -2.88,-2.655 -1.89,0 -2.925,1.17 -2.925,2.655 0,1.485 0.99,2.7 2.925,2.7 z"
|
inkscape:connector-curvature="0" /></g></svg>
|
||||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:expanded;font-size:45px;line-height:125%;font-family:'Novecento sans wide';-inkscape-font-specification:'Novecento sans wide, Semi-Bold Expanded';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff"
|
|
||||||
id="path3378" /><path
|
|
||||||
d="m 346.79791,347.77604 c -6.39,0 -10.26,4.455 -10.26,13.095 0,8.64 3.87,13.095 10.26,13.095 6.345,0 10.215,-4.455 10.215,-13.095 0,-8.64 -3.87,-13.095 -10.215,-13.095 z m 0,4.32 c 3.78,0 5.49,2.79 5.49,8.775 0,5.94 -1.71,8.775 -5.49,8.775 -3.825,0 -5.535,-2.835 -5.535,-8.775 0,-5.985 1.71,-8.775 5.535,-8.775 z"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:expanded;font-size:45px;line-height:125%;font-family:'Novecento sans wide';-inkscape-font-specification:'Novecento sans wide, Semi-Bold Expanded';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff"
|
|
||||||
id="path3380" /></g></svg>
|
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
@ -223,7 +223,7 @@ class ScanWidget(QtWidgets.QWidget):
|
||||||
self._zoom(self.zoomFactor**y, ev.x())
|
self._zoom(self.zoomFactor**y, ev.x())
|
||||||
|
|
||||||
def resizeEvent(self, ev):
|
def resizeEvent(self, ev):
|
||||||
if not ev.oldSize().isValid():
|
if not ev.oldSize().isValid() or not ev.oldSize().width():
|
||||||
self.viewRange()
|
self.viewRange()
|
||||||
return
|
return
|
||||||
self.ticker.min_ticks = max(
|
self.ticker.min_ticks = max(
|
||||||
|
|
|
@ -74,4 +74,4 @@ class AnalyzerTest(ExperimentCase):
|
||||||
log = "".join([_extract_log_chars(msg.data)
|
log = "".join([_extract_log_chars(msg.data)
|
||||||
for msg in dump.messages
|
for msg in dump.messages
|
||||||
if isinstance(msg, OutputMessage) and msg.channel == dump.log_channel])
|
if isinstance(msg, OutputMessage) and msg.channel == dump.log_channel])
|
||||||
self.assertEqual(log, "foo\x1E32\n\x1D")
|
self.assertEqual(log, "foo\x1E32\x1D")
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from artiq.experiment import *
|
||||||
|
from artiq.test.hardware_testbench import ExperimentCase
|
||||||
|
|
||||||
|
|
||||||
|
artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY")
|
||||||
|
|
||||||
|
|
||||||
|
class _Transfer(EnvExperiment):
|
||||||
|
def build(self):
|
||||||
|
self.setattr_device("core")
|
||||||
|
self.data = b"\x00"*(10**6)
|
||||||
|
|
||||||
|
@rpc
|
||||||
|
def source(self) -> TBytes:
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
@rpc(flags={"async"})
|
||||||
|
def sink(self, data):
|
||||||
|
assert data == self.data
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def host_to_device(self):
|
||||||
|
t0 = self.core.get_rtio_counter_mu()
|
||||||
|
data = self.source()
|
||||||
|
t1 = self.core.get_rtio_counter_mu()
|
||||||
|
return len(data)/self.core.mu_to_seconds(t1-t0)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def device_to_host(self):
|
||||||
|
t0 = self.core.get_rtio_counter_mu()
|
||||||
|
self.sink(self.data)
|
||||||
|
t1 = self.core.get_rtio_counter_mu()
|
||||||
|
return len(self.data)/self.core.mu_to_seconds(t1-t0)
|
||||||
|
|
||||||
|
|
||||||
|
class TransferTest(ExperimentCase):
|
||||||
|
@unittest.skipUnless(artiq_low_latency,
|
||||||
|
"timings are dependent on CPU load and network conditions")
|
||||||
|
def test_host_to_device(self):
|
||||||
|
exp = self.create(_Transfer)
|
||||||
|
host_to_device_rate = exp.host_to_device()
|
||||||
|
print(host_to_device_rate, "B/s")
|
||||||
|
self.assertGreater(host_to_device_rate, 2e6)
|
||||||
|
|
||||||
|
@unittest.skipUnless(artiq_low_latency,
|
||||||
|
"timings are dependent on CPU load and network conditions")
|
||||||
|
def test_device_to_host(self):
|
||||||
|
exp = self.create(_Transfer)
|
||||||
|
device_to_host_rate = exp.device_to_host()
|
||||||
|
print(device_to_host_rate, "B/s")
|
||||||
|
self.assertGreater(device_to_host_rate, 2e6)
|
|
@ -0,0 +1,12 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
|
from artiq.experiment import *
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
a = [1,2]
|
||||||
|
# CHECK-L: ${LINE:+2}: error: values cannot be mutated in-place
|
||||||
|
# CHECK-L: ${LINE:+1}: note: try using `a = a + [3,4]`
|
||||||
|
a += [3,4]
|
||||||
|
|
|
@ -9,3 +9,6 @@ list(1)
|
||||||
|
|
||||||
# CHECK-L: ${LINE:+1}: error: the arguments of min() must be of a numeric type
|
# CHECK-L: ${LINE:+1}: error: the arguments of min() must be of a numeric type
|
||||||
min([1], [1])
|
min([1], [1])
|
||||||
|
|
||||||
|
# CHECK-L: ${LINE:+1}: error: strings currently cannot be constructed
|
||||||
|
str(1)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
|
||||||
# RUN: %python %s
|
# RUN: %python %s
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||||
# REQUIRES: exceptions
|
# REQUIRES: exceptions
|
||||||
|
|
||||||
assert -(-1) == 1
|
assert -(-1) == 1
|
||||||
|
@ -20,6 +20,12 @@ assert 3 % 2 == 1
|
||||||
assert -3 % 2 == 1
|
assert -3 % 2 == 1
|
||||||
assert 3 % -2 == -1
|
assert 3 % -2 == -1
|
||||||
assert -3 % -2 == -1
|
assert -3 % -2 == -1
|
||||||
|
assert -1 % 8 == 7
|
||||||
|
#ARTIQ#assert int64(3) % 2 == 1
|
||||||
|
#ARTIQ#assert int64(-3) % 2 == 1
|
||||||
|
#ARTIQ#assert int64(3) % -2 == -1
|
||||||
|
#ARTIQ#assert int64(-3) % -2 == -1
|
||||||
|
assert -1 % 8 == 7
|
||||||
assert 3.0 % 2.0 == 1.0
|
assert 3.0 % 2.0 == 1.0
|
||||||
assert -3.0 % 2.0 == 1.0
|
assert -3.0 % 2.0 == 1.0
|
||||||
assert 3.0 % -2.0 == -1.0
|
assert 3.0 % -2.0 == -1.0
|
||||||
|
@ -35,6 +41,24 @@ assert -1 >> 32 == -1
|
||||||
assert 0x18 & 0x0f == 0x08
|
assert 0x18 & 0x0f == 0x08
|
||||||
assert 0x18 | 0x0f == 0x1f
|
assert 0x18 | 0x0f == 0x1f
|
||||||
assert 0x18 ^ 0x0f == 0x17
|
assert 0x18 ^ 0x0f == 0x17
|
||||||
|
#ARTIQ#assert ~0x18 == -25
|
||||||
|
#ARTIQ#assert ~int64(0x18) == -25
|
||||||
|
|
||||||
assert [1] + [2] == [1, 2]
|
try:
|
||||||
assert [1] * 3 == [1, 1, 1]
|
1 / 0
|
||||||
|
except ZeroDivisionError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
try:
|
||||||
|
1 // 0
|
||||||
|
except ZeroDivisionError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
try:
|
||||||
|
1 % 0
|
||||||
|
except ZeroDivisionError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
|
@ -3,3 +3,6 @@
|
||||||
|
|
||||||
ary = array([1, 2, 3])
|
ary = array([1, 2, 3])
|
||||||
assert [x*x for x in ary] == [1, 4, 9]
|
assert [x*x for x in ary] == [1, 4, 9]
|
||||||
|
|
||||||
|
assert [1] + [2] == [1, 2]
|
||||||
|
assert [1] * 3 == [1, 1, 1]
|
||||||
|
|
|
@ -90,9 +90,9 @@ class WorkerCase(unittest.TestCase):
|
||||||
with self.assertLogs() as logs:
|
with self.assertLogs() as logs:
|
||||||
with self.assertRaises(WorkerInternalException):
|
with self.assertRaises(WorkerInternalException):
|
||||||
_run_experiment("ExceptionTermination")
|
_run_experiment("ExceptionTermination")
|
||||||
self.assertEqual(len(logs.records), 1)
|
self.assertGreater(len(logs.records), 0)
|
||||||
self.assertIn("Terminating with exception (TypeError)",
|
self.assertIn("Terminating with exception (TypeError)",
|
||||||
logs.output[0])
|
logs.output[-1])
|
||||||
|
|
||||||
def test_watchdog_no_timeout(self):
|
def test_watchdog_no_timeout(self):
|
||||||
_run_experiment("WatchdogNoTimeout")
|
_run_experiment("WatchdogNoTimeout")
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
# $ conda env create -f conda/artiq-dev.yaml
|
# $ conda env create -f conda/artiq-dev.yaml
|
||||||
name: artiq-dev
|
name: artiq-dev
|
||||||
channels:
|
channels:
|
||||||
- defaults
|
|
||||||
- conda-forge/label/main
|
|
||||||
- m-labs/label/dev
|
- m-labs/label/dev
|
||||||
- m-labs/label/main
|
- m-labs/label/main
|
||||||
|
- defaults
|
||||||
|
- conda-forge/label/main
|
||||||
dependencies:
|
dependencies:
|
||||||
- artiq-dev
|
- artiq-dev
|
||||||
|
|
|
@ -14,15 +14,14 @@ requirements:
|
||||||
run:
|
run:
|
||||||
- python >=3.5.3,<3.6
|
- python >=3.5.3,<3.6
|
||||||
- setuptools 33.1.1
|
- setuptools 33.1.1
|
||||||
- migen 0.5
|
- migen 0.7 py35_0+gite554f07
|
||||||
- misoc 0.6
|
- misoc 0.9 py35_0+gitcb8e314c
|
||||||
- jesd204b 0.3
|
- jesd204b 0.3
|
||||||
- binutils-or1k-linux >=2.27
|
- binutils-or1k-linux >=2.27
|
||||||
- llvm-or1k
|
- llvm-or1k 4.0.1
|
||||||
- llvmlite-artiq 0.12.0
|
- llvmlite-artiq 0.20.0
|
||||||
- rust-core-or1k 1.20.0 16
|
- rust-core-or1k 1.23.0 19
|
||||||
- cargo 0.11.0
|
- openocd 0.10.0 1
|
||||||
- openocd >=0.10
|
|
||||||
- lit
|
- lit
|
||||||
- outputcheck
|
- outputcheck
|
||||||
- coverage
|
- coverage
|
||||||
|
@ -38,7 +37,7 @@ requirements:
|
||||||
- python-dateutil
|
- python-dateutil
|
||||||
- pyqt >=5.5
|
- pyqt >=5.5
|
||||||
- quamash
|
- quamash
|
||||||
- pyqtgraph
|
- pyqtgraph 0.10.0
|
||||||
- pygit2
|
- pygit2
|
||||||
- aiohttp
|
- aiohttp
|
||||||
- pythonparser >=1.1
|
- pythonparser >=1.1
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
# $ conda env create -f conda/artiq-doc.yaml
|
# $ conda env create -f conda/artiq-doc.yaml
|
||||||
name: artiq-doc
|
name: artiq-doc
|
||||||
channels:
|
channels:
|
||||||
- defaults
|
|
||||||
- conda-forge/label/main
|
|
||||||
- m-labs/label/dev
|
- m-labs/label/dev
|
||||||
- m-labs/label/main
|
- m-labs/label/main
|
||||||
|
- defaults
|
||||||
|
- conda-forge/label/main
|
||||||
dependencies:
|
dependencies:
|
||||||
- python>=3.5.3,<3.6
|
- python>=3.5.3,<3.6
|
||||||
- sphinx=1.4.8
|
- sphinx=1.4.8
|
||||||
|
|
|
@ -9,6 +9,6 @@ mkdir -p $SOC_PREFIX
|
||||||
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_clock --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE
|
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_clock --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE
|
||||||
cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX
|
cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX
|
||||||
cp misoc_nist_clock_kc705/software/bios/bios.bin $SOC_PREFIX
|
cp misoc_nist_clock_kc705/software/bios/bios.bin $SOC_PREFIX
|
||||||
cp misoc_nist_clock_kc705/software/runtime/runtime.fbi $SOC_PREFIX
|
cp misoc_nist_clock_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
||||||
|
|
||||||
wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/single-tap/bscan_spi_xc7k325t.bit
|
wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/single-tap/bscan_spi_xc7k325t.bit
|
||||||
|
|
|
@ -6,7 +6,7 @@ source:
|
||||||
git_url: ../..
|
git_url: ../..
|
||||||
|
|
||||||
build:
|
build:
|
||||||
noarch: generic
|
noarch: python
|
||||||
ignore_prefix_files: True
|
ignore_prefix_files: True
|
||||||
number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}
|
number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}
|
||||||
string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }}
|
string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }}
|
||||||
|
|
|
@ -9,6 +9,6 @@ mkdir -p $SOC_PREFIX
|
||||||
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_qc2 --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE
|
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_qc2 --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE
|
||||||
cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX
|
cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX
|
||||||
cp misoc_nist_qc2_kc705/software/bios/bios.bin $SOC_PREFIX
|
cp misoc_nist_qc2_kc705/software/bios/bios.bin $SOC_PREFIX
|
||||||
cp misoc_nist_qc2_kc705/software/runtime/runtime.fbi $SOC_PREFIX
|
cp misoc_nist_qc2_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
||||||
|
|
||||||
wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/single-tap/bscan_spi_xc7k325t.bit
|
wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/single-tap/bscan_spi_xc7k325t.bit
|
||||||
|
|
|
@ -6,7 +6,7 @@ source:
|
||||||
git_url: ../..
|
git_url: ../..
|
||||||
|
|
||||||
build:
|
build:
|
||||||
noarch: generic
|
noarch: python
|
||||||
ignore_prefix_files: True
|
ignore_prefix_files: True
|
||||||
number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}
|
number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}
|
||||||
string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }}
|
string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }}
|
||||||
|
|
|
@ -6,9 +6,9 @@ BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh
|
||||||
SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-phaser
|
SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-phaser
|
||||||
mkdir -p $SOC_PREFIX
|
mkdir -p $SOC_PREFIX
|
||||||
|
|
||||||
V=1 $PYTHON -m artiq.gateware.targets.phaser --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE
|
V=1 $PYTHON -m artiq.gateware.targets.kc705_phaser --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE
|
||||||
cp misoc_phaser_kc705/gateware/top.bit $SOC_PREFIX
|
cp misoc_phaser_kc705/gateware/top.bit $SOC_PREFIX
|
||||||
cp misoc_phaser_kc705/software/bios/bios.bin $SOC_PREFIX
|
cp misoc_phaser_kc705/software/bios/bios.bin $SOC_PREFIX
|
||||||
cp misoc_phaser_kc705/software/runtime/runtime.fbi $SOC_PREFIX
|
cp misoc_phaser_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
||||||
|
|
||||||
wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/single-tap/bscan_spi_xc7k325t.bit
|
wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/single-tap/bscan_spi_xc7k325t.bit
|
||||||
|
|
|
@ -6,7 +6,7 @@ source:
|
||||||
git_url: ../..
|
git_url: ../..
|
||||||
|
|
||||||
build:
|
build:
|
||||||
noarch: generic
|
noarch: python
|
||||||
ignore_prefix_files: True
|
ignore_prefix_files: True
|
||||||
number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}
|
number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}
|
||||||
string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }}
|
string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }}
|
||||||
|
|
|
@ -26,10 +26,10 @@ requirements:
|
||||||
- setuptools 33.1.1
|
- setuptools 33.1.1
|
||||||
run:
|
run:
|
||||||
- python >=3.5.3,<3.6
|
- python >=3.5.3,<3.6
|
||||||
- llvmlite-artiq 0.12.0.dev py35_30
|
- llvmlite-artiq 0.20.0
|
||||||
- binutils-or1k-linux
|
- binutils-or1k-linux >=2.27
|
||||||
- pythonparser >=1.1
|
- pythonparser >=1.1
|
||||||
- openocd >=0.10
|
- openocd 0.10.0 1
|
||||||
- lit
|
- lit
|
||||||
- outputcheck
|
- outputcheck
|
||||||
- scipy
|
- scipy
|
||||||
|
|
|
@ -20,6 +20,12 @@ import sphinx_rtd_theme
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
|
||||||
|
# Hack-patch Sphinx so that ARTIQ-Python types are correctly printed
|
||||||
|
# See: https://github.com/m-labs/artiq/issues/741
|
||||||
|
from sphinx.ext import autodoc
|
||||||
|
autodoc.repr = str
|
||||||
|
|
||||||
|
|
||||||
class Mock(MagicMock):
|
class Mock(MagicMock):
|
||||||
@classmethod
|
@classmethod
|
||||||
def __getattr__(cls, name):
|
def __getattr__(cls, name):
|
||||||
|
|
|
@ -162,11 +162,10 @@ Installation
|
||||||
............
|
............
|
||||||
|
|
||||||
These installation instructions are a short form of those in the ARTIQ manual.
|
These installation instructions are a short form of those in the ARTIQ manual.
|
||||||
|
|
||||||
* See the chapter on setting up a :ref:`development environment <develop-from-conda>`.
|
* See the chapter on setting up a :ref:`development environment <develop-from-conda>`.
|
||||||
* When compiling the binaries, use the ``phaser`` target:::
|
* When compiling the binaries, use the ``phaser`` target: ``python -m artiq.gateware.targets.kc705_phaser``
|
||||||
$ python -m artiq.gateware.targets.phaser
|
* From time to time and on request there may be pre-built binaries in the ``artiq-kc705-phaser`` package on the M-Labs conda package label.
|
||||||
* From time to time and on request there may be pre-built binaries in the
|
|
||||||
``artiq-kc705-phaser`` package on the M-Labs conda package label.
|
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
.....
|
.....
|
||||||
|
|
|
@ -27,7 +27,7 @@ ARTIQ Anaconda development environment
|
||||||
$ git clone --recursive https://github.com/m-labs/artiq ~/artiq-dev/artiq
|
$ git clone --recursive https://github.com/m-labs/artiq ~/artiq-dev/artiq
|
||||||
$ cd ~/artiq-dev/artiq
|
$ cd ~/artiq-dev/artiq
|
||||||
|
|
||||||
Add ``-b release-X`` to the ``git clone`` command if you are building a stable branch of ARTIQ (the default will fetch the development ``master`` branch).
|
Add ``-b release-X`` to the ``git clone`` command if you are building a stable branch of ARTIQ. Replace ``X`` with the major release. The default will fetch the development ``master`` branch.
|
||||||
3. :ref:`Install Anaconda or Miniconda <install-anaconda>`
|
3. :ref:`Install Anaconda or Miniconda <install-anaconda>`
|
||||||
4. Create and activate a conda environment named ``artiq-dev`` and install the ``artiq-dev`` package which pulls in all the packages required to develop ARTIQ::
|
4. Create and activate a conda environment named ``artiq-dev`` and install the ``artiq-dev`` package which pulls in all the packages required to develop ARTIQ::
|
||||||
|
|
||||||
|
@ -37,10 +37,9 @@ ARTIQ Anaconda development environment
|
||||||
|
|
||||||
$ pip install -e .
|
$ pip install -e .
|
||||||
6. :ref:`Install Vivado <install-xilinx>`
|
6. :ref:`Install Vivado <install-xilinx>`
|
||||||
7. :ref:`Obtain and install the JTAG SPI flash proxy bitstream <install-bscan-spi>`
|
7. :ref:`Configure OpenOCD <setup-openocd>`
|
||||||
8. :ref:`Configure OpenOCD <setup-openocd>`
|
8. :ref:`Build target binaries <build-target-binaries>`
|
||||||
9. :ref:`Build target binaries <build-target-binaries>`
|
9. :ref:`Flash target binaries <flash-target-binaries>`
|
||||||
10. :ref:`Flash target binaries <flash-target-binaries>`
|
|
||||||
|
|
||||||
.. _install-from-source:
|
.. _install-from-source:
|
||||||
|
|
||||||
|
@ -90,22 +89,22 @@ and the ARTIQ kernels.
|
||||||
* Install LLVM and Clang: ::
|
* Install LLVM and Clang: ::
|
||||||
|
|
||||||
$ cd ~/artiq-dev
|
$ cd ~/artiq-dev
|
||||||
$ git clone -b artiq-3.9 https://github.com/m-labs/llvm-or1k
|
$ git clone -b artiq-4.0 https://github.com/m-labs/llvm-or1k
|
||||||
$ cd llvm-or1k
|
$ cd llvm-or1k
|
||||||
$ git clone -b artiq-3.9 https://github.com/m-labs/clang-or1k tools/clang
|
$ git clone -b artiq-4.0 https://github.com/m-labs/clang-or1k tools/clang
|
||||||
|
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
$ cd build
|
$ cd build
|
||||||
$ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON
|
$ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=OR1K -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON -DCLANG_ENABLE_ARCMT=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF
|
||||||
$ make -j4
|
$ make -j4
|
||||||
$ sudo make install
|
$ sudo make install
|
||||||
|
|
||||||
* Install Rust: ::
|
* Install Rust: ::
|
||||||
|
|
||||||
$ cd ~/artiq-dev
|
$ cd ~/artiq-dev
|
||||||
$ git clone -b artiq-1.20.0 https://github.com/m-labs/rust
|
$ git clone -b artiq-1.23.0 https://github.com/m-labs/rust
|
||||||
$ cd rust
|
$ cd rust
|
||||||
$ git submodule update --init
|
$ git submodule update --init --recursive
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
$ cd build
|
$ cd build
|
||||||
$ ../configure --prefix=/usr/local/rust-or1k --llvm-root=/usr/local/llvm-or1k --disable-manage-submodules --disable-docs
|
$ ../configure --prefix=/usr/local/rust-or1k --llvm-root=/usr/local/llvm-or1k --disable-manage-submodules --disable-docs
|
||||||
|
@ -113,14 +112,16 @@ and the ARTIQ kernels.
|
||||||
$ sudo chown $USER.$USER /usr/local/rust-or1k
|
$ sudo chown $USER.$USER /usr/local/rust-or1k
|
||||||
$ make install
|
$ make install
|
||||||
|
|
||||||
$ libs="libcore libstd_unicode liballoc liblibc_mini libunwind"
|
$ libs="core std_unicode alloc"
|
||||||
$ 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 ."
|
$ rustc="/usr/local/rust-or1k/bin/rustc --target or1k-unknown-none -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s -g --crate-type rlib -L ."
|
||||||
$ destdir="/usr/local/rust-or1k/lib/rustlib/or1k-unknown-none/lib/"
|
$ 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 ${rustc} ../src/${lib}/lib.rs; done
|
$ for lib in ${libs}; do ${rustc} --crate-name ${lib} ../src/lib${lib}/lib.rs; done
|
||||||
$ ${rustc} -Cpanic=abort ../src/libpanic_abort/lib.rs
|
$ ${rustc} --crate-name libc ../src/liblibc_mini/lib.rs
|
||||||
$ ${rustc} -Cpanic=unwind ../src/libpanic_unwind/lib.rs --cfg llvm_libunwind
|
$ ${rustc} --crate-name unwind ../src/libunwind/lib.rs
|
||||||
|
$ ${rustc} -Cpanic=abort --crate-name panic_abort ../src/libpanic_abort/lib.rs
|
||||||
|
$ ${rustc} -Cpanic=unwind --crate-name panic_unwind ../src/libpanic_unwind/lib.rs --cfg llvm_libunwind
|
||||||
$ mkdir -p ${destdir}
|
$ mkdir -p ${destdir}
|
||||||
$ cp *.rlib ${destdir}
|
$ cp *.rlib ${destdir}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ The conda package contains pre-built binaries that you can directly flash to you
|
||||||
|
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
Conda packages are supported for Linux (64-bit) and Windows (32- and 64-bit).
|
Conda packages are supported for Linux (64-bit) and Windows (64-bit).
|
||||||
Users of other operating systems (32-bit Linux, BSD, OSX ...) should and can :ref:`install from source <install-from-source>`.
|
Users of other operating systems (32-bit Linux or Windows, BSD, OSX ...) should and can :ref:`install from source <install-from-source>`.
|
||||||
|
|
||||||
.. _install-anaconda:
|
.. _install-anaconda:
|
||||||
|
|
||||||
|
@ -37,18 +37,18 @@ Installing the ARTIQ packages
|
||||||
|
|
||||||
First add the conda-forge repository containing ARTIQ dependencies to your conda configuration::
|
First add the conda-forge repository containing ARTIQ dependencies to your conda configuration::
|
||||||
|
|
||||||
$ conda config --add channels http://conda.anaconda.org/conda-forge/label/main
|
$ conda config --prepend channels http://conda.anaconda.org/conda-forge/label/main
|
||||||
|
|
||||||
Then add the M-Labs ``main`` Anaconda package repository containing stable releases and release candidates::
|
Then add the M-Labs ``main`` Anaconda package repository containing stable releases and release candidates::
|
||||||
|
|
||||||
$ conda config --add channels http://conda.anaconda.org/m-labs/label/main
|
$ conda config --prepend channels http://conda.anaconda.org/m-labs/label/main
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
To use the development versions of ARTIQ, also add the ``dev`` label (http://conda.anaconda.org/m-labs/label/dev).
|
To use the development versions of ARTIQ, also add the ``dev`` label (http://conda.anaconda.org/m-labs/label/dev).
|
||||||
Development versions are built for every change and contain more features, but are not as well-tested and are more likely to contain more bugs or inconsistencies than the releases in the ``main`` label.
|
Development versions are built for every change and contain more features, but are not as well-tested and are more likely to contain more bugs or inconsistencies than the releases in the ``main`` label.
|
||||||
|
|
||||||
Then prepare to create a new conda environment with the ARTIQ package and the matching binaries for your hardware:
|
Then prepare to create a new conda environment with the ARTIQ package and the matching binaries for your hardware:
|
||||||
choose a suitable name for the environment, for example ``artiq-main`` if you intend to track the main label or ``artiq-2016-04-01`` if you consider the environment a snapshot of ARTIQ on 2016-04-01.
|
choose a suitable name for the environment, for example ``artiq-main`` if you intend to track the main label, ``artiq-3`` for the 3.x release series, or ``artiq-2016-04-01`` if you consider the environment a snapshot of ARTIQ on 2016-04-01.
|
||||||
Choose the package containing the binaries for your hardware:
|
Choose the package containing the binaries for your hardware:
|
||||||
|
|
||||||
* ``artiq-kc705-nist_clock`` for the KC705 board with the NIST "clock" FMC backplane and AD9914 DDS chips.
|
* ``artiq-kc705-nist_clock`` for the KC705 board with the NIST "clock" FMC backplane and AD9914 DDS chips.
|
||||||
|
@ -112,6 +112,9 @@ The ``artiq`` or ``artiq-dev`` conda packages install ``openocd`` automatically
|
||||||
|
|
||||||
.. _setup-openocd:
|
.. _setup-openocd:
|
||||||
|
|
||||||
|
Configuring OpenOCD
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Some additional steps are necessary to ensure that OpenOCD can communicate with the FPGA board.
|
Some additional steps are necessary to ensure that OpenOCD can communicate with the FPGA board.
|
||||||
|
|
||||||
On Linux, first ensure that the current user belongs to the ``plugdev`` group. If it does not, run ``sudo adduser $USER plugdev`` and relogin. Afterwards::
|
On Linux, first ensure that the current user belongs to the ``plugdev`` group. If it does not, run ``sudo adduser $USER plugdev`` and relogin. Afterwards::
|
||||||
|
|
Loading…
Reference in New Issue