forked from M-Labs/artiq
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:
commit
bc9203457e
|
@ -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.
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
|
@ -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)
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,44 +149,29 @@ 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:
|
|
||||||
different_addresses = 0
|
|
||||||
if fine_ts_width:
|
|
||||||
self.sync.rsys += collision.eq(
|
|
||||||
(self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
|
|
||||||
& ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
|
|
||||||
|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))
|
different_addresses = 0
|
||||||
self.sync.rsys += [
|
if fine_ts_width:
|
||||||
# buf now contains valid data. enable NOP.
|
self.sync.rsys += collision.eq(
|
||||||
If(self.we & ~any_error, nop_en.eq(1)),
|
(self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
|
||||||
# underflows cancel the write. allow it to be retried.
|
& ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
|
||||||
If(self.underflow, nop_en.eq(0))
|
|different_addresses))
|
||||||
]
|
else:
|
||||||
|
self.sync.rsys += collision.eq(
|
||||||
|
self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
|
||||||
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,
|
||||||
|
|
|
@ -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))
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,8 +119,9 @@ 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,
|
""",
|
||||||
rtio_clk=self.cd_rtio.clk)
|
ext_clk=rtio_external_clk, int_clk=rtio_internal_clk,
|
||||||
|
rtio_clk=self.cd_rtio.clk)
|
||||||
|
|
||||||
|
|
||||||
class NIST_QC1(BaseSoC, AMPSoC):
|
class NIST_QC1(BaseSoC, AMPSoC):
|
||||||
|
@ -112,9 +135,9 @@ class NIST_QC1(BaseSoC, AMPSoC):
|
||||||
}
|
}
|
||||||
csr_map.update(BaseSoC.csr_map)
|
csr_map.update(BaseSoC.csr_map)
|
||||||
mem_map = {
|
mem_map = {
|
||||||
"timer_kernel": 0x10000000, # (shadow @0x90000000)
|
"timer_kernel": 0x10000000, # (shadow @0x90000000)
|
||||||
"rtio": 0x20000000, # (shadow @0xa0000000)
|
"rtio": 0x20000000, # (shadow @0xa0000000)
|
||||||
"mailbox": 0x70000000 # (shadow @0xf0000000)
|
"mailbox": 0x70000000 # (shadow @0xf0000000)
|
||||||
}
|
}
|
||||||
mem_map.update(BaseSoC.mem_map)
|
mem_map.update(BaseSoC.mem_map)
|
||||||
|
|
||||||
|
@ -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():
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
rtio_moninj_mon_probe_sel_write(i);
|
for(j=0;j<CONFIG_RTIO_DDS_COUNT;j++) {
|
||||||
rtio_moninj_mon_value_update_write(1);
|
rtio_moninj_mon_chan_sel_write(CONFIG_RTIO_FIRST_DDS_CHANNEL+j);
|
||||||
reply.dds_ftws[i] = rtio_moninj_mon_value_read();
|
for(i=0;i<CONFIG_DDS_CHANNELS_PER_BUS;i++) {
|
||||||
|
rtio_moninj_mon_probe_sel_write(i);
|
||||||
|
rtio_moninj_mon_value_update_write(1);
|
||||||
|
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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
|
@ -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
|
||||||
|
|
|
@ -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 |
|
||||||
+--------------+--------+--------+--------+--------+
|
+--------------+--------+--------+--------+--------+
|
||||||
|
|
|
@ -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
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue