forked from M-Labs/artiq
1
0
Fork 0

Merge branch 'master' into scanwidget

* 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
  ...
This commit is contained in:
Robert Jördens 2016-03-10 12:46:07 +01:00
commit bc9203457e
42 changed files with 763 additions and 335 deletions

View File

@ -11,4 +11,8 @@ Release notes
This requires reflashing the runtime and the flash storage filesystem image This requires reflashing the runtime and the flash storage filesystem image
or erase and rewrite its entries. or erase and rewrite its entries.
* RTIOCollisionError has been renamed to RTIOCollision * 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.

View File

@ -1,12 +1,12 @@
from artiq.coredevice import exceptions, dds, spi from artiq.coredevice import exceptions, dds, spi
from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOSequenceError, from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOSequenceError,
RTIOCollision, RTIOOverflow, RTIOCollision, RTIOOverflow, RTIOBusy,
DDSBatchError, CacheError) DDSBatchError, CacheError)
from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE, from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE,
PHASE_MODE_TRACKING) PHASE_MODE_TRACKING)
__all__ = [] __all__ = []
__all__ += ["RTIOUnderflow", "RTIOSequenceError", "RTIOCollision", __all__ += ["RTIOUnderflow", "RTIOSequenceError", "RTIOCollision",
"RTIOOverflow", "DDSBatchError", "CacheError"] "RTIOOverflow", "RTIOBusy", "DDSBatchError", "CacheError"]
__all__ += ["PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", __all__ += ["PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE",
"PHASE_MODE_TRACKING"] "PHASE_MODE_TRACKING"]

View File

@ -40,16 +40,19 @@ def decode_message(data):
DecodedDump = namedtuple( DecodedDump = namedtuple(
"DecodedDump", "log_channel dds_channel dds_onehot_sel messages") "DecodedDump", "log_channel dds_onehot_sel messages")
def decode_dump(data): def decode_dump(data):
parts = struct.unpack(">IQbbbb", data[:16]) parts = struct.unpack(">IQbbb", data[:15])
(sent_bytes, total_byte_count, (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): expected_len = sent_bytes + 15
raise ValueError("analyzer dump has incorrect length") if expected_len != len(data):
raise ValueError("analyzer dump has incorrect length "
"(got {}, expected {})".format(
len(data), expected_len))
if overflow_occured: if overflow_occured:
logger.warning("analyzer FIFO overflow occured, " logger.warning("analyzer FIFO overflow occured, "
"some messages have been lost") "some messages have been lost")
@ -57,14 +60,12 @@ def decode_dump(data):
logger.info("analyzer ring buffer has wrapped %d times", logger.info("analyzer ring buffer has wrapped %d times",
total_byte_count//sent_bytes) total_byte_count//sent_bytes)
position = 16 position = 15
messages = [] messages = []
for _ in range(sent_bytes//32): for _ in range(sent_bytes//32):
messages.append(decode_message(data[position:position+32])) messages.append(decode_message(data[position:position+32]))
position += 32 position += 32
return DecodedDump(log_channel, return DecodedDump(log_channel, bool(dds_onehot_sel), messages)
dds_channel, bool(dds_onehot_sel),
messages)
def vcd_codes(): def vcd_codes():
@ -299,21 +300,31 @@ def get_vcd_log_channels(log_channel, messages):
return vcd_log_channels return vcd_log_channels
def get_ref_period(devices): def get_single_device_argument(devices, module, cls, argument):
ref_period = None ref_period = None
for desc in devices.values(): for desc in devices.values():
if isinstance(desc, dict) and desc["type"] == "local": if isinstance(desc, dict) and desc["type"] == "local":
if (desc["module"] == "artiq.coredevice.core" if (desc["module"] == module
and desc["class"] == "Core"): and desc["class"] == cls):
if ref_period is None: if ref_period is None:
ref_period = desc["arguments"]["ref_period"] ref_period = desc["arguments"][argument]
else: else:
return None # more than one core device found return None # more than one device found
return ref_period 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, def create_channel_handlers(vcd_manager, devices, ref_period,
dds_channel, dds_onehot_sel): dds_sysclk, dds_onehot_sel):
channel_handlers = dict() channel_handlers = dict()
for name, desc in sorted(devices.items(), key=itemgetter(0)): for name, desc in sorted(devices.items(), key=itemgetter(0)):
if isinstance(desc, dict) and desc["type"] == "local": 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) channel_handlers[channel] = TTLClockGenHandler(vcd_manager, name, ref_period)
if (desc["module"] == "artiq.coredevice.dds" if (desc["module"] == "artiq.coredevice.dds"
and desc["class"] in {"AD9858", "AD9914"}): and desc["class"] in {"AD9858", "AD9914"}):
sysclk = desc["arguments"]["sysclk"] dds_bus_channel = desc["arguments"]["bus_channel"]
dds_channel_ddsbus = desc["arguments"]["channel"] dds_channel = desc["arguments"]["channel"]
if dds_channel in channel_handlers: if dds_bus_channel in channel_handlers:
dds_handler = channel_handlers[dds_channel] dds_handler = channel_handlers[dds_bus_channel]
if dds_handler.dds_type != desc["class"]: if dds_handler.dds_type != desc["class"]:
raise ValueError("All DDS channels must have the same type") 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: else:
dds_handler = DDSHandler(vcd_manager, desc["class"], dds_handler = DDSHandler(vcd_manager, desc["class"],
dds_onehot_sel, sysclk) dds_sysclk, dds_onehot_sel)
channel_handlers[dds_channel] = dds_handler channel_handlers[dds_bus_channel] = dds_handler
dds_handler.add_dds_channel(name, dds_channel_ddsbus) dds_handler.add_dds_channel(name, dds_channel)
return channel_handlers return channel_handlers
@ -355,12 +364,16 @@ def decoded_dump_to_vcd(fileobj, devices, dump):
else: else:
logger.warning("unable to determine core device ref_period") logger.warning("unable to determine core device ref_period")
ref_period = 1e-9 # guess 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) messages = sorted(dump.messages, key=get_message_time)
channel_handlers = create_channel_handlers( channel_handlers = create_channel_handlers(
vcd_manager, devices, ref_period, 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) vcd_log_channels = get_vcd_log_channels(dump.log_channel, messages)
channel_handlers[dump.log_channel] = LogHandler(vcd_manager, vcd_log_channels) channel_handlers[dump.log_channel] = LogHandler(vcd_manager, vcd_log_channels)
slack = vcd_manager.get_channel("rtio_slack", 64) slack = vcd_manager.get_channel("rtio_slack", 64)

45
artiq/coredevice/cache.py Normal file
View File

@ -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)

View File

@ -22,7 +22,7 @@ def _render_diagnostic(diagnostic, colored):
lines = [shorten_path(path) for path in diagnostic.render(colored=colored)] lines = [shorten_path(path) for path in diagnostic.render(colored=colored)]
return "\n".join(lines) return "\n".join(lines)
colors_supported = (os.name == 'posix') colors_supported = os.name == "posix"
class _DiagnosticEngine(diagnostic.Engine): class _DiagnosticEngine(diagnostic.Engine):
def render_diagnostic(self, diagnostic): def render_diagnostic(self, diagnostic):
sys.stderr.write(_render_diagnostic(diagnostic, colored=colors_supported) + "\n") sys.stderr.write(_render_diagnostic(diagnostic, colored=colors_supported) + "\n")
@ -41,13 +41,6 @@ class CompileError(Exception):
def rtio_get_counter() -> TInt64: def rtio_get_counter() -> TInt64:
raise NotImplementedError("syscall not simulated") 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: class Core:
"""Core device driver. """Core device driver.
@ -126,31 +119,3 @@ class Core:
min_now = rtio_get_counter() + 125000 min_now = rtio_get_counter() + 125000
if now_mu() < min_now: if now_mu() < min_now:
at_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)

View File

@ -11,7 +11,12 @@ PHASE_MODE_TRACKING = 2
@syscall @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_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32,
pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated") raise NotImplementedError("syscall not simulated")
@syscall @syscall
@ -22,35 +27,36 @@ def dds_batch_enter(time_mu: TInt64) -> TNone:
def dds_batch_exit() -> TNone: def dds_batch_exit() -> TNone:
raise NotImplementedError("syscall not simulated") raise NotImplementedError("syscall not simulated")
@syscall
def dds_set(time_mu: TInt64, channel: TInt32, ftw: TInt32,
pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")
class _BatchContextManager: class _BatchContextManager:
def __init__(self, dds_bus): def __init__(self, core_dds):
self.dds_bus = dds_bus self.core_dds = core_dds
self.core = self.core_dds.core
@kernel @kernel
def __enter__(self): def __enter__(self):
self.dds_bus.batch_enter() self.core_dds.dds_batch_enter()
@kernel @kernel
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
self.dds_bus.batch_exit() self.core_dds.dds_batch_exit()
class DDSBus: class CoreDDS:
"""Core device Direct Digital Synthesis (DDS) bus batching driver. """Core device Direct Digital Synthesis (DDS) driver.
Manages batching of DDS commands on a DDS shared bus.""" Gives access to the DDS functionality of the core device.
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) self.batch = _BatchContextManager(self)
@kernel @kernel
def batch_enter(self): def dds_batch_enter(self):
"""Starts a DDS command batch. All DDS commands are buffered """Starts a DDS command batch. All DDS commands are buffered
after this call, until ``batch_exit`` is called. after this call, until ``batch_exit`` is called.
@ -59,26 +65,27 @@ class DDSBus:
dds_batch_enter(now_mu()) dds_batch_enter(now_mu())
@kernel @kernel
def batch_exit(self): def dds_batch_exit(self):
"""Ends a DDS command batch. All buffered DDS commands are issued """Ends a DDS command batch. All buffered DDS commands are issued
on the bus.""" on the bus."""
dds_batch_exit() dds_batch_exit()
class _DDSGeneric: 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. Controls one DDS channel managed directly by the core device's runtime.
This class should not be used directly, instead, use the chip-specific This class should not be used directly, instead, use the chip-specific
drivers such as ``AD9858`` and ``AD9914``. 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. :param channel: channel number of the DDS device to control.
""" """
def __init__(self, dmgr, sysclk, channel): def __init__(self, dmgr, bus_channel, channel, core_dds_device="core_dds"):
self.core = dmgr.get("core") self.core_dds = dmgr.get(core_dds_device)
self.sysclk = sysclk self.core = self.core_dds.core
self.bus_channel = bus_channel
self.channel = channel self.channel = channel
self.phase_mode = PHASE_MODE_CONTINUOUS self.phase_mode = PHASE_MODE_CONTINUOUS
@ -87,14 +94,14 @@ class _DDSGeneric:
"""Returns the frequency tuning word corresponding to the given """Returns the frequency tuning word corresponding to the given
frequency. frequency.
""" """
return round(int(2, width=64)**32*frequency/self.sysclk) return round(int(2, width=64)**32*frequency/self.core_dds.sysclk)
@portable @portable
def ftw_to_frequency(self, ftw): def ftw_to_frequency(self, ftw):
"""Returns the frequency corresponding to the given frequency tuning """Returns the frequency corresponding to the given frequency tuning
word. word.
""" """
return ftw*self.sysclk/int(2, width=64)**32 return ftw*self.core_dds.sysclk/int(2, width=64)**32
@portable @portable
def turns_to_pow(self, turns): def turns_to_pow(self, turns):
@ -124,7 +131,7 @@ class _DDSGeneric:
"""Resets and initializes the DDS channel. """Resets and initializes the DDS channel.
The runtime does this for all channels upon core device startup.""" 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 @kernel
def set_phase_mode(self, phase_mode): def set_phase_mode(self, phase_mode):
@ -163,7 +170,8 @@ class _DDSGeneric:
""" """
if phase_mode == _PHASE_MODE_DEFAULT: if phase_mode == _PHASE_MODE_DEFAULT:
phase_mode = self.phase_mode 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 @kernel
def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT,

View File

@ -98,6 +98,18 @@ class RTIOCollision(Exception):
""" """
artiq_builtin = True artiq_builtin = True
class RTIOBusy(Exception):
"""Raised when at least one output event could not be executed because
the given channel was already busy executing a previous event.
This exception is raised late: after the error condition occurred. More
specifically it is raised on submitting an event on the same channel after
the execution of the faulty event was attempted.
The offending event was discarded.
"""
artiq_builtin = True
class RTIOOverflow(Exception): class RTIOOverflow(Exception):
"""Raised when at least one event could not be registered into the RTIO """Raised when at least one event could not be registered into the RTIO
input FIFO because it was full (CPU not reading fast enough). input FIFO because it was full (CPU not reading fast enough).

View File

@ -34,8 +34,8 @@ class PCA9548:
On the KC705, this chip is used for selecting the I2C buses on the two FMC On the KC705, this chip is used for selecting the I2C buses on the two FMC
connectors. HPC=1, LPC=2. connectors. HPC=1, LPC=2.
""" """
def __init__(self, dmgr, busno=0, address=0xe8): def __init__(self, dmgr, busno=0, address=0xe8, core_device="core"):
self.core = dmgr.get("core") self.core = dmgr.get(core_device)
self.busno = busno self.busno = busno
self.address = address self.address = address
@ -77,8 +77,8 @@ class TCA6424A:
On the NIST QC2 hardware, this chip is used for switching the directions On the NIST QC2 hardware, this chip is used for switching the directions
of TTL buffers.""" of TTL buffers."""
def __init__(self, dmgr, busno=0, address=0x44): def __init__(self, dmgr, busno=0, address=0x44, core_device="core"):
self.core = dmgr.get("core") self.core = dmgr.get(core_device)
self.busno = busno self.busno = busno
self.address = address self.address = address

View File

@ -1,5 +1,5 @@
from artiq.language.core import (kernel, portable, seconds_to_mu, now_mu, from artiq.language.core import (kernel, portable, seconds_to_mu, now_mu,
delay_mu, int) delay_mu, int, mu_to_seconds)
from artiq.language.units import MHz from artiq.language.units import MHz
from artiq.coredevice.rtio import rtio_output, rtio_input_data from artiq.coredevice.rtio import rtio_output, rtio_input_data
@ -40,8 +40,8 @@ class SPIMaster:
:param channel: RTIO channel number of the SPI bus to control. :param channel: RTIO channel number of the SPI bus to control.
""" """
def __init__(self, dmgr, channel): def __init__(self, dmgr, channel, core_device="core"):
self.core = dmgr.get("core") self.core = dmgr.get(core_device)
self.ref_period_mu = seconds_to_mu(self.core.coarse_ref_period, self.ref_period_mu = seconds_to_mu(self.core.coarse_ref_period,
self.core) self.core)
self.channel = channel self.channel = channel
@ -58,7 +58,7 @@ class SPIMaster:
@portable @portable
def frequency_to_div(self, f): def frequency_to_div(self, f):
return int(1/(f*self.ref_period)) + 1 return int(1/(f*mu_to_seconds(self.ref_period_mu))) + 1
@kernel @kernel
def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz): def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz):

View File

@ -10,8 +10,8 @@ class TTLOut:
:param channel: channel number :param channel: channel number
""" """
def __init__(self, dmgr, channel): def __init__(self, dmgr, channel, core_device="core"):
self.core = dmgr.get("core") self.core = dmgr.get(core_device)
self.channel = channel self.channel = channel
# in RTIO cycles # in RTIO cycles
@ -82,8 +82,8 @@ class TTLInOut:
:param channel: channel number :param channel: channel number
""" """
def __init__(self, dmgr, channel): def __init__(self, dmgr, channel, core_device="core"):
self.core = dmgr.get("core") self.core = dmgr.get(core_device)
self.channel = channel self.channel = channel
# in RTIO cycles # in RTIO cycles
@ -232,8 +232,8 @@ class TTLClockGen:
:param channel: channel number :param channel: channel number
""" """
def __init__(self, dmgr, channel): def __init__(self, dmgr, channel, core_device="core"):
self.core = dmgr.get("core") self.core = dmgr.get(core_device)
self.channel = channel self.channel = channel
# in RTIO cycles # in RTIO cycles

View File

@ -48,7 +48,6 @@ def main():
decoded_dump = decode_dump(dump) decoded_dump = decode_dump(dump)
if args.print_decoded: if args.print_decoded:
print("Log channel:", decoded_dump.log_channel) print("Log channel:", decoded_dump.log_channel)
print("DDS channel:", decoded_dump.dds_channel)
print("DDS one-hot:", decoded_dump.dds_onehot_sel) print("DDS one-hot:", decoded_dump.dds_onehot_sel)
for message in decoded_dump.messages: for message in decoded_dump.messages:
print(message) print(message)

View File

@ -54,6 +54,26 @@ class _RTIOCounter(Module):
self.comb += gt.i.eq(self.value_rtio), self.value_sys.eq(gt.o) self.comb += gt.i.eq(self.value_rtio), self.value_sys.eq(gt.o)
class _BlindTransfer(Module):
def __init__(self):
self.i = Signal()
self.o = Signal()
ps = PulseSynchronizer("rio", "rsys")
ps_ack = PulseSynchronizer("rsys", "rio")
self.submodules += ps, ps_ack
blind = Signal()
self.sync.rio += [
If(self.i, blind.eq(1)),
If(ps_ack.o, blind.eq(0))
]
self.comb += [
ps.i.eq(self.i & ~blind),
ps_ack.i.eq(ps.o),
self.o.eq(ps.o)
]
# CHOOSING A GUARD TIME # CHOOSING A GUARD TIME
# #
# The buffer must be transferred to the FIFO soon enough to account for: # The buffer must be transferred to the FIFO soon enough to account for:
@ -95,7 +115,7 @@ class _OutputManager(Module):
ev_layout.append(("address", address_width)) ev_layout.append(("address", address_width))
ev_layout.append(("timestamp", counter.width + fine_ts_width)) ev_layout.append(("timestamp", counter.width + fine_ts_width))
# ev must be valid 1 cycle before we to account for the latency in # ev must be valid 1 cycle before we to account for the latency in
# generating replace, sequence_error and nop # generating replace, sequence_error and collision
self.ev = Record(ev_layout) self.ev = Record(ev_layout)
self.writable = Signal() self.writable = Signal()
@ -104,6 +124,7 @@ class _OutputManager(Module):
self.underflow = Signal() # valid 1 cycle after we, pulsed self.underflow = Signal() # valid 1 cycle after we, pulsed
self.sequence_error = Signal() self.sequence_error = Signal()
self.collision = Signal() self.collision = Signal()
self.busy = Signal() # pulsed
# # # # # #
@ -128,18 +149,17 @@ class _OutputManager(Module):
sequence_error = Signal() sequence_error = Signal()
collision = Signal() collision = Signal()
any_error = Signal() any_error = Signal()
nop = Signal() if interface.enable_replace:
self.sync.rsys += [
# Note: replace may be asserted at the same time as collision # Note: replace may be asserted at the same time as collision
# when addresses are different. In that case, it is a collision. # when addresses are different. In that case, it is a collision.
replace.eq(self.ev.timestamp == buf.timestamp), self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp)
# Detect sequence errors on coarse timestamps only # Detect sequence errors on coarse timestamps only
# so that they are mutually exclusive with collision errors. # so that they are mutually exclusive with collision errors.
sequence_error.eq(self.ev.timestamp[fine_ts_width:] self.sync.rsys += sequence_error.eq(self.ev.timestamp[fine_ts_width:] <
< buf.timestamp[fine_ts_width:]) buf.timestamp[fine_ts_width:])
] if interface.enable_replace:
if hasattr(self.ev, "a"): if address_width:
different_addresses = self.ev.a != buf.a different_addresses = self.ev.address != buf.address
else: else:
different_addresses = 0 different_addresses = 0
if fine_ts_width: if fine_ts_width:
@ -147,25 +167,11 @@ class _OutputManager(Module):
(self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
& ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width]) & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
|different_addresses)) |different_addresses))
self.comb += any_error.eq(sequence_error | collision)
if interface.suppress_nop:
# disable NOP at reset: do not suppress a first write with all 0s
nop_en = Signal(reset=0)
addresses_equal = [getattr(self.ev, a) == getattr(buf, a)
for a in ("data", "address")
if hasattr(self.ev, a)]
if addresses_equal:
self.sync.rsys += nop.eq(
nop_en & reduce(and_, addresses_equal))
else: else:
self.comb.eq(nop.eq(0)) self.sync.rsys += collision.eq(
self.sync.rsys += [ self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
# buf now contains valid data. enable NOP.
If(self.we & ~any_error, nop_en.eq(1)),
# underflows cancel the write. allow it to be retried.
If(self.underflow, nop_en.eq(0))
]
self.comb += [ self.comb += [
any_error.eq(sequence_error | collision),
self.sequence_error.eq(self.we & sequence_error), self.sequence_error.eq(self.we & sequence_error),
self.collision.eq(self.we & collision) self.collision.eq(self.we & collision)
] ]
@ -186,7 +192,7 @@ class _OutputManager(Module):
fifo.we.eq(1) fifo.we.eq(1)
) )
), ),
If(self.we & ~replace & ~nop & ~any_error, If(self.we & ~replace & ~any_error,
fifo.we.eq(1) fifo.we.eq(1)
) )
) )
@ -195,7 +201,7 @@ class _OutputManager(Module):
# Must come after read to handle concurrent read+write properly # Must come after read to handle concurrent read+write properly
self.sync.rsys += [ self.sync.rsys += [
buf_just_written.eq(0), buf_just_written.eq(0),
If(self.we & ~nop & ~any_error, If(self.we & ~any_error,
buf_just_written.eq(1), buf_just_written.eq(1),
buf_pending.eq(1), buf_pending.eq(1),
buf.eq(self.ev) buf.eq(self.ev)
@ -217,12 +223,19 @@ class _OutputManager(Module):
self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))
# FIFO read through buffer # FIFO read through buffer
# TODO: report error on stb & busy
self.comb += [ self.comb += [
dout_ack.eq( dout_ack.eq(
dout.timestamp[fine_ts_width:] == counter.value_rtio), dout.timestamp[fine_ts_width:] == counter.value_rtio),
interface.stb.eq(dout_stb & dout_ack) interface.stb.eq(dout_stb & dout_ack)
] ]
busy_transfer = _BlindTransfer()
self.submodules += busy_transfer
self.comb += [
busy_transfer.i.eq(interface.stb & interface.busy),
self.busy.eq(busy_transfer.o),
]
if data_width: if data_width:
self.comb += interface.data.eq(dout.data) self.comb += interface.data.eq(dout.data)
if address_width: if address_width:
@ -278,18 +291,11 @@ class _InputManager(Module):
fifo.re.eq(self.re) fifo.re.eq(self.re)
] ]
overflow_sync = PulseSynchronizer("rio", "rsys") overflow_transfer = _BlindTransfer()
overflow_ack_sync = PulseSynchronizer("rsys", "rio") self.submodules += overflow_transfer
self.submodules += overflow_sync, overflow_ack_sync
overflow_blind = Signal()
self.comb += overflow_sync.i.eq(fifo.we & ~fifo.writable & ~overflow_blind)
self.sync.rio += [
If(fifo.we & ~fifo.writable, overflow_blind.eq(1)),
If(overflow_ack_sync.o, overflow_blind.eq(0))
]
self.comb += [ self.comb += [
overflow_ack_sync.i.eq(overflow_sync.o), overflow_transfer.i.eq(fifo.we & ~fifo.writable),
self.overflow.eq(overflow_sync.o) self.overflow.eq(overflow_transfer.o),
] ]
@ -317,8 +323,7 @@ class Channel:
class LogChannel: class LogChannel:
"""A degenerate channel used to log messages into the analyzer.""" """A degenerate channel used to log messages into the analyzer."""
def __init__(self): def __init__(self):
self.interface = rtlink.Interface( self.interface = rtlink.Interface(rtlink.OInterface(32))
rtlink.OInterface(32, suppress_nop=False))
self.probes = [] self.probes = []
self.overrides = [] self.overrides = []
@ -336,10 +341,11 @@ class _KernelCSRs(AutoCSR):
self.o_address = CSRStorage(address_width) self.o_address = CSRStorage(address_width)
self.o_timestamp = CSRStorage(full_ts_width) self.o_timestamp = CSRStorage(full_ts_width)
self.o_we = CSR() self.o_we = CSR()
self.o_status = CSRStatus(4) self.o_status = CSRStatus(5)
self.o_underflow_reset = CSR() self.o_underflow_reset = CSR()
self.o_sequence_error_reset = CSR() self.o_sequence_error_reset = CSR()
self.o_collision_reset = CSR() self.o_collision_reset = CSR()
self.o_busy_reset = CSR()
if data_width: if data_width:
self.i_data = CSRStatus(data_width) self.i_data = CSRStatus(data_width)
@ -427,6 +433,7 @@ class RTIO(Module):
underflow = Signal() underflow = Signal()
sequence_error = Signal() sequence_error = Signal()
collision = Signal() collision = Signal()
busy = Signal()
self.sync.rsys += [ self.sync.rsys += [
If(selected & self.kcsrs.o_underflow_reset.re, If(selected & self.kcsrs.o_underflow_reset.re,
underflow.eq(0)), underflow.eq(0)),
@ -434,14 +441,18 @@ class RTIO(Module):
sequence_error.eq(0)), sequence_error.eq(0)),
If(selected & self.kcsrs.o_collision_reset.re, If(selected & self.kcsrs.o_collision_reset.re,
collision.eq(0)), collision.eq(0)),
If(selected & self.kcsrs.o_busy_reset.re,
busy.eq(0)),
If(o_manager.underflow, underflow.eq(1)), If(o_manager.underflow, underflow.eq(1)),
If(o_manager.sequence_error, sequence_error.eq(1)), If(o_manager.sequence_error, sequence_error.eq(1)),
If(o_manager.collision, collision.eq(1)) If(o_manager.collision, collision.eq(1)),
If(o_manager.busy, busy.eq(1))
] ]
o_statuses.append(Cat(~o_manager.writable, o_statuses.append(Cat(~o_manager.writable,
underflow, underflow,
sequence_error, sequence_error,
collision)) collision,
busy))
if channel.interface.i is not None: if channel.interface.i is not None:
i_manager = _InputManager(channel.interface.i, self.counter, i_manager = _InputManager(channel.interface.i, self.counter,

View File

@ -79,8 +79,7 @@ class Inout(Module):
class ClockGen(Module): class ClockGen(Module):
def __init__(self, pad, ftw_width=24): def __init__(self, pad, ftw_width=24):
self.rtlink = rtlink.Interface( self.rtlink = rtlink.Interface(rtlink.OInterface(ftw_width))
rtlink.OInterface(ftw_width, suppress_nop=False))
# # # # # #

View File

@ -5,7 +5,7 @@ from artiq.gateware.rtio import rtlink
class RT2WB(Module): class RT2WB(Module):
def __init__(self, address_width, wb=None): def __init__(self, address_width, wb=None, rtio_enable_replace=False):
if wb is None: if wb is None:
wb = wishbone.Interface() wb = wishbone.Interface()
self.wb = wb self.wb = wb
@ -13,7 +13,7 @@ class RT2WB(Module):
rtlink.OInterface( rtlink.OInterface(
len(wb.dat_w), len(wb.dat_w),
address_width + 1, address_width + 1,
suppress_nop=False), enable_replace=rtio_enable_replace),
rtlink.IInterface( rtlink.IInterface(
len(wb.dat_r), len(wb.dat_r),
timestamped=False) timestamped=False)

View File

@ -3,7 +3,7 @@ from migen import *
class OInterface: class OInterface:
def __init__(self, data_width, address_width=0, def __init__(self, data_width, address_width=0,
fine_ts_width=0, suppress_nop=True): fine_ts_width=0, enable_replace=True):
self.stb = Signal() self.stb = Signal()
self.busy = Signal() self.busy = Signal()
@ -14,14 +14,14 @@ class OInterface:
if fine_ts_width: if fine_ts_width:
self.fine_ts = Signal(fine_ts_width) self.fine_ts = Signal(fine_ts_width)
self.suppress_nop = suppress_nop self.enable_replace = enable_replace
@classmethod @classmethod
def like(cls, other): def like(cls, other):
return cls(get_data_width(other), return cls(get_data_width(other),
get_address_width(other), get_address_width(other),
get_fine_ts_width(other), get_fine_ts_width(other),
other.suppress_nop) other.enable_replace)
class IInterface: class IInterface:

View File

@ -204,8 +204,9 @@ class NIST_QC1(_NIST_Ions):
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy)) rtio_channels.append(rtio.Channel.from_phy(phy))
self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
self.config["DDS_CHANNEL_COUNT"] = 8 self.config["RTIO_DDS_COUNT"] = 1
self.config["DDS_CHANNELS_PER_BUS"] = 8
self.config["DDS_AD9858"] = True self.config["DDS_AD9858"] = True
phy = dds.AD9858(platform.request("dds"), 8) phy = dds.AD9858(platform.request("dds"), 8)
self.submodules += phy self.submodules += phy
@ -277,8 +278,9 @@ class NIST_CLOCK(_NIST_Ions):
rtio_channels.append(rtio.Channel.from_phy( rtio_channels.append(rtio.Channel.from_phy(
phy, ofifo_depth=128, ififo_depth=128)) phy, ofifo_depth=128, ififo_depth=128))
self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
self.config["DDS_CHANNEL_COUNT"] = 11 self.config["RTIO_DDS_COUNT"] = 1
self.config["DDS_CHANNELS_PER_BUS"] = 11
self.config["DDS_AD9914"] = True self.config["DDS_AD9914"] = True
self.config["DDS_ONEHOT_SEL"] = True self.config["DDS_ONEHOT_SEL"] = True
phy = dds.AD9914(platform.request("dds"), 11, onehot=True) phy = dds.AD9914(platform.request("dds"), 11, onehot=True)
@ -331,8 +333,9 @@ class NIST_QC2(_NIST_Ions):
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy)) rtio_channels.append(rtio.Channel.from_phy(phy))
self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
self.config["DDS_CHANNEL_COUNT"] = 12 self.config["RTIO_DDS_COUNT"] = 1
self.config["DDS_CHANNELS_PER_BUS"] = 12
self.config["DDS_AD9914"] = True self.config["DDS_AD9914"] = True
self.config["DDS_ONEHOT_SEL"] = True self.config["DDS_ONEHOT_SEL"] = True
phy = dds.AD9914(platform.request("dds"), 12, onehot=True) phy = dds.AD9914(platform.request("dds"), 12, onehot=True)

View File

@ -9,11 +9,10 @@ from fractions import Fraction
from migen import * from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.cdc import MultiReg from migen.genlib.cdc import MultiReg
from migen.build.generic_platform import *
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
from misoc.interconnect import wishbone
from misoc.cores import gpio from misoc.cores import gpio
from misoc.integration.soc_core import mem_decoder
from misoc.targets.pipistrello import (BaseSoC, soc_pipistrello_args, from misoc.targets.pipistrello import (BaseSoC, soc_pipistrello_args,
soc_pipistrello_argdict) soc_pipistrello_argdict)
from misoc.integration.builder import builder_args, builder_argdict from misoc.integration.builder import builder_args, builder_argdict
@ -24,6 +23,28 @@ from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_spartan6, dds, spi
from artiq import __version__ as artiq_version from artiq import __version__ as artiq_version
_pmod_spi = [
("pmod_spi", 0,
Subsignal("cs_n", Pins("PMOD:0")),
Subsignal("mosi", Pins("PMOD:1")),
Subsignal("miso", Pins("PMOD:2")),
Subsignal("clk", Pins("PMOD:3")),
IOStandard("LVTTL")
),
("pmod_extended_spi", 0,
Subsignal("cs_n", Pins("PMOD:0")),
Subsignal("mosi", Pins("PMOD:1")),
Subsignal("miso", Pins("PMOD:2")),
Subsignal("clk", Pins("PMOD:3")),
Subsignal("int", Pins("PMOD:4")),
Subsignal("rst", Pins("PMOD:5")),
Subsignal("d0", Pins("PMOD:6")),
Subsignal("d1", Pins("PMOD:7")),
IOStandard("LVTTL")
),
]
class _RTIOCRG(Module, AutoCSR): class _RTIOCRG(Module, AutoCSR):
def __init__(self, platform, clk_freq): def __init__(self, platform, clk_freq):
self._clock_sel = CSRStorage() self._clock_sel = CSRStorage()
@ -88,7 +109,8 @@ class _RTIOCRG(Module, AutoCSR):
# ISE infers correct period constraints for cd_rtio.clk from # ISE infers correct period constraints for cd_rtio.clk from
# the internal clock. The first two TIGs target just the BUFGMUX. # the internal clock. The first two TIGs target just the BUFGMUX.
platform.add_platform_command(""" platform.add_platform_command(
"""
NET "sys_clk" TNM_NET = "GRPsys_clk"; NET "sys_clk" TNM_NET = "GRPsys_clk";
NET "{ext_clk}" TNM_NET = "GRPext_clk"; NET "{ext_clk}" TNM_NET = "GRPext_clk";
TIMESPEC "TSfix_ise1" = FROM "GRPsys_clk" TO "GRPext_clk" TIG; TIMESPEC "TSfix_ise1" = FROM "GRPsys_clk" TO "GRPext_clk" TIG;
@ -97,7 +119,8 @@ TIMESPEC "TSfix_ise2" = FROM "GRPsys_clk" TO "GRPint_clk" TIG;
NET "{rtio_clk}" TNM_NET = "GRPrtio_clk"; NET "{rtio_clk}" TNM_NET = "GRPrtio_clk";
TIMESPEC "TSfix_ise3" = FROM "GRPrtio_clk" TO "GRPsys_clk" TIG; TIMESPEC "TSfix_ise3" = FROM "GRPrtio_clk" TO "GRPsys_clk" TIG;
TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG; TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG;
""", ext_clk=rtio_external_clk, int_clk=rtio_internal_clk, """,
ext_clk=rtio_external_clk, int_clk=rtio_internal_clk,
rtio_clk=self.cd_rtio.clk) rtio_clk=self.cd_rtio.clk)
@ -134,6 +157,7 @@ class NIST_QC1(BaseSoC, AMPSoC):
trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd {build_name}.pcf trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd {build_name}.pcf
""" """
platform.add_extension(nist_qc1.papilio_adapter_io) platform.add_extension(nist_qc1.papilio_adapter_io)
platform.add_extension(_pmod_spi)
self.submodules.leds = gpio.GPIOOut(platform.request("user_led", 4)) self.submodules.leds = gpio.GPIOOut(platform.request("user_led", 4))
@ -177,13 +201,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4))
pmod = self.platform.request("pmod", 0) spi_pins = self.platform.request("pmod_extended_spi", 0)
for i in range(4, 8):
phy = ttl_simple.Inout(pmod.d[i])
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=128,
ofifo_depth=128))
self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels)
@ -191,19 +209,15 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy)) rtio_channels.append(rtio.Channel.from_phy(phy))
spi_pins = Module()
spi_pins.cs_n = pmod.d[0]
spi_pins.mosi = pmod.d[1]
spi_pins.miso = pmod.d[2]
spi_pins.clk = pmod.d[3]
phy = spi.SPIMaster(spi_pins) phy = spi.SPIMaster(spi_pins)
self.submodules += phy self.submodules += phy
self.config["RTIO_FIRST_SPI_CHANNEL"] = len(rtio_channels) self.config["RTIO_FIRST_SPI_CHANNEL"] = len(rtio_channels)
rtio_channels.append(rtio.Channel.from_phy( rtio_channels.append(rtio.Channel.from_phy(
phy, ofifo_depth=128, ififo_depth=128)) phy, ofifo_depth=256, ififo_depth=256))
self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
self.config["DDS_CHANNEL_COUNT"] = 8 self.config["RTIO_DDS_COUNT"] = 1
self.config["DDS_CHANNELS_PER_BUS"] = 8
self.config["DDS_AD9858"] = True self.config["DDS_AD9858"] = True
dds_pins = platform.request("dds") dds_pins = platform.request("dds")
self.comb += dds_pins.p.eq(0) self.comb += dds_pins.p.eq(0)
@ -222,8 +236,8 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
self.config["RTIO_FINE_TS_WIDTH"] = self.rtio.fine_ts_width self.config["RTIO_FINE_TS_WIDTH"] = self.rtio.fine_ts_width
self.config["DDS_RTIO_CLK_RATIO"] = 8 >> self.rtio.fine_ts_width self.config["DDS_RTIO_CLK_RATIO"] = 8 >> self.rtio.fine_ts_width
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio, self.submodules.rtio_analyzer = rtio.Analyzer(
self.get_native_sdram_if()) self.rtio, self.get_native_sdram_if())
def main(): def main():

View File

@ -85,7 +85,7 @@ class AppletIPCServer(AsyncioParentComm):
await asyncio.wait([self.server_task]) await asyncio.wait([self.server_task])
class AppletDock(QDockWidgetCloseDetect): class _AppletDock(QDockWidgetCloseDetect):
def __init__(self, datasets_sub, uid, name, command): def __init__(self, datasets_sub, uid, name, command):
QDockWidgetCloseDetect.__init__(self, "Applet: " + name) QDockWidgetCloseDetect.__init__(self, "Applet: " + name)
self.setObjectName("applet" + str(uid)) self.setObjectName("applet" + str(uid))
@ -137,7 +137,7 @@ class AppletDock(QDockWidgetCloseDetect):
def fix_initial_size(self): def fix_initial_size(self):
self.embed_window.resize(self.embed_widget.size()) self.embed_window.resize(self.embed_widget.size())
async def terminate(self): async def terminate(self, delete_self=True):
if self.starting_stopping: if self.starting_stopping:
return return
self.starting_stopping = True self.starting_stopping = True
@ -163,8 +163,12 @@ class AppletDock(QDockWidgetCloseDetect):
self.starting_stopping = False self.starting_stopping = False
if delete_self:
self.setParent(None)
self.deleteLater()
async def restart(self): async def restart(self):
await self.terminate() await self.terminate(False)
await self.start() await self.start()
@ -235,7 +239,7 @@ class AppletsDock(QtWidgets.QDockWidget):
self.table.cellChanged.connect(self.cell_changed) self.table.cellChanged.connect(self.cell_changed)
def create(self, uid, name, command): def create(self, uid, name, command):
dock = AppletDock(self.datasets_sub, uid, name, command) dock = _AppletDock(self.datasets_sub, uid, name, command)
self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
dock.setFloating(True) dock.setFloating(True)
asyncio.ensure_future(dock.start()) asyncio.ensure_future(dock.start())

View File

@ -303,6 +303,9 @@ class LogDockManager:
return dock return dock
def on_dock_closed(self, name): def on_dock_closed(self, name):
dock = self.docks[name]
dock.setParent(None)
dock.deleteLater()
del self.docks[name] del self.docks[name]
self.update_closable() self.update_closable()

View File

@ -118,13 +118,14 @@ class _TTLWidget(QtWidgets.QFrame):
class _DDSWidget(QtWidgets.QFrame): class _DDSWidget(QtWidgets.QFrame):
def __init__(self, channel, sysclk, title): def __init__(self, bus_channel, channel, sysclk, title):
self.bus_channel = bus_channel
self.channel = channel self.channel = channel
self.sysclk = sysclk self.sysclk = sysclk
QtWidgets.QFrame.__init__(self) QtWidgets.QFrame.__init__(self)
self.setFrameShape(QtWidgets.QFrame.Panel) self.setFrameShape(QtWidgets.QFrame.Box)
self.setFrameShadow(QtWidgets.QFrame.Raised) self.setFrameShadow(QtWidgets.QFrame.Raised)
grid = QtWidgets.QGridLayout() grid = QtWidgets.QGridLayout()
@ -146,13 +147,14 @@ class _DDSWidget(QtWidgets.QFrame):
self.set_value(0) self.set_value(0)
def set_value(self, ftw): def set_value(self, ftw):
frequency = ftw*self.sysclk/2**32 frequency = ftw*self.sysclk()/2**32
self._value.setText("<font size=\"6\">{:.7f} MHz</font>" self._value.setText("<font size=\"6\">{:.7f} MHz</font>"
.format(float(frequency)/1e6)) .format(float(frequency)/1e6))
class _DeviceManager: class _DeviceManager:
def __init__(self, send_to_device, init): def __init__(self, send_to_device, init):
self.dds_sysclk = 0
self.send_to_device = send_to_device self.send_to_device = send_to_device
self.ddb = dict() self.ddb = dict()
self.ttl_cb = lambda: None self.ttl_cb = lambda: None
@ -162,6 +164,9 @@ class _DeviceManager:
for k, v in init.items(): for k, v in init.items():
self[k] = v self[k] = v
def get_dds_sysclk(self):
return self.dds_sysclk
def __setitem__(self, k, v): def __setitem__(self, k, v):
if k in self.ttl_widgets: if k in self.ttl_widgets:
del self[k] del self[k]
@ -181,12 +186,15 @@ class _DeviceManager:
self.ttl_widgets[k] = _TTLWidget( self.ttl_widgets[k] = _TTLWidget(
channel, self.send_to_device, force_out, title) channel, self.send_to_device, force_out, title)
self.ttl_cb() self.ttl_cb()
if (v["module"] == "artiq.coredevice.dds"
and v["class"] == "CoreDDS"):
self.dds_sysclk = v["arguments"]["sysclk"]
if (v["module"] == "artiq.coredevice.dds" if (v["module"] == "artiq.coredevice.dds"
and v["class"] in {"AD9858", "AD9914"}): and v["class"] in {"AD9858", "AD9914"}):
bus_channel = v["arguments"]["bus_channel"]
channel = v["arguments"]["channel"] channel = v["arguments"]["channel"]
sysclk = v["arguments"]["sysclk"]
self.dds_widgets[channel] = _DDSWidget( self.dds_widgets[channel] = _DDSWidget(
channel, sysclk, title) bus_channel, channel, self.get_dds_sysclk, title)
self.dds_cb() self.dds_cb()
except KeyError: except KeyError:
pass pass
@ -275,19 +283,23 @@ class MonInj(TaskObject):
"is not present yet") "is not present yet")
return return
try: try:
ttl_levels, ttl_oes, ttl_overrides = \ hlen = 8*3+4
struct.unpack(">QQQ", data[:8*3]) (ttl_levels, ttl_oes, ttl_overrides,
dds_rtio_first_channel, dds_channels_per_bus) = \
struct.unpack(">QQQHH", data[:hlen])
for w in self.dm.ttl_widgets.values(): for w in self.dm.ttl_widgets.values():
channel = w.channel channel = w.channel
w.set_value(ttl_levels & (1 << channel), w.set_value(ttl_levels & (1 << channel),
ttl_oes & (1 << channel), ttl_oes & (1 << channel),
ttl_overrides & (1 << channel)) ttl_overrides & (1 << channel))
dds_data = data[8*3:] dds_data = data[hlen:]
ndds = len(dds_data)//4 ndds = len(dds_data)//4
ftws = struct.unpack(">" + "I"*ndds, dds_data) ftws = struct.unpack(">" + "I"*ndds, dds_data)
for w in self.dm.dds_widgets.values(): for w in self.dm.dds_widgets.values():
offset = (dds_channels_per_bus*w.bus_channel
+ w.channel-dds_rtio_first_channel)
try: try:
ftw = ftws[w.channel] ftw = ftws[offset]
except KeyError: except KeyError:
pass pass
else: else:

157
artiq/monkey_patches.py Normal file
View File

@ -0,0 +1,157 @@
import sys
__all__ = []
if sys.version_info[:3] == (3, 5, 1):
import asyncio
import socket
import collections
import itertools
import os
# See https://github.com/m-labs/artiq/issues/253
@asyncio.coroutines.coroutine
def create_server(self, protocol_factory, host=None, port=None,
*,
family=socket.AF_UNSPEC,
flags=socket.AI_PASSIVE,
sock=None,
backlog=100,
ssl=None,
reuse_address=None,
reuse_port=None):
"""Create a TCP server.
The host parameter can be a string, in that case the TCP server is bound
to host and port.
The host parameter can also be a sequence of strings and in that case
the TCP server is bound to all hosts of the sequence. If a host
appears multiple times (possibly indirectly e.g. when hostnames
resolve to the same IP address), the server is only bound once to that
host.
Return a Server object which can be used to stop the service.
This method is a coroutine.
"""
if isinstance(ssl, bool):
raise TypeError('ssl argument must be an SSLContext or None')
if host is not None or port is not None:
if sock is not None:
raise ValueError(
'host/port and sock can not be specified at the same time')
AF_INET6 = getattr(socket, 'AF_INET6', 0)
if reuse_address is None:
reuse_address = os.name == 'posix' and sys.platform != 'cygwin'
sockets = []
if host == '':
hosts = [None]
elif (isinstance(host, str) or
not isinstance(host, collections.Iterable)):
hosts = [host]
else:
hosts = host
fs = [self._create_server_getaddrinfo(host, port, family=family,
flags=flags)
for host in hosts]
infos = yield from asyncio.tasks.gather(*fs, loop=self)
infos = set(itertools.chain.from_iterable(infos))
completed = False
try:
for res in infos:
af, socktype, proto, canonname, sa = res
try:
sock = socket.socket(af, socktype, proto)
except socket.error:
# Assume it's a bad family/type/protocol combination.
if self._debug:
asyncio.log.logger.warning('create_server() failed to create '
'socket.socket(%r, %r, %r)',
af, socktype, proto, exc_info=True)
continue
sockets.append(sock)
if reuse_address:
sock.setsockopt(
socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if reuse_port:
if not hasattr(socket, 'SO_REUSEPORT'):
raise ValueError(
'reuse_port not supported by socket module')
else:
sock.setsockopt(
socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
# Disable IPv4/IPv6 dual stack support (enabled by
# default on Linux) which makes a single socket
# listen on both address families.
if af == AF_INET6 and hasattr(socket, 'IPPROTO_IPV6'):
sock.setsockopt(socket.IPPROTO_IPV6,
socket.IPV6_V6ONLY,
True)
try:
sock.bind(sa)
except OSError as err:
raise OSError(err.errno, 'error while attempting '
'to bind on address %r: %s'
% (sa, err.strerror.lower()))
completed = True
finally:
if not completed:
for sock in sockets:
sock.close()
else:
if sock is None:
raise ValueError('Neither host/port nor sock were specified')
sockets = [sock]
server = asyncio.base_events.Server(self, sockets)
for sock in sockets:
sock.listen(backlog)
sock.setblocking(False)
self._start_serving(protocol_factory, sock, ssl, server)
if self._debug:
asyncio.log.logger.info("%r is serving", server)
return server
asyncio.base_events.BaseEventLoop.create_server = create_server
# See https://github.com/m-labs/artiq/issues/247
def _loop_writing(self, f=None, data=None):
try:
assert f is self._write_fut
self._write_fut = None
self._pending_write = 0
if f:
f.result()
if data is None:
data = self._buffer
self._buffer = None
if not data:
if self._closing:
self._loop.call_soon(self._call_connection_lost, None)
if self._eof_written:
self._sock.shutdown(socket.SHUT_WR)
# Now that we've reduced the buffer size, tell the
# protocol to resume writing if it was paused. Note that
# we do this last since the callback is called immediately
# and it may add more data to the buffer (even causing the
# protocol to be paused again).
self._maybe_resume_protocol()
else:
self._write_fut = self._loop._proactor.send(self._sock, data)
if not self._write_fut.done():
assert self._pending_write == 0
self._pending_write = len(data)
self._write_fut.add_done_callback(self._loop_writing)
self._maybe_pause_protocol()
else:
self._write_fut.add_done_callback(self._loop_writing)
except (ConnectionResetError, ConnectionAbortedError) as exc:
self._force_close(exc)
except OSError as exc:
self._fatal_error(exc, 'Fatal write error on pipe transport')
from asyncio import proactor_events
proactor_events._ProactorBaseWritePipeTransport._loop_writing = _loop_writing

View File

@ -1,6 +1,8 @@
import asyncio import asyncio
from copy import copy from copy import copy
from artiq.monkey_patches import *
class AsyncioServer: class AsyncioServer:
"""Generic TCP server based on asyncio. """Generic TCP server based on asyncio.

View File

@ -12,7 +12,6 @@ struct analyzer_header {
unsigned long long int total_byte_count; unsigned long long int total_byte_count;
unsigned char overflow_occured; unsigned char overflow_occured;
unsigned char log_channel; unsigned char log_channel;
unsigned char dds_channel;
unsigned char dds_onehot_sel; unsigned char dds_onehot_sel;
} __attribute__((packed)); } __attribute__((packed));
@ -72,7 +71,6 @@ void analyzer_start(void)
analyzer_header.overflow_occured = rtio_analyzer_message_encoder_overflow_read(); analyzer_header.overflow_occured = rtio_analyzer_message_encoder_overflow_read();
analyzer_header.log_channel = CONFIG_RTIO_LOG_CHANNEL; analyzer_header.log_channel = CONFIG_RTIO_LOG_CHANNEL;
analyzer_header.dds_channel = CONFIG_RTIO_DDS_CHANNEL;
#ifdef CONFIG_DDS_ONEHOT_SEL #ifdef CONFIG_DDS_ONEHOT_SEL
analyzer_header.dds_onehot_sel = 1; analyzer_header.dds_onehot_sel = 1;
#else #else

View File

@ -16,12 +16,12 @@ static void rtio_output_blind(int channel, int addr, int data)
rtio_o_we_write(1); rtio_o_we_write(1);
} }
static void dds_write(int addr, int data) static void dds_write(int bus_channel, int addr, int data)
{ {
rtio_output_blind(CONFIG_RTIO_DDS_CHANNEL, addr, data); rtio_output_blind(bus_channel, addr, data);
} }
static int dds_read(int addr) static int dds_read(int bus_channel, int addr)
{ {
int r; int r;
@ -31,7 +31,7 @@ static int dds_read(int addr)
#ifdef CONFIG_DDS_AD9914 #ifdef CONFIG_DDS_AD9914
#define DDS_READ_FLAG 256 #define DDS_READ_FLAG 256
#endif #endif
dds_write(addr | DDS_READ_FLAG, 0); dds_write(bus_channel, addr | DDS_READ_FLAG, 0);
while(rtio_i_status_read() & RTIO_I_STATUS_EMPTY); while(rtio_i_status_read() & RTIO_I_STATUS_EMPTY);
r = rtio_i_data_read(); r = rtio_i_data_read();
rtio_i_re_write(1); rtio_i_re_write(1);
@ -75,16 +75,18 @@ void bridge_main(void)
struct msg_brg_dds_sel *msg; struct msg_brg_dds_sel *msg;
msg = (struct msg_brg_dds_sel *)umsg; msg = (struct msg_brg_dds_sel *)umsg;
dds_write(DDS_GPIO, msg->channel << 1); dds_write(msg->bus_channel, DDS_GPIO, msg->channel << 1);
mailbox_acknowledge(); mailbox_acknowledge();
break; break;
} }
case MESSAGE_TYPE_BRG_DDS_RESET: { case MESSAGE_TYPE_BRG_DDS_RESET: {
unsigned int g; unsigned int g;
struct msg_brg_dds_reset *msg;
g = dds_read(DDS_GPIO); msg = (struct msg_brg_dds_reset *)umsg;
dds_write(DDS_GPIO, g | 1); g = dds_read(msg->bus_channel, DDS_GPIO);
dds_write(DDS_GPIO, g); dds_write(msg->bus_channel, DDS_GPIO, g | 1);
dds_write(msg->bus_channel, DDS_GPIO, g);
mailbox_acknowledge(); mailbox_acknowledge();
break; break;
@ -95,7 +97,7 @@ void bridge_main(void)
msg = (struct msg_brg_dds_read_request *)umsg; msg = (struct msg_brg_dds_read_request *)umsg;
rmsg.type = MESSAGE_TYPE_BRG_DDS_READ_REPLY; rmsg.type = MESSAGE_TYPE_BRG_DDS_READ_REPLY;
rmsg.data = dds_read(msg->address); rmsg.data = dds_read(msg->bus_channel, msg->address);
mailbox_send_and_wait(&rmsg); mailbox_send_and_wait(&rmsg);
break; break;
} }
@ -103,14 +105,18 @@ void bridge_main(void)
struct msg_brg_dds_write *msg; struct msg_brg_dds_write *msg;
msg = (struct msg_brg_dds_write *)umsg; msg = (struct msg_brg_dds_write *)umsg;
dds_write(msg->address, msg->data); dds_write(msg->bus_channel, msg->address, msg->data);
mailbox_acknowledge(); mailbox_acknowledge();
break; break;
} }
case MESSAGE_TYPE_BRG_DDS_FUD: case MESSAGE_TYPE_BRG_DDS_FUD: {
dds_write(DDS_FUD, 0); struct msg_brg_dds_fud *msg;
msg = (struct msg_brg_dds_fud *)umsg;
dds_write(msg->bus_channel, DDS_FUD, 0);
mailbox_acknowledge(); mailbox_acknowledge();
break; break;
}
default: default:
mailbox_acknowledge(); mailbox_acknowledge();
break; break;

View File

@ -43,30 +43,33 @@ void brg_ttlo(int n, int value)
mailbox_send_and_wait(&msg); mailbox_send_and_wait(&msg);
} }
void brg_ddssel(int channel) void brg_ddssel(int bus_channel, int channel)
{ {
struct msg_brg_dds_sel msg; struct msg_brg_dds_sel msg;
msg.type = MESSAGE_TYPE_BRG_DDS_SEL; msg.type = MESSAGE_TYPE_BRG_DDS_SEL;
msg.bus_channel = bus_channel;
msg.channel = channel; msg.channel = channel;
mailbox_send_and_wait(&msg); mailbox_send_and_wait(&msg);
} }
void brg_ddsreset(void) void brg_ddsreset(int bus_channel)
{ {
struct msg_base msg; struct msg_brg_dds_reset msg;
msg.type = MESSAGE_TYPE_BRG_DDS_RESET; msg.type = MESSAGE_TYPE_BRG_DDS_RESET;
msg.bus_channel = bus_channel;
mailbox_send_and_wait(&msg); mailbox_send_and_wait(&msg);
} }
unsigned int brg_ddsread(unsigned int address) unsigned int brg_ddsread(int bus_channel, unsigned int address)
{ {
struct msg_brg_dds_read_request msg; struct msg_brg_dds_read_request msg;
struct msg_brg_dds_read_reply *rmsg; struct msg_brg_dds_read_reply *rmsg;
unsigned int r; unsigned int r;
msg.type = MESSAGE_TYPE_BRG_DDS_READ_REQUEST; msg.type = MESSAGE_TYPE_BRG_DDS_READ_REQUEST;
msg.bus_channel = bus_channel;
msg.address = address; msg.address = address;
mailbox_send(&msg); mailbox_send(&msg);
while(1) { while(1) {
@ -82,20 +85,22 @@ unsigned int brg_ddsread(unsigned int address)
} }
} }
void brg_ddswrite(unsigned int address, unsigned int data) void brg_ddswrite(int bus_channel, unsigned int address, unsigned int data)
{ {
struct msg_brg_dds_write msg; struct msg_brg_dds_write msg;
msg.type = MESSAGE_TYPE_BRG_DDS_WRITE; msg.type = MESSAGE_TYPE_BRG_DDS_WRITE;
msg.bus_channel = bus_channel;
msg.address = address; msg.address = address;
msg.data = data; msg.data = data;
mailbox_send_and_wait(&msg); mailbox_send_and_wait(&msg);
} }
void brg_ddsfud(void) void brg_ddsfud(int bus_channel)
{ {
struct msg_base msg; struct msg_brg_dds_fud msg;
msg.type = MESSAGE_TYPE_BRG_DDS_FUD; msg.type = MESSAGE_TYPE_BRG_DDS_FUD;
msg.bus_channel = bus_channel;
mailbox_send_and_wait(&msg); mailbox_send_and_wait(&msg);
} }

View File

@ -6,10 +6,10 @@ void brg_start(void);
void brg_ttloe(int n, int value); void brg_ttloe(int n, int value);
void brg_ttlo(int n, int value); void brg_ttlo(int n, int value);
void brg_ddssel(int channel); void brg_ddssel(int bus_channel, int channel);
void brg_ddsreset(void); void brg_ddsreset(int bus_channel);
unsigned int brg_ddsread(unsigned int address); unsigned int brg_ddsread(int bus_channel, unsigned int address);
void brg_ddswrite(unsigned int address, unsigned int data); void brg_ddswrite(int bus_channel, unsigned int address, unsigned int data);
void brg_ddsfud(void); void brg_ddsfud(int bus_channel);
#endif /* __BRIDGE_CTL_H */ #endif /* __BRIDGE_CTL_H */

View File

@ -26,11 +26,11 @@
#endif #endif
#define DDS_WRITE(addr, data) do { \ #define DDS_WRITE(addr, data) do { \
rtio_output(now, CONFIG_RTIO_DDS_CHANNEL, addr, data); \ rtio_output(now, bus_channel, addr, data); \
now += DURATION_WRITE; \ now += DURATION_WRITE; \
} while(0) } while(0)
void dds_init(long long int timestamp, int channel) void dds_init(long long int timestamp, int bus_channel, int channel)
{ {
long long int now; long long int now;
@ -82,17 +82,23 @@ void dds_init(long long int timestamp, int channel)
/* Compensation to keep phase continuity when switching from absolute or tracking /* Compensation to keep phase continuity when switching from absolute or tracking
* to continuous phase mode. */ * to continuous phase mode. */
static unsigned int continuous_phase_comp[CONFIG_DDS_CHANNEL_COUNT]; static unsigned int continuous_phase_comp[CONFIG_RTIO_DDS_COUNT][CONFIG_DDS_CHANNELS_PER_BUS];
static void dds_set_one(long long int now, long long int ref_time, unsigned int channel, static void dds_set_one(long long int now, long long int ref_time,
int bus_channel, int channel,
unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude) unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude)
{ {
unsigned int channel_enc; unsigned int channel_enc;
if(channel >= CONFIG_DDS_CHANNEL_COUNT) { if((channel < 0) || (channel >= CONFIG_DDS_CHANNELS_PER_BUS)) {
core_log("Attempted to set invalid DDS channel\n"); core_log("Attempted to set invalid DDS channel\n");
return; return;
} }
if((bus_channel < CONFIG_RTIO_FIRST_DDS_CHANNEL)
|| (bus_channel >= (CONFIG_RTIO_FIRST_DDS_CHANNEL+CONFIG_RTIO_DDS_COUNT))) {
core_log("Attempted to use invalid DDS bus\n");
return;
}
#ifdef CONFIG_DDS_ONEHOT_SEL #ifdef CONFIG_DDS_ONEHOT_SEL
channel_enc = 1 << channel; channel_enc = 1 << channel;
#else #else
@ -124,7 +130,7 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int
/* Disable autoclear phase accumulator and enables OSK. */ /* Disable autoclear phase accumulator and enables OSK. */
DDS_WRITE(DDS_CFR1L, 0x0108); DDS_WRITE(DDS_CFR1L, 0x0108);
#endif #endif
pow += continuous_phase_comp[channel]; pow += continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel];
} else { } else {
long long int fud_time; long long int fud_time;
@ -140,7 +146,7 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int
pow -= (ref_time - fud_time)*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH); pow -= (ref_time - fud_time)*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH);
if(phase_mode == PHASE_MODE_TRACKING) if(phase_mode == PHASE_MODE_TRACKING)
pow += ref_time*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH); pow += ref_time*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH);
continuous_phase_comp[channel] = pow; continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel] = pow;
} }
#ifdef CONFIG_DDS_AD9858 #ifdef CONFIG_DDS_AD9858
@ -157,6 +163,7 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int
} }
struct dds_set_params { struct dds_set_params {
int bus_channel;
int channel; int channel;
unsigned int ftw; unsigned int ftw;
unsigned int pow; unsigned int pow;
@ -189,20 +196,22 @@ void dds_batch_exit(void)
now = batch_ref_time - batch_count*(DURATION_PROGRAM + DURATION_WRITE); now = batch_ref_time - batch_count*(DURATION_PROGRAM + DURATION_WRITE);
for(i=0;i<batch_count;i++) { for(i=0;i<batch_count;i++) {
dds_set_one(now, batch_ref_time, dds_set_one(now, batch_ref_time,
batch[i].channel, batch[i].ftw, batch[i].pow, batch[i].phase_mode, batch[i].bus_channel, batch[i].channel,
batch[i].ftw, batch[i].pow, batch[i].phase_mode,
batch[i].amplitude); batch[i].amplitude);
now += DURATION_PROGRAM + DURATION_WRITE; now += DURATION_PROGRAM + DURATION_WRITE;
} }
batch_mode = 0; batch_mode = 0;
} }
void dds_set(long long int timestamp, int channel, void dds_set(long long int timestamp, int bus_channel, int channel,
unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude) unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude)
{ {
if(batch_mode) { if(batch_mode) {
if(batch_count >= DDS_MAX_BATCH) if(batch_count >= DDS_MAX_BATCH)
artiq_raise_from_c("DDSBatchError", "DDS batch error", 0, 0, 0); artiq_raise_from_c("DDSBatchError", "DDS batch error", 0, 0, 0);
/* timestamp parameter ignored (determined by batch) */ /* timestamp parameter ignored (determined by batch) */
batch[batch_count].bus_channel = bus_channel;
batch[batch_count].channel = channel; batch[batch_count].channel = channel;
batch[batch_count].ftw = ftw; batch[batch_count].ftw = ftw;
batch[batch_count].pow = pow; batch[batch_count].pow = pow;
@ -210,7 +219,8 @@ void dds_set(long long int timestamp, int channel,
batch[batch_count].amplitude = amplitude; batch[batch_count].amplitude = amplitude;
batch_count++; batch_count++;
} else { } else {
dds_set_one(timestamp - DURATION_PROGRAM, timestamp, channel, ftw, pow, phase_mode, dds_set_one(timestamp - DURATION_PROGRAM, timestamp,
amplitude); bus_channel, channel,
ftw, pow, phase_mode, amplitude);
} }
} }

View File

@ -54,10 +54,10 @@ enum {
PHASE_MODE_TRACKING = 2 PHASE_MODE_TRACKING = 2
}; };
void dds_init(long long int timestamp, int channel); void dds_init(long long int timestamp, int bus_channel, int channel);
void dds_batch_enter(long long int timestamp); void dds_batch_enter(long long int timestamp);
void dds_batch_exit(void); void dds_batch_exit(void);
void dds_set(long long int timestamp, int channel, void dds_set(long long int timestamp, int bus_channel, int channel,
unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude); unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude);
#endif /* __DDS_H */ #endif /* __DDS_H */

View File

@ -150,23 +150,37 @@ struct msg_brg_ttl_out {
struct msg_brg_dds_sel { struct msg_brg_dds_sel {
int type; int type;
int bus_channel;
int channel; int channel;
}; };
struct msg_brg_dds_reset {
int type;
int bus_channel;
};
struct msg_brg_dds_read_request { struct msg_brg_dds_read_request {
int type; int type;
int bus_channel;
unsigned int address; unsigned int address;
}; };
struct msg_brg_dds_read_reply { struct msg_brg_dds_read_reply {
int type; int type;
int bus_channel;
unsigned int data; unsigned int data;
}; };
struct msg_brg_dds_write { struct msg_brg_dds_write {
int type; int type;
int bus_channel;
unsigned int address; unsigned int address;
unsigned int data; unsigned int data;
}; };
struct msg_brg_dds_fud {
int type;
int bus_channel;
};
#endif /* __MESSAGES_H */ #endif /* __MESSAGES_H */

View File

@ -36,13 +36,15 @@ struct monitor_reply {
long long int ttl_levels; long long int ttl_levels;
long long int ttl_oes; long long int ttl_oes;
long long int ttl_overrides; long long int ttl_overrides;
unsigned int dds_ftws[CONFIG_DDS_CHANNEL_COUNT]; unsigned short int dds_rtio_first_channel;
}; unsigned short int dds_channels_per_bus;
unsigned int dds_ftws[CONFIG_RTIO_DDS_COUNT*CONFIG_DDS_CHANNELS_PER_BUS];
} __attribute__((packed));
static void moninj_monitor(const ip_addr_t *addr, u16_t port) static void moninj_monitor(const ip_addr_t *addr, u16_t port)
{ {
struct monitor_reply reply; struct monitor_reply reply;
int i; int i, j;
struct pbuf *reply_p; struct pbuf *reply_p;
reply.ttl_levels = 0; reply.ttl_levels = 0;
@ -64,11 +66,15 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
reply.ttl_overrides |= 1LL << i; reply.ttl_overrides |= 1LL << i;
} }
rtio_moninj_mon_chan_sel_write(CONFIG_RTIO_DDS_CHANNEL); reply.dds_rtio_first_channel = CONFIG_RTIO_FIRST_DDS_CHANNEL;
for(i=0;i<CONFIG_DDS_CHANNEL_COUNT;i++) { reply.dds_channels_per_bus = CONFIG_DDS_CHANNELS_PER_BUS;
for(j=0;j<CONFIG_RTIO_DDS_COUNT;j++) {
rtio_moninj_mon_chan_sel_write(CONFIG_RTIO_FIRST_DDS_CHANNEL+j);
for(i=0;i<CONFIG_DDS_CHANNELS_PER_BUS;i++) {
rtio_moninj_mon_probe_sel_write(i); rtio_moninj_mon_probe_sel_write(i);
rtio_moninj_mon_value_update_write(1); rtio_moninj_mon_value_update_write(1);
reply.dds_ftws[i] = rtio_moninj_mon_value_read(); reply.dds_ftws[CONFIG_DDS_CHANNELS_PER_BUS*j+i] = rtio_moninj_mon_value_read();
}
} }
reply_p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct monitor_reply), PBUF_RAM); reply_p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct monitor_reply), PBUF_RAM);

View File

@ -39,6 +39,12 @@ static void rtio_process_exceptional_status(
"RTIO collision at {0} mu, channel {1}", "RTIO collision at {0} mu, channel {1}",
timestamp, channel, 0); timestamp, channel, 0);
} }
if(status & RTIO_O_STATUS_BUSY) {
rtio_o_busy_reset_write(1);
artiq_raise_from_c("RTIOBusy",
"RTIO busy on channel {0}",
channel, 0, 0);
}
} }

View File

@ -7,6 +7,7 @@
#define RTIO_O_STATUS_UNDERFLOW 2 #define RTIO_O_STATUS_UNDERFLOW 2
#define RTIO_O_STATUS_SEQUENCE_ERROR 4 #define RTIO_O_STATUS_SEQUENCE_ERROR 4
#define RTIO_O_STATUS_COLLISION 8 #define RTIO_O_STATUS_COLLISION 8
#define RTIO_O_STATUS_BUSY 16
#define RTIO_I_STATUS_EMPTY 1 #define RTIO_I_STATUS_EMPTY 1
#define RTIO_I_STATUS_OVERFLOW 2 #define RTIO_I_STATUS_OVERFLOW 2

View File

@ -104,6 +104,28 @@ static void ttlo(char *n, char *value)
brg_ttlo(n2, value2); brg_ttlo(n2, value2);
} }
static int bus_channel = CONFIG_RTIO_FIRST_DDS_CHANNEL;
static void ddsbus(char *n)
{
char *c;
unsigned int n2;
if(*n == 0) {
printf("ddsbus <n>\n");
return;
}
n2 = strtoul(n, &c, 0);
if(*c != 0) {
printf("incorrect bus channel\n");
return;
}
bus_channel = n2;
}
static void ddssel(char *n) static void ddssel(char *n)
{ {
char *c; char *c;
@ -123,7 +145,7 @@ static void ddssel(char *n)
#ifdef CONFIG_DDS_ONEHOT_SEL #ifdef CONFIG_DDS_ONEHOT_SEL
n2 = 1 << n2; n2 = 1 << n2;
#endif #endif
brg_ddssel(n2); brg_ddssel(bus_channel, n2);
} }
static void ddsw(char *addr, char *value) static void ddsw(char *addr, char *value)
@ -147,7 +169,7 @@ static void ddsw(char *addr, char *value)
return; return;
} }
brg_ddswrite(addr2, value2); brg_ddswrite(bus_channel, addr2, value2);
} }
static void ddsr(char *addr) static void ddsr(char *addr)
@ -167,16 +189,16 @@ static void ddsr(char *addr)
} }
#ifdef CONFIG_DDS_AD9858 #ifdef CONFIG_DDS_AD9858
printf("0x%02x\n", brg_ddsread(addr2)); printf("0x%02x\n", brg_ddsread(bus_channel, addr2));
#endif #endif
#ifdef CONFIG_DDS_AD9914 #ifdef CONFIG_DDS_AD9914
printf("0x%04x\n", brg_ddsread(addr2)); printf("0x%04x\n", brg_ddsread(bus_channel, addr2));
#endif #endif
} }
static void ddsfud(void) static void ddsfud(void)
{ {
brg_ddsfud(); brg_ddsfud(bus_channel);
} }
static void ddsftw(char *n, char *ftw) static void ddsftw(char *n, char *ftw)
@ -203,36 +225,36 @@ static void ddsftw(char *n, char *ftw)
#ifdef CONFIG_DDS_ONEHOT_SEL #ifdef CONFIG_DDS_ONEHOT_SEL
n2 = 1 << n2; n2 = 1 << n2;
#endif #endif
brg_ddssel(n2); brg_ddssel(bus_channel, n2);
#ifdef CONFIG_DDS_AD9858 #ifdef CONFIG_DDS_AD9858
brg_ddswrite(DDS_FTW0, ftw2 & 0xff); brg_ddswrite(bus_channel, DDS_FTW0, ftw2 & 0xff);
brg_ddswrite(DDS_FTW1, (ftw2 >> 8) & 0xff); brg_ddswrite(bus_channel, DDS_FTW1, (ftw2 >> 8) & 0xff);
brg_ddswrite(DDS_FTW2, (ftw2 >> 16) & 0xff); brg_ddswrite(bus_channel, DDS_FTW2, (ftw2 >> 16) & 0xff);
brg_ddswrite(DDS_FTW3, (ftw2 >> 24) & 0xff); brg_ddswrite(bus_channel, DDS_FTW3, (ftw2 >> 24) & 0xff);
#endif #endif
#ifdef CONFIG_DDS_AD9914 #ifdef CONFIG_DDS_AD9914
brg_ddswrite(DDS_FTWL, ftw2 & 0xffff); brg_ddswrite(bus_channel, DDS_FTWL, ftw2 & 0xffff);
brg_ddswrite(DDS_FTWH, (ftw2 >> 16) & 0xffff); brg_ddswrite(bus_channel, DDS_FTWH, (ftw2 >> 16) & 0xffff);
#endif #endif
brg_ddsfud(); brg_ddsfud(bus_channel);
} }
static void ddsreset(void) static void ddsreset(void)
{ {
brg_ddsreset(); brg_ddsreset(bus_channel);
} }
#ifdef CONFIG_DDS_AD9858 #ifdef CONFIG_DDS_AD9858
static void ddsinit(void) static void ddsinit(void)
{ {
brg_ddsreset(); brg_ddsreset(bus_channel);
brg_ddswrite(DDS_CFR0, 0x78); brg_ddswrite(bus_channel, DDS_CFR0, 0x78);
brg_ddswrite(DDS_CFR1, 0x00); brg_ddswrite(bus_channel, DDS_CFR1, 0x00);
brg_ddswrite(DDS_CFR2, 0x00); brg_ddswrite(bus_channel, DDS_CFR2, 0x00);
brg_ddswrite(DDS_CFR3, 0x00); brg_ddswrite(bus_channel, DDS_CFR3, 0x00);
brg_ddsfud(); brg_ddsfud(bus_channel);
} }
#endif #endif
@ -241,17 +263,17 @@ static void ddsinit(void)
{ {
long long int t; long long int t;
brg_ddsreset(); brg_ddsreset(bus_channel);
brg_ddswrite(DDS_CFR1H, 0x0000); /* Enable cosine output */ brg_ddswrite(bus_channel, DDS_CFR1H, 0x0000); /* Enable cosine output */
brg_ddswrite(DDS_CFR2L, 0x8900); /* Enable matched latency */ brg_ddswrite(bus_channel, DDS_CFR2L, 0x8900); /* Enable matched latency */
brg_ddswrite(DDS_CFR2H, 0x0080); /* Enable profile mode */ brg_ddswrite(bus_channel, DDS_CFR2H, 0x0080); /* Enable profile mode */
brg_ddswrite(DDS_ASF, 0x0fff); /* Set amplitude to maximum */ brg_ddswrite(bus_channel, DDS_ASF, 0x0fff); /* Set amplitude to maximum */
brg_ddswrite(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ brg_ddswrite(bus_channel, DDS_CFR4H, 0x0105); /* Enable DAC calibration */
brg_ddswrite(DDS_FUD, 0); brg_ddswrite(bus_channel, DDS_FUD, 0);
t = clock_get_ms(); t = clock_get_ms();
while(clock_get_ms() < t + 2); while(clock_get_ms() < t + 2);
brg_ddswrite(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ brg_ddswrite(bus_channel, DDS_CFR4H, 0x0005); /* Disable DAC calibration */
brg_ddsfud(); brg_ddsfud(bus_channel);
} }
#endif #endif
@ -265,34 +287,34 @@ static void do_ddstest_one(unsigned int i)
unsigned int f, g, j; unsigned int f, g, j;
#ifdef CONFIG_DDS_ONEHOT_SEL #ifdef CONFIG_DDS_ONEHOT_SEL
brg_ddssel(1 << i); brg_ddssel(bus_channel, 1 << i);
#else #else
brg_ddssel(i); brg_ddssel(bus_channel, i);
#endif #endif
ddsinit(); ddsinit();
for(j=0; j<12; j++) { for(j=0; j<12; j++) {
f = v[j]; f = v[j];
#ifdef CONFIG_DDS_AD9858 #ifdef CONFIG_DDS_AD9858
brg_ddswrite(DDS_FTW0, f & 0xff); brg_ddswrite(bus_channel, DDS_FTW0, f & 0xff);
brg_ddswrite(DDS_FTW1, (f >> 8) & 0xff); brg_ddswrite(bus_channel, DDS_FTW1, (f >> 8) & 0xff);
brg_ddswrite(DDS_FTW2, (f >> 16) & 0xff); brg_ddswrite(bus_channel, DDS_FTW2, (f >> 16) & 0xff);
brg_ddswrite(DDS_FTW3, (f >> 24) & 0xff); brg_ddswrite(bus_channel, DDS_FTW3, (f >> 24) & 0xff);
#endif #endif
#ifdef CONFIG_DDS_AD9914 #ifdef CONFIG_DDS_AD9914
brg_ddswrite(DDS_FTWL, f & 0xffff); brg_ddswrite(bus_channel, DDS_FTWL, f & 0xffff);
brg_ddswrite(DDS_FTWH, (f >> 16) & 0xffff); brg_ddswrite(bus_channel, DDS_FTWH, (f >> 16) & 0xffff);
#endif #endif
brg_ddsfud(); brg_ddsfud(bus_channel);
#ifdef CONFIG_DDS_AD9858 #ifdef CONFIG_DDS_AD9858
g = brg_ddsread(DDS_FTW0); g = brg_ddsread(bus_channel, DDS_FTW0);
g |= brg_ddsread(DDS_FTW1) << 8; g |= brg_ddsread(bus_channel, DDS_FTW1) << 8;
g |= brg_ddsread(DDS_FTW2) << 16; g |= brg_ddsread(bus_channel, DDS_FTW2) << 16;
g |= brg_ddsread(DDS_FTW3) << 24; g |= brg_ddsread(bus_channel, DDS_FTW3) << 24;
#endif #endif
#ifdef CONFIG_DDS_AD9914 #ifdef CONFIG_DDS_AD9914
g = brg_ddsread(DDS_FTWL); g = brg_ddsread(bus_channel, DDS_FTWL);
g |= brg_ddsread(DDS_FTWH) << 16; g |= brg_ddsread(bus_channel, DDS_FTWH) << 16;
#endif #endif
if(g != f) if(g != f)
printf("readback fail on DDS %d, 0x%08x != 0x%08x\n", i, g, f); printf("readback fail on DDS %d, 0x%08x != 0x%08x\n", i, g, f);
@ -330,7 +352,7 @@ static void ddstest(char *n, char *channel)
do_ddstest_one(channel2); do_ddstest_one(channel2);
} else { } else {
for(i=0;i<n2;i++) for(i=0;i<n2;i++)
for(j=0;j<CONFIG_DDS_CHANNEL_COUNT;j++) for(j=0;j<CONFIG_DDS_CHANNELS_PER_BUS;j++)
do_ddstest_one(j); do_ddstest_one(j);
} }
} }
@ -542,6 +564,7 @@ static void help(void)
puts("clksrc <n> - select RTIO clock source"); puts("clksrc <n> - select RTIO clock source");
puts("ttloe <n> <v> - set TTL output enable"); puts("ttloe <n> <v> - set TTL output enable");
puts("ttlo <n> <v> - set TTL output value"); puts("ttlo <n> <v> - set TTL output value");
puts("ddsbus <n> - select the DDS bus RTIO channel");
puts("ddssel <n> - select a DDS"); puts("ddssel <n> - select a DDS");
puts("ddsinit - reset, config, FUD DDS"); puts("ddsinit - reset, config, FUD DDS");
puts("ddsreset - reset DDS"); puts("ddsreset - reset DDS");
@ -624,6 +647,7 @@ static void do_command(char *c)
else if(strcmp(token, "ttloe") == 0) ttloe(get_token(&c), get_token(&c)); else if(strcmp(token, "ttloe") == 0) ttloe(get_token(&c), get_token(&c));
else if(strcmp(token, "ttlo") == 0) ttlo(get_token(&c), get_token(&c)); else if(strcmp(token, "ttlo") == 0) ttlo(get_token(&c), get_token(&c));
else if(strcmp(token, "ddsbus") == 0) ddsbus(get_token(&c));
else if(strcmp(token, "ddssel") == 0) ddssel(get_token(&c)); else if(strcmp(token, "ddssel") == 0) ddssel(get_token(&c));
else if(strcmp(token, "ddsw") == 0) ddsw(get_token(&c), get_token(&c)); else if(strcmp(token, "ddsw") == 0) ddsw(get_token(&c), get_token(&c));
else if(strcmp(token, "ddsr") == 0) ddsr(get_token(&c)); else if(strcmp(token, "ddsr") == 0) ddsr(get_token(&c));

View File

@ -5,21 +5,22 @@ from artiq.test.hardware_testbench import ExperimentCase
class _Cache(EnvExperiment): class _Cache(EnvExperiment):
def build(self): def build(self):
self.setattr_device("core") self.setattr_device("core")
self.print = lambda x: print(x) self.setattr_device("core_cache")
@kernel @kernel
def get(self, key): def get(self, key):
return self.core.get_cache(key) return self.core_cache.get(key)
@kernel @kernel
def put(self, key, value): def put(self, key, value):
self.core.put_cache(key, value) self.core_cache.put(key, value)
@kernel @kernel
def get_put(self, key, value): def get_put(self, key, value):
self.get(key) self.get(key)
self.put(key, value) self.put(key, value)
class CacheTest(ExperimentCase): class CacheTest(ExperimentCase):
def test_get_empty(self): def test_get_empty(self):
exp = self.create(_Cache) exp = self.create(_Cache)

View File

@ -12,6 +12,10 @@ from artiq.test.hardware_testbench import ExperimentCase
artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY") artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY")
class PulseNotReceived(Exception):
pass
class RTT(EnvExperiment): class RTT(EnvExperiment):
def build(self): def build(self):
self.setattr_device("core") self.setattr_device("core")
@ -29,7 +33,10 @@ class RTT(EnvExperiment):
delay(1*us) delay(1*us)
t0 = now_mu() t0 = now_mu()
self.ttl_inout.pulse(1*us) self.ttl_inout.pulse(1*us)
self.set_dataset("rtt", mu_to_seconds(self.ttl_inout.timestamp_mu() - t0)) t1 = self.ttl_inout.timestamp_mu()
if t1 < 0:
raise PulseNotReceived()
self.set_dataset("rtt", mu_to_seconds(t1 - t0))
class Loopback(EnvExperiment): class Loopback(EnvExperiment):
@ -41,6 +48,7 @@ class Loopback(EnvExperiment):
@kernel @kernel
def run(self): def run(self):
self.loop_in.input() self.loop_in.input()
self.loop_out.off()
delay(1*us) delay(1*us)
with parallel: with parallel:
self.loop_in.gate_rising(2*us) self.loop_in.gate_rising(2*us)
@ -48,7 +56,10 @@ class Loopback(EnvExperiment):
delay(1*us) delay(1*us)
t0 = now_mu() t0 = now_mu()
self.loop_out.pulse(1*us) self.loop_out.pulse(1*us)
self.set_dataset("rtt", mu_to_seconds(self.loop_in.timestamp_mu() - t0)) t1 = self.loop_in.timestamp_mu()
if t1 < 0:
raise PulseNotReceived()
self.set_dataset("rtt", mu_to_seconds(t1 - t0))
class ClockGeneratorLoopback(EnvExperiment): class ClockGeneratorLoopback(EnvExperiment):

View File

@ -0,0 +1,83 @@
from artiq.experiment import *
from artiq.test.hardware_testbench import ExperimentCase
class WrongError(Exception):
pass
class Collision(EnvExperiment):
def build(self):
self.setattr_device("core")
self.setattr_device("spi0")
@kernel
def run(self):
self.core.break_realtime()
t = now_mu()
try:
self.spi0.set_config_mu()
except RTIOBusy:
raise WrongError()
at_mu(t)
self.spi0.set_config_mu()
class Busy(EnvExperiment):
def build(self):
self.setattr_device("core")
self.setattr_device("spi0")
self.setattr_device("led")
@kernel
def run(self):
try:
self.core.break_realtime()
self.spi0.set_config_mu()
t = now_mu()
self.spi0.set_config_mu()
at_mu(t + self.spi0.ref_period_mu)
self.spi0.set_config_mu() # causes the error
self.led.on()
self.led.sync() # registers the error
self.core.break_realtime()
except RTIOBusy:
raise WrongError() # we don't expect RTIOBusy so far
self.spi0.set_config_mu() # raises the error
class DrainErrors(EnvExperiment):
def build(self):
self.setattr_device("core")
self.setattr_device("spi0")
self.setattr_device("led")
@kernel
def run(self):
while True:
try:
self.core.break_realtime()
delay(100*us)
self.spi0.set_config_mu()
self.led.on()
self.led.sync()
self.core.break_realtime()
self.spi0.set_config_mu()
self.led.off()
return
except:
pass
class SPITest(ExperimentCase):
def tearDown(self):
self.execute(DrainErrors)
ExperimentCase.tearDown(self)
def test_collision(self):
with self.assertRaises(RTIOCollision):
self.execute(Collision)
def test_busy(self):
with self.assertRaises(RTIOBusy):
self.execute(Busy)

View File

@ -107,9 +107,10 @@ class ExperimentCase(unittest.TestCase):
return exp return exp
except KeyError as e: except KeyError as e:
# skip if ddb does not match requirements # skip if ddb does not match requirements
raise unittest.SkipTest(*e.args) raise unittest.SkipTest(
"device_db entry `{}` not found".format(*e.args))
def execute(self, cls, *args, **kwargs): def execute(self, cls, **kwargs):
expid = { expid = {
"file": sys.modules[cls.__module__].__file__, "file": sys.modules[cls.__module__].__file__,
"class_name": cls.__name__, "class_name": cls.__name__,
@ -124,3 +125,8 @@ class ExperimentCase(unittest.TestCase):
except CompileError as error: except CompileError as error:
# Reduce amount of text on terminal. # Reduce amount of text on terminal.
raise error from None raise error from None
except Exception as exn:
if hasattr(exn, "artiq_core_exception"):
exn.args = "{}\n{}".format(exn.args[0],
exn.artiq_core_exception),
raise exn

View File

@ -89,6 +89,8 @@ The board has RTIO SPI buses mapped as follows:
| 25 | SPI2_CS_N | SPI2_MOSI | SPI2_MISO | SPI2_CLK | | 25 | SPI2_CS_N | SPI2_MOSI | SPI2_MISO | SPI2_CLK |
+--------------+-------------+-------------+-----------+------------+ +--------------+-------------+-------------+-----------+------------+
The DDS bus is on channel 26.
NIST QC2 NIST QC2
++++++++ ++++++++
@ -132,15 +134,7 @@ When plugged to an adapter, the NIST QC1 hardware can be used. The TTL lines are
+--------------+------------+--------------+ +--------------+------------+--------------+
| 21 | USER_LED_4 | Output | | 21 | USER_LED_4 | Output |
+--------------+------------+--------------+ +--------------+------------+--------------+
| 22 | PMOD_4 | Input+Output | | 22 | TTL15 | Clock |
+--------------+------------+--------------+
| 23 | PMOD_5 | Input+Output |
+--------------+------------+--------------+
| 24 | PMOD_6 | Input+Output |
+--------------+------------+--------------+
| 25 | PMOD_7 | Input+Output |
+--------------+------------+--------------+
| 26 | TTL15 | Clock |
+--------------+------------+--------------+ +--------------+------------+--------------+
The input only limitation on channels 0 and 1 comes from the QC-DAQ adapter. When the adapter is not used (and physically unplugged from the Pipistrello board), the corresponding pins on the Pipistrello can be used as outputs. Do not configure these channels as outputs when the adapter is plugged, as this would cause electrical contention. The input only limitation on channels 0 and 1 comes from the QC-DAQ adapter. When the adapter is not used (and physically unplugged from the Pipistrello board), the corresponding pins on the Pipistrello can be used as outputs. Do not configure these channels as outputs when the adapter is plugged, as this would cause electrical contention.
@ -153,5 +147,5 @@ Interface Type 2 (SPI) and 2A (expanded SPI):
+--------------+--------+--------+--------+--------+ +--------------+--------+--------+--------+--------+
| RTIO channel | CS_N | MOSI | MISO | CLK | | RTIO channel | CS_N | MOSI | MISO | CLK |
+==============+========+========+========+========+ +==============+========+========+========+========+
| 27 | PMOD_0 | PMOD_1 | PMOD_2 | PMOD_3 | | 23 | PMOD_0 | PMOD_1 | PMOD_2 | PMOD_3 |
+--------------+--------+--------+--------+--------+ +--------------+--------+--------+--------+--------+

View File

@ -42,6 +42,12 @@ These drivers are for the core device and the peripherals closely integrated int
.. automodule:: artiq.coredevice.i2c .. automodule:: artiq.coredevice.i2c
:members: :members:
:mod:`artiq.coredevice.cache` module
-----------------------------------------
.. automodule:: artiq.coredevice.cache
:members:
:mod:`artiq.coredevice.exceptions` module :mod:`artiq.coredevice.exceptions` module
----------------------------------------- -----------------------------------------

View File

@ -1,5 +1,6 @@
# This is an example device database that needs to be adapted to your setup. # This is an example device database that needs to be adapted to your setup.
# 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.
{ {
"comm": { "comm": {
@ -14,6 +15,17 @@
"class": "Core", "class": "Core",
"arguments": {"ref_period": 1e-9} "arguments": {"ref_period": 1e-9}
}, },
"core_cache": {
"type": "local",
"module": "artiq.coredevice.cache",
"class": "CoreCache"
},
"core_dds": {
"type": "local",
"module": "artiq.coredevice.dds",
"class": "CoreDDS",
"arguments": {"sysclk": 3e9}
},
"i2c_switch": { "i2c_switch": {
"type": "local", "type": "local",
@ -121,30 +133,24 @@
"arguments": {"spi_device": "spi0", "ldac_device": "ttl0"} "arguments": {"spi_device": "spi0", "ldac_device": "ttl0"}
}, },
"dds_bus": {
"type": "local",
"module": "artiq.coredevice.dds",
"class": "DDSBus",
"arguments": {}
},
"dds0": { "dds0": {
"type": "local", "type": "local",
"module": "artiq.coredevice.dds", "module": "artiq.coredevice.dds",
"class": "AD9914", "class": "AD9914",
"arguments": {"sysclk": 3e9, "channel": 0}, "arguments": {"bus_channel": 26, "channel": 0},
"comment": "Comments work in DDS panel as well" "comment": "Comments work in DDS panel as well"
}, },
"dds1": { "dds1": {
"type": "local", "type": "local",
"module": "artiq.coredevice.dds", "module": "artiq.coredevice.dds",
"class": "AD9914", "class": "AD9914",
"arguments": {"sysclk": 3e9, "channel": 1} "arguments": {"bus_channel": 26, "channel": 1}
}, },
"dds2": { "dds2": {
"type": "local", "type": "local",
"module": "artiq.coredevice.dds", "module": "artiq.coredevice.dds",
"class": "AD9914", "class": "AD9914",
"arguments": {"sysclk": 3e9, "channel": 2} "arguments": {"bus_channel": 26, "channel": 2}
}, },
"qc_q1_0": { "qc_q1_0": {
@ -154,25 +160,25 @@
# that it always resolves to a network-visible IP address (see documentation). # that it always resolves to a network-visible IP address (see documentation).
"host": "::1", "host": "::1",
"port": 4000, "port": 4000,
"command": "pdq2_controller --no-localhost-bind -p {port} --bind {bind} --simulation --dump qc_q1_0.bin" "command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_0.bin"
}, },
"qc_q1_1": { "qc_q1_1": {
"type": "controller", "type": "controller",
"host": "::1", "host": "::1",
"port": 4001, "port": 4001,
"command": "pdq2_controller --no-localhost-bind -p {port} --bind {bind} --simulation --dump qc_q1_1.bin" "command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_1.bin"
}, },
"qc_q1_2": { "qc_q1_2": {
"type": "controller", "type": "controller",
"host": "::1", "host": "::1",
"port": 4002, "port": 4002,
"command": "pdq2_controller --no-localhost-bind -p {port} --bind {bind} --simulation --dump qc_q1_2.bin" "command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_2.bin"
}, },
"qc_q1_3": { "qc_q1_3": {
"type": "controller", "type": "controller",
"host": "::1", "host": "::1",
"port": 4003, "port": 4003,
"command": "pdq2_controller --no-localhost-bind -p {port} --bind {bind} --simulation --dump qc_q1_3.bin" "command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_3.bin"
}, },
"electrodes": { "electrodes": {
"type": "local", "type": "local",

View File

@ -6,7 +6,7 @@ class PhotonHistogram(EnvExperiment):
def build(self): def build(self):
self.setattr_device("core") self.setattr_device("core")
self.setattr_device("dds_bus") self.setattr_device("core_dds")
self.setattr_device("bd_dds") self.setattr_device("bd_dds")
self.setattr_device("bd_sw") self.setattr_device("bd_sw")
self.setattr_device("bdd_dds") self.setattr_device("bdd_dds")
@ -22,7 +22,7 @@ class PhotonHistogram(EnvExperiment):
@kernel @kernel
def program_cooling(self): def program_cooling(self):
with self.dds_bus.batch: with self.core_dds.batch:
self.bd_dds.set(200*MHz) self.bd_dds.set(200*MHz)
self.bdd_dds.set(300*MHz) self.bdd_dds.set(300*MHz)

View File

@ -6,7 +6,7 @@ class DDSTest(EnvExperiment):
def build(self): def build(self):
self.setattr_device("core") self.setattr_device("core")
self.setattr_device("dds_bus") self.setattr_device("core_dds")
self.setattr_device("dds0") self.setattr_device("dds0")
self.setattr_device("dds1") self.setattr_device("dds1")
self.setattr_device("dds2") self.setattr_device("dds2")
@ -17,7 +17,7 @@ class DDSTest(EnvExperiment):
@kernel @kernel
def run(self): def run(self):
with self.dds_bus.batch: with self.core_dds.batch:
self.dds1.set(120*MHz) self.dds1.set(120*MHz)
self.dds2.set(200*MHz) self.dds2.set(200*MHz)
delay(1*us) delay(1*us)