2015-12-31 22:23:13 +08:00
|
|
|
import os, sys
|
2015-08-07 16:44:49 +08:00
|
|
|
|
|
|
|
from pythonparser import diagnostic
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2014-12-03 18:20:30 +08:00
|
|
|
from artiq.language.core import *
|
2015-08-11 00:25:48 +08:00
|
|
|
from artiq.language.types import *
|
2015-08-20 03:37:31 +08:00
|
|
|
from artiq.language.units import *
|
2014-12-03 18:20:30 +08:00
|
|
|
|
2015-11-24 17:32:04 +08:00
|
|
|
from artiq.compiler.module import Module
|
|
|
|
from artiq.compiler.embedding import Stitcher
|
2015-08-07 16:44:49 +08:00
|
|
|
from artiq.compiler.targets import OR1KTarget
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2015-08-07 16:44:49 +08:00
|
|
|
# Import for side effects (creating the exception classes).
|
|
|
|
from artiq.coredevice import exceptions
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2016-01-16 09:28:26 +08:00
|
|
|
|
|
|
|
def _render_diagnostic(diagnostic, colored):
|
2015-12-31 22:23:13 +08:00
|
|
|
def shorten_path(path):
|
|
|
|
return path.replace(os.path.normpath(os.path.join(__file__, "..", "..")), "<artiq>")
|
2016-01-16 09:28:26 +08:00
|
|
|
lines = [shorten_path(path) for path in diagnostic.render(colored)]
|
2015-12-31 22:23:13 +08:00
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
|
|
class _DiagnosticEngine(diagnostic.Engine):
|
2016-01-04 22:11:54 +08:00
|
|
|
def render_diagnostic(self, diagnostic):
|
2016-01-16 09:28:26 +08:00
|
|
|
sys.stderr.write(_render_diagnostic(diagnostic, colored=True) + "\n")
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2015-08-07 16:44:49 +08:00
|
|
|
class CompileError(Exception):
|
2015-09-01 12:52:39 +08:00
|
|
|
def __init__(self, diagnostic):
|
|
|
|
self.diagnostic = diagnostic
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
# Prepend a newline so that the message shows up on after
|
|
|
|
# exception class name printed by Python.
|
2016-01-16 09:28:26 +08:00
|
|
|
return "\n" + _render_diagnostic(self.diagnostic, colored=True)
|
2014-11-03 18:44:30 +08:00
|
|
|
|
2015-08-11 00:25:48 +08:00
|
|
|
|
|
|
|
@syscall
|
|
|
|
def rtio_get_counter() -> TInt64:
|
|
|
|
raise NotImplementedError("syscall not simulated")
|
|
|
|
|
2016-01-10 21:04:55 +08:00
|
|
|
@syscall
|
2016-01-10 21:08:26 +08:00
|
|
|
def cache_get(key: TStr) -> TList(TInt32):
|
2016-01-10 21:04:55 +08:00
|
|
|
raise NotImplementedError("syscall not simulated")
|
|
|
|
|
|
|
|
@syscall
|
2016-01-11 04:01:20 +08:00
|
|
|
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
|
2016-01-10 21:04:55 +08:00
|
|
|
raise NotImplementedError("syscall not simulated")
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class Core:
|
2015-10-06 18:12:57 +08:00
|
|
|
"""Core device driver.
|
|
|
|
|
|
|
|
:param ref_period: period of the reference clock for the RTIO subsystem.
|
|
|
|
On platforms that use clock multiplication and SERDES-based PHYs,
|
|
|
|
this is the period after multiplication. For example, with a RTIO core
|
|
|
|
clocked at 125MHz and a SERDES multiplication factor of 8, the
|
|
|
|
reference period is 1ns.
|
|
|
|
The time machine unit is equal to this period.
|
|
|
|
:param external_clock: whether the core device should switch to its
|
|
|
|
external RTIO clock input instead of using its internal oscillator.
|
|
|
|
:param comm_device: name of the device used for communications.
|
|
|
|
"""
|
2015-12-20 22:05:52 +08:00
|
|
|
def __init__(self, dmgr, ref_period, external_clock=False, comm_device="comm"):
|
2015-07-14 04:08:20 +08:00
|
|
|
self.ref_period = ref_period
|
|
|
|
self.external_clock = external_clock
|
2015-10-06 18:12:57 +08:00
|
|
|
self.comm = dmgr.get(comm_device)
|
2014-12-03 18:20:30 +08:00
|
|
|
|
2015-05-02 23:41:49 +08:00
|
|
|
self.first_run = True
|
2014-11-21 04:38:52 +08:00
|
|
|
self.core = self
|
2015-03-13 21:55:18 +08:00
|
|
|
self.comm.core = self
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2015-12-19 06:41:32 +08:00
|
|
|
def compile(self, function, args, kwargs, set_result=None, with_attr_writeback=True):
|
2015-08-07 16:44:49 +08:00
|
|
|
try:
|
2015-12-31 22:23:13 +08:00
|
|
|
engine = _DiagnosticEngine(all_errors_are_fatal=True)
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2015-08-07 16:44:49 +08:00
|
|
|
stitcher = Stitcher(engine=engine)
|
2015-12-19 05:26:18 +08:00
|
|
|
stitcher.stitch_call(function, args, kwargs, set_result)
|
2015-08-11 01:25:57 +08:00
|
|
|
stitcher.finalize()
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2015-08-31 23:59:33 +08:00
|
|
|
module = Module(stitcher, ref_period=self.ref_period)
|
2015-08-09 02:47:20 +08:00
|
|
|
target = OR1KTarget()
|
2014-09-17 17:06:51 +08:00
|
|
|
|
2015-08-10 20:12:22 +08:00
|
|
|
library = target.compile_and_link([module])
|
|
|
|
stripped_library = target.strip(library)
|
|
|
|
|
2015-08-26 12:56:01 +08:00
|
|
|
return stitcher.object_map, stripped_library, \
|
2015-08-10 20:12:22 +08:00
|
|
|
lambda addresses: target.symbolize(library, addresses)
|
2015-08-07 16:44:49 +08:00
|
|
|
except diagnostic.Error as error:
|
2015-09-01 12:52:39 +08:00
|
|
|
raise CompileError(error.diagnostic) from error
|
2014-10-29 17:09:45 +08:00
|
|
|
|
2015-08-07 16:44:49 +08:00
|
|
|
def run(self, function, args, kwargs):
|
2015-12-19 05:26:18 +08:00
|
|
|
result = None
|
|
|
|
def set_result(new_result):
|
|
|
|
nonlocal result
|
|
|
|
result = new_result
|
|
|
|
|
|
|
|
object_map, kernel_library, symbolizer = self.compile(function, args, kwargs, set_result)
|
2015-08-09 07:17:19 +08:00
|
|
|
|
2015-05-02 23:41:49 +08:00
|
|
|
if self.first_run:
|
|
|
|
self.comm.check_ident()
|
|
|
|
self.comm.switch_clock(self.external_clock)
|
2015-08-07 16:44:49 +08:00
|
|
|
self.first_run = False
|
|
|
|
|
2015-08-10 20:12:22 +08:00
|
|
|
self.comm.load(kernel_library)
|
2015-08-07 16:44:49 +08:00
|
|
|
self.comm.run()
|
2015-08-26 12:56:01 +08:00
|
|
|
self.comm.serve(object_map, symbolizer)
|
2014-11-21 04:38:52 +08:00
|
|
|
|
2015-12-19 05:26:18 +08:00
|
|
|
return result
|
|
|
|
|
2015-02-19 00:56:30 +08:00
|
|
|
@kernel
|
2015-07-02 04:22:53 +08:00
|
|
|
def get_rtio_counter_mu(self):
|
2015-08-11 00:25:48 +08:00
|
|
|
return rtio_get_counter()
|
2015-02-19 00:56:30 +08:00
|
|
|
|
2014-11-21 04:38:52 +08:00
|
|
|
@kernel
|
2015-05-03 20:42:42 +08:00
|
|
|
def break_realtime(self):
|
2015-10-06 18:12:57 +08:00
|
|
|
"""Set the timeline to the current value of the hardware RTIO counter
|
|
|
|
plus a margin of 125000 machine units."""
|
2015-09-27 23:22:13 +08:00
|
|
|
min_now = rtio_get_counter() + 125000
|
2015-08-17 23:41:21 +08:00
|
|
|
if now_mu() < min_now:
|
|
|
|
at_mu(min_now)
|
2016-01-10 21:04:55 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def get_cache(self, key):
|
2016-01-17 00:38:55 +08:00
|
|
|
"""Extract a value from the core device cache.
|
|
|
|
After a value is extracted, it cannot be replaced with another value using
|
|
|
|
:meth:`put_cache` until all kernel functions finish executing; attempting
|
|
|
|
to replace it will result in a :class:`artiq.coredevice.exceptions.CacheError`.
|
|
|
|
|
|
|
|
If the cache does not contain any value associated with ``key``, an empty list
|
|
|
|
is returned.
|
|
|
|
|
|
|
|
The value is not copied, so mutating it will change what's stored in the cache.
|
|
|
|
|
|
|
|
:param str key: cache key
|
|
|
|
:return: a list of 32-bit integers
|
|
|
|
"""
|
2016-01-10 21:04:55 +08:00
|
|
|
return cache_get(key)
|
|
|
|
|
|
|
|
@kernel
|
|
|
|
def put_cache(self, key, value):
|
2016-01-17 00:38:55 +08:00
|
|
|
"""Put a value into the core device cache. The value will persist until reboot.
|
|
|
|
|
|
|
|
To remove a value from the cache, call :meth:`put_cache` with an empty list.
|
|
|
|
|
|
|
|
:param str key: cache key
|
|
|
|
:param list value: a list of 32-bit integers
|
|
|
|
"""
|
|
|
|
cache_put(key, value)
|