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: aee0345ed75f
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: 8f952fdb9841
Choose a head ref
  • 5 commits
  • 1 file changed
  • 1 contributor

Commits on Aug 25, 2016

  1. Copy the full SHA
    7481d4e View commit details
  2. Copy the full SHA
    aabe53e View commit details
  3. Copy the full SHA
    eb180da View commit details
  4. doc/rtio: input vis

    jordens committed Aug 25, 2016
    Copy the full SHA
    446dcf2 View commit details
  5. doc/rtio: vis RTIOUnderflow

    jordens committed Aug 25, 2016
    Copy the full SHA
    8f952fd View commit details
Showing with 81 additions and 13 deletions.
  1. +81 −13 doc/manual/rtio.rst
94 changes: 81 additions & 13 deletions doc/manual/rtio.rst
Original file line number Diff line number Diff line change
@@ -52,14 +52,14 @@ The :meth:`artiq.coredevice.ttl.TTLOut.on` method places an rising edge on the t
Then the cursor is moved forward 2 µs and a falling edge event is placed at the new cursor position.
Then later, when the wall clock reaches the respective timestamps the RTIO gateware executes the two events.

The following diagram shows what is going on at the different levels of the software and gateware stack:
The following diagram shows what is going on at the different levels of the software and gateware stack (assuming one machine unit of time is 1 ns):

.. wavedrom::
{
signal: [
{name: 'kernel', wave: 'x22.2x', data: ['on()', 'delay(2*us)', 'off()'], node: '..A.XB'},
{name: 'now_mu', wave: '2...2.', data: ['7000', '9000'], node: '..P..Q'},
{name: 'slack', wave: 'x2x.2x', data: ['4400', '5800']},
{name: 'kernel', wave: 'x32.4x', data: ['on()', 'delay(2*us)', 'off()'], node: '..A.XB'},
{name: 'now', wave: '2...2.', data: ['7000', '9000'], node: '..P..Q'},
{name: 'slack', wave: 'x3x.4x', data: ['4400', '5800']},
{},
{name: 'rtio_counter', wave: 'x2x|2x|2x2x', data: ['2600', '3200', '7000', '9000'], node: ' V.W'},
{name: 'ttl', wave: 'x1.0', node: ' R.S', phase: -7.5},
@@ -93,6 +93,23 @@ The experiment attempts to handle the exception by moving the cursor forward and
delay(16.6667*ms)
ttl.on()

.. wavedrom::
{
signal: [
{name: 'kernel', wave: 'x34..2.3x', data: ['on()', 'RTIOUnderflow', 'delay(dt)', 'on()'], node: '..AB....C', phase: -3},
{name: 'now_mu', wave: '2.....2', data: ['t0', 't0+dt'], node: '.D.....E', phase: -4},
{},
{name: 'slack', wave: '2x....2', data: ['< 0', '> 0'], node: '.T', phase: -4},
{},
{name: 'rtio_counter', wave: 'x2x.........2x', data: ['t0', 't0+dt'], node: '............P'},
{name: 'tll', wave: 'x...........1', node: '.R..........S', phase: -.5}
],
edge: [
'A-~>R forbidden', 'D-~>R', 'T-~B exception',
'C~>S allowed', 'E~>S', 'P~>S'
]
}

To track down ``RTIOUnderflows`` in an experiment there are a few approaches:

* Exception backtraces show where underflow has occurred while executing the
@@ -115,6 +132,21 @@ The :meth:`artiq.coredevice.ttl.TTLInOut.count` method of an input channel can l
The :meth:`artiq.coredevice.ttl.TTLInOut.gate_rising` method leaves the timeline cursor at the closure time of the gate and ``count()`` must necessarily wait until the gate closing event has actually been executed which is sometime with ``rtio_counter > now``.
In these situations where ``count()`` leads to a synchronization of timeline cursor and wall clock, a ``delay()`` is necessary to reestablish positive slack so that output events can be placed.

.. wavedrom::
{
signal: [
{name: 'kernel', wave: '3..4|..2.5..x..', data: ['gate_rising()', 'count()', 'delay()', 'pulse()'], node: '.A.B...C.ZD.E'},
{name: 'now_mu', wave: '2.2.|....2.2.', node: '.P.Q.....XV.W'},
{},
{},
{name: 'input gate', wave: 'x1.0', node: '.T.U', phase: -3.5},
{name: 'output', wave: 'x1.0', node: '.R.S', phase: -11.5}
],
edge: [
'A~>T', 'P~>T', 'B~>U', 'Q~>U', 'U~>C', 'D~>R', 'E~>S', 'V~>R', 'W~>S'
]
}

Overflow exceptions
-------------------

@@ -129,28 +161,64 @@ Seamless handover
The timeline cursor persists across kernel invocations.
This is demonstrated in the following example where a pulse is split across two kernels:::

def run():
k1()
k2()

@kernel
def kernel1():
def k1():
ttl.on()
delay(1*s)

@kernel
def kernel2():
def k2():
ttl.off()

def run():
kernel1()
kernel2()
Here, ``run()`` calls ``k1()`` which exits leaving the cursor one second after the rising edge and ``k2()`` then submits a falling edge at that position.

.. wavedrom::
{
signal: [
{name: 'kernel', wave: '3.3..5..|4.', data: ['k1: on()', 'k1: delay(dt)', 'k1->k2 swap', 'k2: off()'], node: '..A........B'},
{name: 'now', wave: '2....2...|.', data: ['t0', 't0+dt'], node: '..P........Q'},
{},
{},
{name: 'rtio_counter', wave: 'x.........|2x|2', data: ['t0', 't0+dt'], node: '...........V..W'},
{name: 'ttl', wave: 'x1..0', node: '.R..S', phase: -10.5},
],
edge: [
'A~>R', 'P~>R', 'V~>R', 'B~>S', 'Q~>S', 'W~>S'
],
}

``kernel1()`` exits leaving the cursor one second after the rising edge and ``kernel2()`` then submits a falling edge at that position.

RTIO reset
-----------
Synchronization
---------------

The seamless handover of the timeline (cursor and events) across kernels and experiments implies that a kernel can exit long before the events it has submitted have been executed.
If a previous kernel sets timeline cursor far in the future this effectively locks the system.
It also means that a kernel is not guaranteed to always be executed with positive slack.
When a kernel should wait until all the events on a particular channel have been executed, use the :meth:`artiq.coredevice.ttl.TTLOut.sync` method of a channel:

.. wavedrom::
{
signal: [
{name: 'kernel', wave: 'x3x.|2.|x', data: ['on()', 'sync()'], node: '..A.....Y'},
{name: 'now', wave: '2..', data: ['7000'], node: '..P'},
{},
{},
{name: 'rtio_counter', wave: 'x2x.|..2x', data: ['2000', '7000'], node: ' ....V'},
{name: 'ttl', wave: 'x1', node: ' R', phase: -6.5},
],
edge: [
'A~>R', 'P~>R', 'V~>R', 'V~>Y'
],
}

RTIO reset
-----------

The seamless handover also means that a kernel is not guaranteed to always be executed with positive slack.
An experiment can face any of these circumstances (large positive slack, full FIFOs, or negative slack).
Therefore, when switching experiments it can be adequate to clear the RTIO FIFOs and initialize the timeline cursor to "sometime in the near future" using :meth:`artiq.coredevice.core.Core.reset`.
The example idle kernel implements this mechanism.
Since it never waits for any input, it will rapidly fill the output FIFOs and would produce a large positive slack.