Skip to content

Commit

Permalink
Merge branch 'master' into scanwidget
Browse files Browse the repository at this point in the history
* master: (38 commits)
  hardware_testbench: better message when skipping
  test_spi: drain errors and be more strict on where we expect errors
  monkey-patch asyncio.proactor_events to handle ConnectionAbortedError on Windows. Closes #247
  test/rtio/Loopback: ensure loop_out is low before starting test
  test/rtio: raise exception when pulse is not received
  rtio: fix different address collision detection
  frontend/coreanalyzer: do not attempt to print obsolete decoded_dump attribute. Closes #324
  coredevice: put cache into separate file/device
  gui: delete log/applet docks instead of hiding them
  gui/moninj: make DDS widgets look less like buttons
  rtio: remove NOP suppression capability
  rtio/wishbone: make replace configurable
  exceptions: clarify RTIOBusy
  gateware/rtio: factor _BlindTransfer
  test_spi: break_realtime
  test_spi: simplify test, add collision vs busy test
  hardware_testbench: clean up artiq_core_exeption printing
  coredevice: fix _DDSGeneric __init__ args
  hardware_testbench: also print artiq_core_exeption
  rtio/core: fix syntax
  ...
jordens committed Mar 10, 2016
2 parents 81bc999 + a618a6d commit bc92034
Showing 42 changed files with 761 additions and 333 deletions.
6 changes: 5 additions & 1 deletion RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
@@ -11,4 +11,8 @@ Release notes
This requires reflashing the runtime and the flash storage filesystem image
or erase and rewrite its entries.
* RTIOCollisionError has been renamed to RTIOCollision

* the new API for DDS batches is:
with self.core_dds.batch:
...
with core_dds a device of type artiq.coredevice.dds.CoreDDS.
The dds_bus device should not be used anymore.
4 changes: 2 additions & 2 deletions artiq/coredevice/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from artiq.coredevice import exceptions, dds, spi
from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOSequenceError,
RTIOCollision, RTIOOverflow,
RTIOCollision, RTIOOverflow, RTIOBusy,
DDSBatchError, CacheError)
from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE,
PHASE_MODE_TRACKING)

__all__ = []
__all__ += ["RTIOUnderflow", "RTIOSequenceError", "RTIOCollision",
"RTIOOverflow", "DDSBatchError", "CacheError"]
"RTIOOverflow", "RTIOBusy", "DDSBatchError", "CacheError"]
__all__ += ["PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE",
"PHASE_MODE_TRACKING"]
63 changes: 38 additions & 25 deletions artiq/coredevice/analyzer.py
Original file line number Diff line number Diff line change
@@ -40,31 +40,32 @@ def decode_message(data):


DecodedDump = namedtuple(
"DecodedDump", "log_channel dds_channel dds_onehot_sel messages")
"DecodedDump", "log_channel dds_onehot_sel messages")


def decode_dump(data):
parts = struct.unpack(">IQbbbb", data[:16])
parts = struct.unpack(">IQbbb", data[:15])
(sent_bytes, total_byte_count,
overflow_occured, log_channel, dds_channel, dds_onehot_sel) = parts
overflow_occured, log_channel, dds_onehot_sel) = parts

if sent_bytes + 16 != len(data):
raise ValueError("analyzer dump has incorrect length")
expected_len = sent_bytes + 15
if expected_len != len(data):
raise ValueError("analyzer dump has incorrect length "
"(got {}, expected {})".format(
len(data), expected_len))
if overflow_occured:
logger.warning("analyzer FIFO overflow occured, "
"some messages have been lost")
if total_byte_count > sent_bytes:
logger.info("analyzer ring buffer has wrapped %d times",
total_byte_count//sent_bytes)

position = 16
position = 15
messages = []
for _ in range(sent_bytes//32):
messages.append(decode_message(data[position:position+32]))
position += 32
return DecodedDump(log_channel,
dds_channel, bool(dds_onehot_sel),
messages)
return DecodedDump(log_channel, bool(dds_onehot_sel), messages)


def vcd_codes():
@@ -299,21 +300,31 @@ def get_vcd_log_channels(log_channel, messages):
return vcd_log_channels


def get_ref_period(devices):
def get_single_device_argument(devices, module, cls, argument):
ref_period = None
for desc in devices.values():
if isinstance(desc, dict) and desc["type"] == "local":
if (desc["module"] == "artiq.coredevice.core"
and desc["class"] == "Core"):
if (desc["module"] == module
and desc["class"] == cls):
if ref_period is None:
ref_period = desc["arguments"]["ref_period"]
ref_period = desc["arguments"][argument]
else:
return None # more than one core device found
return None # more than one device found
return ref_period


def get_ref_period(devices):
return get_single_device_argument(devices, "artiq.coredevice.core",
"Core", "ref_period")


def get_dds_sysclk(devices):
return get_single_device_argument(devices, "artiq.coredevice.core",
"CoreDDS", "sysclk")


def create_channel_handlers(vcd_manager, devices, ref_period,
dds_channel, dds_onehot_sel):
dds_sysclk, dds_onehot_sel):
channel_handlers = dict()
for name, desc in sorted(devices.items(), key=itemgetter(0)):
if isinstance(desc, dict) and desc["type"] == "local":
@@ -327,19 +338,17 @@ def create_channel_handlers(vcd_manager, devices, ref_period,
channel_handlers[channel] = TTLClockGenHandler(vcd_manager, name, ref_period)
if (desc["module"] == "artiq.coredevice.dds"
and desc["class"] in {"AD9858", "AD9914"}):
sysclk = desc["arguments"]["sysclk"]
dds_channel_ddsbus = desc["arguments"]["channel"]
if dds_channel in channel_handlers:
dds_handler = channel_handlers[dds_channel]
dds_bus_channel = desc["arguments"]["bus_channel"]
dds_channel = desc["arguments"]["channel"]
if dds_bus_channel in channel_handlers:
dds_handler = channel_handlers[dds_bus_channel]
if dds_handler.dds_type != desc["class"]:
raise ValueError("All DDS channels must have the same type")
if dds_handler.sysclk != sysclk:
raise ValueError("All DDS channels must have the same sysclk")
else:
dds_handler = DDSHandler(vcd_manager, desc["class"],
dds_onehot_sel, sysclk)
channel_handlers[dds_channel] = dds_handler
dds_handler.add_dds_channel(name, dds_channel_ddsbus)
dds_sysclk, dds_onehot_sel)
channel_handlers[dds_bus_channel] = dds_handler
dds_handler.add_dds_channel(name, dds_channel)
return channel_handlers


@@ -355,12 +364,16 @@ def decoded_dump_to_vcd(fileobj, devices, dump):
else:
logger.warning("unable to determine core device ref_period")
ref_period = 1e-9 # guess
dds_sysclk = get_dds_sysclk(devices)
if dds_sysclk is None:
logger.warning("unable to determine DDS sysclk")
dds_sysclk = 3e9 # guess

messages = sorted(dump.messages, key=get_message_time)

channel_handlers = create_channel_handlers(
vcd_manager, devices, ref_period,
dump.dds_channel, dump.dds_onehot_sel)
dds_sysclk, dump.dds_onehot_sel)
vcd_log_channels = get_vcd_log_channels(dump.log_channel, messages)
channel_handlers[dump.log_channel] = LogHandler(vcd_manager, vcd_log_channels)
slack = vcd_manager.get_channel("rtio_slack", 64)
45 changes: 45 additions & 0 deletions artiq/coredevice/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from artiq.language.core import *
from artiq.language.types import *


@syscall
def cache_get(key: TStr) -> TList(TInt32):
raise NotImplementedError("syscall not simulated")

@syscall
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
raise NotImplementedError("syscall not simulated")


class CoreCache:
"""Core device cache access"""
def __init__(self, dmgr, core_device="core"):
self.core = dmgr.get(core_device)

@kernel
def get(self, key):
"""Extract a value from the core device cache.
After a value is extracted, it cannot be replaced with another value using
:meth:`put` 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
"""
return cache_get(key)

@kernel
def put(self, key, value):
"""Put a value into the core device cache. The value will persist until reboot.
To remove a value from the cache, call :meth:`put` with an empty list.
:param str key: cache key
:param list value: a list of 32-bit integers
"""
cache_put(key, value)
37 changes: 1 addition & 36 deletions artiq/coredevice/core.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ def shorten_path(path):
lines = [shorten_path(path) for path in diagnostic.render(colored=colored)]
return "\n".join(lines)

colors_supported = (os.name == 'posix')
colors_supported = os.name == "posix"
class _DiagnosticEngine(diagnostic.Engine):
def render_diagnostic(self, diagnostic):
sys.stderr.write(_render_diagnostic(diagnostic, colored=colors_supported) + "\n")
@@ -41,13 +41,6 @@ def __str__(self):
def rtio_get_counter() -> TInt64:
raise NotImplementedError("syscall not simulated")

@syscall
def cache_get(key: TStr) -> TList(TInt32):
raise NotImplementedError("syscall not simulated")

@syscall
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
raise NotImplementedError("syscall not simulated")

class Core:
"""Core device driver.
@@ -126,31 +119,3 @@ def break_realtime(self):
min_now = rtio_get_counter() + 125000
if now_mu() < min_now:
at_mu(min_now)

@kernel
def get_cache(self, key):
"""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
"""
return cache_get(key)

@kernel
def put_cache(self, key, value):
"""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)
58 changes: 33 additions & 25 deletions artiq/coredevice/dds.py
Original file line number Diff line number Diff line change
@@ -11,46 +11,52 @@


@syscall
def dds_init(time_mu: TInt64, channel: TInt32) -> TNone:
def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")

@syscall
def dds_batch_enter(time_mu: TInt64) -> TNone:
def dds_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32,
pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")

@syscall
def dds_batch_exit() -> TNone:
def dds_batch_enter(time_mu: TInt64) -> TNone:
raise NotImplementedError("syscall not simulated")

@syscall
def dds_set(time_mu: TInt64, channel: TInt32, ftw: TInt32,
pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
def dds_batch_exit() -> TNone:
raise NotImplementedError("syscall not simulated")


class _BatchContextManager:
def __init__(self, dds_bus):
self.dds_bus = dds_bus
def __init__(self, core_dds):
self.core_dds = core_dds
self.core = self.core_dds.core

@kernel
def __enter__(self):
self.dds_bus.batch_enter()
self.core_dds.dds_batch_enter()

@kernel
def __exit__(self, type, value, traceback):
self.dds_bus.batch_exit()
self.core_dds.dds_batch_exit()


class DDSBus:
"""Core device Direct Digital Synthesis (DDS) bus batching driver.
class CoreDDS:
"""Core device Direct Digital Synthesis (DDS) driver.
Gives access to the DDS functionality of the core device.
Manages batching of DDS commands on a DDS shared bus."""
def __init__(self, dmgr):
self.core = dmgr.get("core")
:param sysclk: DDS system frequency. The DDS system clock must be a
phase-locked multiple of the RTIO clock.
"""
def __init__(self, dmgr, sysclk, core_device="core"):
self.core = dmgr.get(core_device)
self.sysclk = sysclk
self.batch = _BatchContextManager(self)

@kernel
def batch_enter(self):
def dds_batch_enter(self):
"""Starts a DDS command batch. All DDS commands are buffered
after this call, until ``batch_exit`` is called.
@@ -59,26 +65,27 @@ def batch_enter(self):
dds_batch_enter(now_mu())

@kernel
def batch_exit(self):
def dds_batch_exit(self):
"""Ends a DDS command batch. All buffered DDS commands are issued
on the bus."""
dds_batch_exit()


class _DDSGeneric:
"""Core device Direct Digital Synthesis (DDS) driver.
"""Core device Direct Digital Synthesis (DDS) channel driver.
Controls one DDS channel managed directly by the core device's runtime.
This class should not be used directly, instead, use the chip-specific
drivers such as ``AD9858`` and ``AD9914``.
:param sysclk: DDS system frequency.
:param bus: name of the DDS bus device that this DDS is connected to.
:param channel: channel number of the DDS device to control.
"""
def __init__(self, dmgr, sysclk, channel):
self.core = dmgr.get("core")
self.sysclk = sysclk
def __init__(self, dmgr, bus_channel, channel, core_dds_device="core_dds"):
self.core_dds = dmgr.get(core_dds_device)
self.core = self.core_dds.core
self.bus_channel = bus_channel
self.channel = channel
self.phase_mode = PHASE_MODE_CONTINUOUS

@@ -87,14 +94,14 @@ def frequency_to_ftw(self, frequency):
"""Returns the frequency tuning word corresponding to the given
frequency.
"""
return round(int(2, width=64)**32*frequency/self.sysclk)
return round(int(2, width=64)**32*frequency/self.core_dds.sysclk)

@portable
def ftw_to_frequency(self, ftw):
"""Returns the frequency corresponding to the given frequency tuning
word.
"""
return ftw*self.sysclk/int(2, width=64)**32
return ftw*self.core_dds.sysclk/int(2, width=64)**32

@portable
def turns_to_pow(self, turns):
@@ -124,7 +131,7 @@ def init(self):
"""Resets and initializes the DDS channel.
The runtime does this for all channels upon core device startup."""
dds_init(now_mu(), self.channel)
dds_init(now_mu(), self.bus_channel, self.channel)

@kernel
def set_phase_mode(self, phase_mode):
@@ -163,7 +170,8 @@ def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT,
"""
if phase_mode == _PHASE_MODE_DEFAULT:
phase_mode = self.phase_mode
dds_set(now_mu(), self.channel, frequency, phase, phase_mode, amplitude)
dds_set(now_mu(), self.bus_channel, self.channel,
frequency, phase, phase_mode, amplitude)

@kernel
def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT,
Loading

0 comments on commit bc92034

Please sign in to comment.