Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b50e3fabb03b
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 349a66124bd8
Choose a head ref
  • 10 commits
  • 25 files changed
  • 2 contributors

Commits on Mar 9, 2016

  1. Copy the full SHA
    f0b0b1b View commit details
  2. Copy the full SHA
    de37487 View commit details
  3. Copy the full SHA
    861c4a9 View commit details
  4. Copy the full SHA
    1c706fa View commit details
  5. Copy the full SHA
    03b53c3 View commit details
  6. rtio/core: fix syntax

    jordens committed Mar 9, 2016
    Copy the full SHA
    3f8e431 View commit details
  7. Copy the full SHA
    b32217c View commit details
  8. Copy the full SHA
    9a661bd View commit details
  9. Copy the full SHA
    8f6653e View commit details
  10. Merge branch 'master' into rtiobusy

    * master:
      coredevice: fix _DDSGeneric __init__ args
      rtio/core: fix syntax
      rtio: disable replace on rt2wb channels
      examples: dds_bus -> core_dds
      fix more multi-DDS-bus problems
      runtime: fix dds declarations
      support for multiple DDS buses (untested)
    jordens committed Mar 9, 2016
    Copy the full SHA
    349a661 View commit details
6 changes: 5 additions & 1 deletion RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
@@ -11,4 +11,8 @@ Release notes
This requires reflashing the runtime and the flash storage filesystem image
or erase and rewrite its entries.
* RTIOCollisionError has been renamed to RTIOCollision

* the new API for DDS batches is:
with self.core_dds.batch:
...
with core_dds a device of type artiq.coredevice.dds.CoreDDS.
The dds_bus device should not be used anymore.
63 changes: 38 additions & 25 deletions artiq/coredevice/analyzer.py
Original file line number Diff line number Diff line change
@@ -40,31 +40,32 @@ def decode_message(data):


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


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

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

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


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


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


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


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


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


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

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

channel_handlers = create_channel_handlers(
vcd_manager, devices, ref_period,
dump.dds_channel, dump.dds_onehot_sel)
dds_sysclk, dump.dds_onehot_sel)
vcd_log_channels = get_vcd_log_channels(dump.log_channel, messages)
channel_handlers[dump.log_channel] = LogHandler(vcd_manager, vcd_log_channels)
slack = vcd_manager.get_channel("rtio_slack", 64)
3 changes: 2 additions & 1 deletion artiq/coredevice/core.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ def shorten_path(path):
lines = [shorten_path(path) for path in diagnostic.render(colored=colored)]
return "\n".join(lines)

colors_supported = (os.name == 'posix')
colors_supported = os.name == "posix"
class _DiagnosticEngine(diagnostic.Engine):
def render_diagnostic(self, diagnostic):
sys.stderr.write(_render_diagnostic(diagnostic, colored=colors_supported) + "\n")
@@ -49,6 +49,7 @@ def cache_get(key: TStr) -> TList(TInt32):
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
raise NotImplementedError("syscall not simulated")


class Core:
"""Core device driver.
58 changes: 33 additions & 25 deletions artiq/coredevice/dds.py
Original file line number Diff line number Diff line change
@@ -11,46 +11,52 @@


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

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

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

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


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

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

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


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

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

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


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

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

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

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

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

@kernel
def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT,
27 changes: 15 additions & 12 deletions artiq/gateware/rtio/core.py
Original file line number Diff line number Diff line change
@@ -130,24 +130,27 @@ def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
collision = Signal()
any_error = Signal()
nop = Signal()
self.sync.rsys += [
if interface.enable_replace:
# Note: replace may be asserted at the same time as 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
# so that they are mutually exclusive with collision errors.
sequence_error.eq(self.ev.timestamp[fine_ts_width:]
< buf.timestamp[fine_ts_width:])
]
if hasattr(self.ev, "a"):
different_addresses = self.ev.a != buf.a
self.sync.rsys += sequence_error.eq(self.ev.timestamp[fine_ts_width:] <
buf.timestamp[fine_ts_width:])
if interface.enable_replace:
if hasattr(self.ev, "a"):
different_addresses = self.ev.a != buf.a
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))
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.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
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
3 changes: 2 additions & 1 deletion artiq/gateware/rtio/phy/wishbone.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,8 @@ def __init__(self, address_width, wb=None):
rtlink.OInterface(
len(wb.dat_w),
address_width + 1,
suppress_nop=False),
suppress_nop=False,
enable_replace=False),
rtlink.IInterface(
len(wb.dat_r),
timestamped=False)
4 changes: 3 additions & 1 deletion artiq/gateware/rtio/rtlink.py
Original file line number Diff line number Diff line change
@@ -3,7 +3,8 @@

class OInterface:
def __init__(self, data_width, address_width=0,
fine_ts_width=0, suppress_nop=True):
fine_ts_width=0, suppress_nop=True,
enable_replace=True):
self.stb = Signal()
self.busy = Signal()

@@ -15,6 +16,7 @@ def __init__(self, data_width, address_width=0,
self.fine_ts = Signal(fine_ts_width)

self.suppress_nop = suppress_nop
self.enable_replace = enable_replace

@classmethod
def like(cls, other):
15 changes: 9 additions & 6 deletions artiq/gateware/targets/kc705.py
Original file line number Diff line number Diff line change
@@ -204,8 +204,9 @@ def __init__(self, cpu_type="or1k", **kwargs):
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))

self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels)
self.config["DDS_CHANNEL_COUNT"] = 8
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
self.config["RTIO_DDS_COUNT"] = 1
self.config["DDS_CHANNELS_PER_BUS"] = 8
self.config["DDS_AD9858"] = True
phy = dds.AD9858(platform.request("dds"), 8)
self.submodules += phy
@@ -277,8 +278,9 @@ def __init__(self, cpu_type="or1k", **kwargs):
rtio_channels.append(rtio.Channel.from_phy(
phy, ofifo_depth=128, ififo_depth=128))

self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels)
self.config["DDS_CHANNEL_COUNT"] = 11
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
self.config["RTIO_DDS_COUNT"] = 1
self.config["DDS_CHANNELS_PER_BUS"] = 11
self.config["DDS_AD9914"] = True
self.config["DDS_ONEHOT_SEL"] = True
phy = dds.AD9914(platform.request("dds"), 11, onehot=True)
@@ -331,8 +333,9 @@ def __init__(self, cpu_type="or1k", **kwargs):
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))

self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels)
self.config["DDS_CHANNEL_COUNT"] = 12
self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
self.config["RTIO_DDS_COUNT"] = 1
self.config["DDS_CHANNELS_PER_BUS"] = 12
self.config["DDS_AD9914"] = True
self.config["DDS_ONEHOT_SEL"] = True
phy = dds.AD9914(platform.request("dds"), 12, onehot=True)
Loading