Skip to content

Readout Pulse Generator Tab

The Readout Pulse Generator tab is the main control panel for readout measurement sequences. It is available on all SHFQC+ Instruments.

Features Overview

  • 1 Sequencer for each Readout Channel
  • 8 or 16 readout waveform memory slots, 4 kSa for each memory slot
  • 8 or 16 integration weights memory slots, 4 kSa for each memory slot
  • Sequence branching
  • Access to multiple internal triggers
  • Interface to DIO and ZSync for synchronization and feedback
  • High-level programming language
  • Display waveforms in waveform memory and integration weight units

Description

Table 1: App icon and short description
Control/Tool Option/Range Description
Generator Generate readout measurement sequences.

Figure 1: SHFQC+ Readout Pulse Generator Tab

The Sequencer Editor can be considered the central control unit of the Quantum Analyzer channel of the SHFQC+ as it has access to the playback of the Waveform Memories to generate Readout Pulses, the start of the Integration of the Readout Signals from the experiment and the communication with additional devices through the DIO or ZSync. The programming language SeqC is based on C and specified in detail in SeqC language. In contrast to other AWG Sequencers, e.g. from the HDAWG, it does not provide writing access to the Waveform Memories and hence does not come with predefined waveforms. The stricter separation between Sequencer and Waveform Memory allows implementation of more advanced and application-specific features, e.g. Time-Staggered Readout, while still providing real-time sequencing.

The Sequencer features a compiler which translates the high-level sequence program (SeqC) into machine instructions to be stored in the Instrument sequencer memory. The sequence program is written using high-level control structures and syntax that are inspired by human language, whereas machine instructions reflect exactly what happens on the hardware level. Writing the sequence program using SeqC represents a more natural and efficient way of working in comparison to writing lists of machine instructions, which is the traditional way of programming AWGs. Concretely, the improvements rely on features such as:

  • Waveform playback and sequencing in a single script
  • Easily readable syntax and naming for run-time variables and constants
  • Definition of user functions and procedures for advanced structuring
  • Syntax validation

By design, there is no one-to-one link between the list of statements in the high-level language and the list of instructions executed by the Sequencer. In order to understand the execution timing, it’s helpful to consider the internal architecture of the Readout Pulse Generator, consisting of the Sequencer itself, and the Waveform Memory including a Waveform Player.

On the Control sub-tab the user configures signal parameters and controls the execution of the sequencer. The sequencer can be started by clicking on Run/Stop. When enabling the Rerun button, the Sequencer will be restarted automatically when its program completes. The Compiler Status shows whether compilation is successful, or generated warnings or errors.

On the Trigger sub-tab users can configure the trigger inputs of the sequencer and control the Hardware Trigger Engine functionality of the Instrument. The sequencer can be triggered by Digital trigger source including DIO trigger, ZSync trigger, or the internal trigger unit. Only Digital trigger and DIO trigger are configured in this sub-tab. ZSync trigger is configured in Device Tab.The internal trigger is configured in the DIO Tab. There are 2 digital triggers that can be configured for each sequencer. The options of Digital trigger source include,

  • the physical trigger input A and B of all Quantum Analyzer channels,
  • the physical trigger input of all Signal Generator channels,
  • the sequencer trigger defined in all sequencers, such as through the command setTrigger,
  • the readout done of all Quantum Analyzer channels,
  • the internal trigger,
  • the software trigger.

The sequencer can also be triggered by DIO trigger input with chosen Valid bit and Polarity (see DIO Tab)

The Advanced sub-tab displays the compiled list of sequencer instructions and the current state of the sequencer on the Instrument. This can help an advanced user in debugging a sequence program and understanding its execution.

Sequencer Operation

Every pulse sequence requires defining a SeqC program. For an example of how to define and upload a sequence, see the Pulse Spectroscopy Tutorial. The status of the upload can be monitored via the Ready node. Once it returns true, the compilation is successful and the program is transferred to the device. If the compilation fails, the Status node will display debug messages.

After successful uploading of a sequence to the Instrument, the Sequencer can be started using the Enable node.

If the Sequencer should wait for a Trigger Input Signal, it can either directly wait for a ZSync Trigger, or access the Auxiliary Triggers.

With the SHFQC+ utility functions, the above-mentioned steps can be realized by a single function. A set of Python API examples can be found in GitHub

All nodes for the Sequencer can be accessed through the node trees,

/dev...​./qachannels/n/generator/...

and

/dev...​./qachannels/n/generator/sequencer/....

SeqC

The syntax of the LabOne AWG Sequencer programming language is based on C, but with a few simplifications. Each statement is concluded with a semicolon, several statements can be grouped with curly brackets, and comment lines are identified with a double slash.

The following example shows some of the fundamental functionalities: repeated playback, triggering, and single/dual-channel waveform playback and readout. See Tutorials for a step-by-step introduction with more examples. The command waitZSyncTrigger is used to wait a trigger from PQSC Programmable Quantum System Controller via ZSync. Alternatively, an external digital trigger from the front panel or an internal trigger can also be used to start the sequence by the command waitDigTrigger. The first playZero sets the delay between the trigger and the first readout pulse, and the second playZero sets the delay between the first and the second readout pulse. The command startQA sends out internal triggers to play readout pulses saved in the waveform memory, to start integrations with waveforms saved in the integration weight units, and to send a Sequencer monitor trigger which can be used to trigger the Scope. The third playZero ensures that the previous commands playZero are finished.

// repeat sequence 100 times
repeat (100) {
    // wait for a trigger over ZSync. Assume the trigger period is longer than the cycle time
    waitZSyncTrigger();

    // alternatively wait for a trigger from digital trigger 1
    // waitDigTrigger(1);

    // wait for 4096 Samples between the trigger and the first readout pulse
    // Note: this playZero command does not yet block the sequencer
    playZero(4096);

    // define how many samples to wait between the two upcoming startQA commands
    // Note: this command blocks the sequencer until the previous playZero command is finished
    playZero(4096);

    // play the pulse stored in Waveform Memory slot 0 and read out using Integration Weight 0
    startQA(QA_GEN_0, QA_INT_0, true,  0x0, 0x0);

    // minimal duration playZero command to wait until the previous playZero command is finished
    playZero(32);

    // play the pulse stored in Waveform Memory slot 0, 1 and 2, and read out using all Integration Weights
    startQA(QA_GEN_0|QA_GEN_1|QA_GEN_2, QA_INT_ALL, true,  0x0, 0x0);
}

Keywords and Comments

The following table lists the keywords used in the LabOne AWG Sequencer language.

Table 2: Programming keywords
Keyword Description
const Constant declaration
var Integer variable declaration
cvar Compile-time variable declaration
string Constant string declaration
true Boolean true constant
false Boolean false constant
for For-loop declaration
while While-loop declaration
repeat Repeat-loop declaration
if If-statement
else Else-part of an if-statement
switch Switch-statement
case Case-statement within a switch
default Default-statement within a switch
return Return from function or procedure, optionally with a return value

The following code example shows how to use comments.

const a = 10; // This is a line comment. Everything between the double
              // slash and the end of the line will be ignored.

/* This is a block comment. Everything between the start-of-block-comment and end-of-block-comment markers is ignored.

For example, the following statement will be ignored by the compiler.

const b = 100;
*/

Constants and Variables

Constants may be used to make the program more readable. They may be of integer or floating-point type. It must be possible for the compiler to compute the value of a constant at compile time, i.e., on the host computer. Constants are declared using the const keyword.

Compile-time variables may be used in computations and loop iterations during compile time, e.g. to create large numbers of waveforms in a loop. They may be of integer or floating-point type. They are used in a similar way as constants, except that they can change their value during compile time operations. Compile-time variables are declared using the cvar keyword.

Variables may be used for making simple computations during run time, i.e., on the Instrument. The Sequencer supports integer variables, addition, and subtraction. Not supported are floating-point variables, multiplication, and division. Typical uses of variables are to step waiting times, to output DIO values, or to tag digital measurement data with a numerical identifier. Variables are declared using the var keyword.

The following code example shows how to use variables.

var b = 100; // Create and initialize a variable

// Repeat the following block of statements 100 times
repeat (100) {
    b = b + 1; // Increment b
    wait(b);   // Wait 'b' cycles
}

The following table shows the predefined constants. These constants are intended to be used as arguments in certain run-time evaluated functions that encode device parameters with integer numbers.

Table 3: Predefined Constants
Name Value Description
M_E 2.71828182845904523536028747135266250 e
M_LOG2E 1.44269504088896340735992468100189214 log2(e)
M_LOG10E 0.434294481903251827651128918916605082 log10(e)
M_LN2 0.693147180559945309417232121458176568 loge(2)
M_LN10 2.30258509299404568401799145468436421 loge(10)
M_PI 3.14159265358979323846264338327950288 pi
M_PI_2 1.57079632679489661923132169163975144 pi/2
M_PI_4 0.785398163397448309615660845819875721 pi/4
M_1_PI 0.318309886183790671537767526745028724 1/pi
M_2_PI 0.636619772367581343075535053490057448 2/pi
M_2_SQRTPI 1.12837916709551257389615890312154517 2/sqrt(pi)
M_SQRT2 1.41421356237309504880168872420969808 sqrt(2)
M_SQRT1_2 0.707106781186547524400844362104849039 1/sqrt(2)

Numbers can be expressed using either of the following formatting.

const a = 10;           // Integer notation
const b = -10;          // Negative number
const h = 0xdeadbeef;   // Hexadecimal integer
const bin = 0b10101;    // Binary integer
const f = 0.1e-3;       // Floating point number.
const not_float = 10e3; // Not a floating point number

Booleans are specified with the keywords true and false. Furthermore, all numbers that evaluate to a nonzero value are considered true. All numbers that evaluate to zero are considered false.

Strings are delimited using "" and are interpreted as constants. Strings may be concatenated using the + operator.

string AWG_PATH = "awgs/0/";
string AWG_GAIN_PATH = AWG_PATH + "gains/0";

Waveform Playback and Predefined Functions

The following table contains the definition of functions for waveform playback and other purposes.

void setDIO(var value)

Writes the value as a 32-bit value to the DIO bus.

The value can be either a const or a var value. Configure the Mode setting in the DIO tab when using this command. The DIO interface speed of 50 MHz limits the rate at which the DIO output value is updated.

Args:

  • value: The value to write to the DIO (const or var)
var getDIO()

Reads a 32-bit value from the DIO bus.

Returns:

var containing the read value

var getDIOTriggered()

Reads a 32-bit value from the DIO bus as recorded at the last DIO trigger position.

Returns:

var containing the read value

void setTrigger(var value)

Sets the Sequencer Trigger output signals.

The state of the two Sequencer Trigger output signals is defined by the bits in the binary representation of the integer value. Allowed parameter values are 0 to 3. For higher integer values, only the two least-significant bits will have an effect.Binary notation of the form 0b00 is recommended for readability.

Args:

  • value: to be written to the trigger distribution unit
void wait(var cycles)

Waits for the given number of Sequencer clock cycles (4 ns per cycle). The execution of the instruction adds an offset of 2 clock cycles, i.e., the statement wait(3) leads to a waiting time of 5 * 4 ns = 20 ns.

Note: the minimum waiting time amounts to 3 cycles, which means that wait(0) and wait(1) will both result in a waiting time of 3 * 4 ns = 12 ns.

Args:

  • cycles: number of cycles to wait
void waitDIOTrigger()

Waits until the DIO interface trigger is active. The trigger is specified by the Strobe Index and Strobe Slope settings in the AWG Sequencer tab.

var getDigTrigger(const index)

Gets the state of the indexed Digital Trigger input (1 or 2).

The physical signal connected to the Digital Trigger input is to be configured in the Readout section of the Quantum Analyzer Setup tab.

Args:

  • index: index of the Digital Trigger input to be read; can be either 1 or 2

Returns:

trigger state, either 0 or 1

void error(string msg,...)

Throws the given error message when reached.

Args:

  • msg: Message to be displayed
void info(string msg,...)

Returns the specified message when reached.

Args:

  • msg: Message to be displayed
void setUserReg(const register, var value)

Writes a value to one of the User Registers (indexed 0 to 15).

The User Registers may be used for communicating information to the LabOne User Interface or a running API program.

Args:

  • register: The register index (0 to 15) to be written to

  • value: The integer value to be written

var getUserReg(const register)

Reads the value from one of the User Registers (indexed 0 to 15). The User Registers may be used for communicating information to the LabOne User Interface or a running API program.

Args:

  • register: The register to be read (0 to 15)

Returns:

current register value

void playZero(var samples)

Zero Playback, which can be used to specify spacings in number of samples at the sample rate of 2 GSa/s between the execution times of commands, such as startQA. Each playZero command blocks the execution of subsequent commands when a previous Zero Playback is already running. Note: the playback of actual waveforms with the startQA command happens in parallel to the Zero Playback, in contrast to the HDAWG and SHFSG!

Args:

  • samples: Number of samples for the spacing. The minimal spacing is 32 samples and the granularity is 16 samples.
void playZero(var samples, const rate)

Zero Playback, which can be used to specify spacings in number of samples between the execution times of commands, such as startQA. Each playZero command blocks the execution of subsequent commands when a previous Zero Playback is already running. Note: the playback of actual waveforms with the startQA command happens in parallel to the Zero Playback, in contrast to the HDAWG and SHFSG!

Args:

  • rate: Sample rate with which the spacing is specified. Divides the device sample rate by 2^rate. Note: this rate does not affect the sample rate of the QA waveform generator (startQA command).

  • samples: Number of samples for the spacing. The minimal spacing is 32 samples and the granularity is 16 samples.

void waitDigTrigger(const index)

Waits for the reception of a trigger signal on the indexed Digital Trigger (index 1 or 2). The physical signals connected to the two AWG Digital Triggers are to be configured in the Trigger sub-tab of the AWG Sequencer tab. The Digital Triggers are configured separately for each AWG Core.

Args:

  • index: Index of the digital trigger input; can be either 1 or 2.
void configFreqSweep(const oscillator_index, const freq_start, const freq_increment)

Configures a frequency sweep.

Args:

  • freq_increment: Specify how much to increment the frequency for each step of the sweep [Hz]

  • freq_start: Specify the start frequency value for the sweep [Hz]

  • oscillator_index: Index of the oscillator that will be used for the sweep

void resetOscPhase(const mask)
void resetOscPhase()

Reset the phase of the oscillator controllable by the sequencer. Each sequencer can control the oscillator of its QACHANNEL.

void setSweepStep(const oscillator_index, var sweep_index)

Executes a step within a frequency sweep.

Args:

  • oscillator_index: Index of the oscillator that will be used for the sweep

  • sweep_index: Sets the step index, from which the frequency is set

void setOscFreq(const oscillator_index, const freq)

Configures the frequency of an oscillator.

Args:

  • freq: Frequency to be set [Hz]

  • oscillator_index: Index of oscillator

var getFeedback(const data_type)

Read the last received feedback message. The argument specify which data the function should return.

Args:

  • data_type: Specifies which data the function should return: ZSYNC_DATA_RAW: Returns the last ZSync message received.

Returns:

var containing the read value

var getFeedback(const data_type, var wait_cycles)

Read the last received feedback message. The argument specify which data the function should return.

Args:

  • data_type: Specifies which data the function should return: ZSYNC_DATA_RAW: Returns the last ZSync message received.

  • wait_cycles: Wait for the specified number of cycles after the most recent waitZSyncTrigger() instruction.

Returns:

var containing the read value

void waitZSyncTrigger()

Waits for a trigger over ZSync.

void startQA(const waveform_generator_mask, const weighted_integrator_mask, const monitor, const result_address, const trigger)

Starts the Quantum Analysis (QA) Readout Waveform Generation, Integration, and Result units.

Args:

  • monitor: Enable the Sequencer Monitor Trigger, which is issued simultaneously with the start of the weighted integration units. In addition to setting this argument to true, the Sequencer Monitor Trigger must be selected as trigger source for the SHFQA Scope in order to align the start of the time trace to the start of the weighted integration. Default: false.

  • result_address: Specify the address of the PQSC readout register in which to store the readout result from this SHFQA. Please refer to the PQSC user manual for more details. Default: 0x0

  • trigger: Sets the sequencer trigger output in the same manner as the setTrigger() command. Default: 0b00

  • waveform_generator_mask: Readout Waveform Generator unit enable mask. Providing a value for this argument is mandatory. The mask can be specified using the predefined constants QA_GEN_n, where n is an index ranging from 0 to 15, except for the 2-channel SHFQA without 16W option, where the range only spans from 0 to 7. To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator | (bit-wise OR). The constant QA_GEN_ALL can be used to enable all units simultaneously. NOTE: the signals from simultaneously enabled Waveform Generation units are combined by a digital adder.

  • weighted_integrator_mask: Integration unit enable mask, default: QA_INT_ALL The mask can be specified using the predefined constants QA_INT_n, where n is an index ranging from 0 to 15, except for the 2-channel SHFQA without 16W option, where the range only spans from 0 to 7. To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator | (bit-wise OR). The constant QA_INT_ALL can be used to enable all units simultaneously.

Expressions

Expressions may be used for making computations based on mathematical functions and operators. There are two kinds of expressions: those evaluated at compile time (when the sequencer program is compiled on the computer), and those evaluated at run time.

Compile-time evaluated expressions only involve constants (const) or compile-time variables (cvar) and can be computed at compile time by the host computer. Such expressions can make use of standard mathematical functions and floating point arithmetic.

Run-time evaluated expressions involve variables (var) and are evaluated by the Sequencer on the Instrument. Due to the limited computational capabilities of the Sequencer, these expressions may only operate on integer numbers and there are less operators available than at compile time.

The following table contains the list of mathematical functions supported at compile time.

Table 4: Mathematical Functions
Function Description
const abs(const c) absolute value
const acos(const c) inverse cosine
const acosh(const c) hyperbolic inverse cosine
const asin(const c) inverse sine
const asinh(const c) hyperbolic inverse sine
const atan(const c) inverse tangent
const atanh(const c) hyperbolic inverse tangent
const cos(const c) cosine
const cosh(const c) hyperbolic cosine
const exp(const c) exponential function
const ln(const c) logarithm to base e (2.71828...)
const log(const c) logarithm to the base 10
const log2(const c) logarithm to the base 2
const log10(const c) logarithm to the base 10
const sign(const c) sign function -1 if x<0; 1 if x>0
const sin(const c) sine
const sinh(const c) hyperbolic sine
const sqrt(const c) square root
const tan(const c) tangent
const tanh(const c) hyperbolic tangent
const ceil(const c) smallest integer value not less than the argument
const round(const c) round to nearest integer
const floor(const c) largest integer value not greater than the argument
const avg(const c1, const c2,...) mean value of all arguments
const max(const c1, const c2,...) maximum of all arguments
const min(const c1, const c2,...) minimum of all arguments
const pow(const base, const exp) first argument raised to the power of second argument
const sum(const c1, const c2,...) sum of all arguments

The following table contains the list of predefined mathematical constants. These can be used for convenience in compile-time evaluated expressions.

Table 5: Predefined Constants
Name Value Description
AWG_RATE_2000MHZ 0 Constant to set Sampling Rate to 2.0 GHz.
AWG_RATE_1000MHZ 1 Constant to set Sampling Rate to 1.0 GHz.
AWG_RATE_500MHZ 2 Constant to set Sampling Rate to 500 MHz.
AWG_RATE_250MHZ 3 Constant to set Sampling Rate to 250 MHz.
AWG_RATE_125MHZ 4 Constant to set Sampling Rate to 125 MHz.
AWG_RATE_62P5MHZ 5 Constant to set Sampling Rate to 62.5 MHz.
AWG_RATE_31P25MHZ 6 Constant to set Sampling Rate to 31.25 MHz.
AWG_RATE_15P63MHZ 7 Constant to set Sampling Rate to 15.63 MHz.
AWG_RATE_7P81MHZ 8 Constant to set Sampling Rate to 7.81 MHz.
AWG_RATE_3P9MHZ 9 Constant to set Sampling Rate to 3.9 MHz.
AWG_RATE_1P95MHZ 10 Constant to set Sampling Rate to 1.95 MHz.
AWG_RATE_976KHZ 11 Constant to set Sampling Rate to 976 kHz.
AWG_RATE_488KHZ 12 Constant to set Sampling Rate to 488 kHz.
AWG_RATE_244KHZ 13 Constant to set Sampling Rate to 244 kHz.
DEVICE_SAMPLE_RATE <actual device sample rate>
ZSYNC_DATA_RAW opaque
Constant to use as argument to getFeedback. Returns the last ZSync message received.
QA_INT_0 (1 << 0)
Constant to enable Integration unit 0 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_1 (1 << 1)
Constant to enable Integration unit 1 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_2 (1 << 2)
Constant to enable Integration unit 2 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_3 (1 << 3)
Constant to enable Integration unit 3 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_4 (1 << 4)
Constant to enable Integration unit 4 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_5 (1 << 5)
Constant to enable Integration unit 5 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_6 (1 << 6)
Constant to enable Integration unit 6 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_7 (1 << 7)
Constant to enable Integration unit 7 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_8 (1 << 8)
Constant to enable Integration unit 8 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_9 (1 << 9)
Constant to enable Integration unit 9 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_10 (1 << 10)
Constant to enable Integration unit 10 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_11 (1 << 11)
Constant to enable Integration unit 11 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_12 (1 << 12)
Constant to enable Integration unit 12 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_13 (1 << 13)
Constant to enable Integration unit 13 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_14 (1 << 14)
Constant to enable Integration unit 14 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_15 (1 << 15)
Constant to enable Integration unit 15 in the Integration unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_INT_ALL (1 << 16) - 1
Constant to enable all Integration units in the Integration unit enable mask of the function startQA().
QA_GEN_0 (1 << 0)
Constant to enable Readout Waveform Generator unit 0 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_1 (1 << 1)
Constant to enable Readout Waveform Generator unit 1 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_2 (1 << 2)
Constant to enable Readout Waveform Generator unit 2 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_3 (1 << 3)
Constant to enable Readout Waveform Generator unit 3 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_4 (1 << 4)
Constant to enable Readout Waveform Generator unit 4 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_5 (1 << 5)
Constant to enable Readout Waveform Generator unit 5 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_6 (1 << 6)
Constant to enable Readout Waveform Generator unit 6 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_7 (1 << 7)
Constant to enable Readout Waveform Generator unit 7 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_8 (1 << 8)
Constant to enable Readout Waveform Generator unit 8 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_9 (1 << 9)
Constant to enable Readout Waveform Generator unit 9 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_10 (1 << 10)
Constant to enable Readout Waveform Generator unit 10 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_11 (1 << 11)
Constant to enable Readout Waveform Generator unit 11 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_12 (1 << 12)
Constant to enable Readout Waveform Generator unit 12 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_13 (1 << 13)
Constant to enable Readout Waveform Generator unit 13 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_14 (1 << 14)
Constant to enable Readout Waveform Generator unit 14 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_15 (1 << 15)
Constant to enable Readout Waveform Generator unit 15 in the Readout Waveform Generator unit enable mask of the function startQA(). To construct more elaborate masks that enable multiple units, combine these predefined constants using the operator
QA_GEN_ALL (1 << 16) - 1
Constant to enable all Waveform Generator units in the waveform generator unit enable mask of the function startQA().

Control Structures

Functions may be declared using the var keyword. Procedures may be declared using the void keyword. Functions must return a value, which should be specified using the return keyword. Procedures can not return values. Functions and procedures may be declared with an arbitrary number of arguments. The return keyword may also be used without arguments to return from an arbitrary point within the function or procedure. Functions and procedures may contain variable and constant declarations. These declarations are local to the scope of the function or procedure.

var function_name(argument1, argument2, ...) {
    // Statements to be executed as part of the function.
    return constant-or-variable;
}
void procedure_name(argument1, argument2, ...) {
    // Statements to be executed as part of the procedure.

    // Optional return statement
    return;
}

An if-then-else structure is used to create a conditional branching point in a sequencer program.

// If-then-else statement syntax
if (expression) {
    // Statements to execute if 'expression' evaluates to 'true'.
} else {
    // Statements to execute if 'expression' evaluates to 'false'.
}

// If-then-else statement short syntax
(expression)?(statement if true):(statement if false)

// If-then-else statement example
const REQUEST_BIT = 0x0001;
const ACKNOWLEDGE_BIT = 0x0002;
const IDLE_BIT = 0x8000;
var dio = getDIO();

if (dio & REQUEST_BIT) {
    dio = dio | ACKNOWLEDGE_BIT;
    setDIO(dio);
} else {
    dio = dio | IDLE_BIT;
    setDIO(dio);
}

A switch-case structure serves to define a conditional branching point similarly to the if-then-else statement, but is used to split the sequencer thread into more than two branches. Unlike the if-then-else structure, the switch statement is synchronous, which means that the execution time is the same for all branches and determined by the execution time of the longest branch. If no default case is provided and no case matches the condition, all cases will be skipped. The case arguments need to be of type const.

// Switch-case statement syntax
switch (expression) {
    case const-expression:
        expression;
    ...
default:
    expression;
}
// Switch-case statement example
switch (getDIO()) {
    case 0:
        startQA(QA_GEN_0, QA_INT_0, true,  0x0, 0x0);
    case 1:
        startQA(QA_GEN_1, QA_INT_1, true,  0x0, 0x0);
    case 2:
        startQA(QA_GEN_2, QA_INT_2, true,  0x0, 0x0);
    default:
        startQA(QA_GEN_3, QA_INT_3, true,  0x0, 0x0);
}

The for loop is used to iterate through a code block several times. The initialization statement is executed before the loop starts. The end-expression is evaluated at the start of each iteration and determines when the loop should stop. The loop is executed as long as this expression is true. The iteration-expression is executed at the end of each loop iteration. Depending on how the for loop is set up, it can be either evaluated at compile time or at run time. For a run-time evaluated for loop, use the var data type as a loop index. To ensure that a loop is evaluated at compile time, use the cvar data type as a loop index. Furthermore, the compile-time for loop should only contain waveform generation/editing operations and it can’t contain any variables of type var.

The following code example shows both versions of the loop.

// For loop syntax
for (initialization; end-expression; iteration-expression) {
    // Statements to execute while end-expression evaluates to true
}

// For loop example (compile-time execution)
cvar i;
wave w_pulses;
for (i = 0; i < 10; i = i + 1) {
    startQA(QA_GEN_0<<1, QA_INT_0, true,  0x0, 0x0);
}

// For loop example (run-time execution)
var k;
var j;
for (j = 9; j >= 0; j = j - 1) {
    startQA(QA_GEN_0, QA_INT_0, true,  0x0, 0x0);
    k += j;
}

The while loop is a simplified version of the for loop. The end-expression is evaluated at the start of each loop iteration. The contents of the loop are executed as long as this expression is true. Like the for loop, this loop comes in a compile-time version (if the end-expression involves only cvar and const) and in a run-time version (if the end-expression involves also var data types).

// While loop syntax
while (end-expression) {
    // Statements to execute while end-expression evaluates to true
}

// While loop example
const STOP_BIT = 0x8000;
var run = 1;
var i = 0;
var dio = 0;
while (run) {
    dio = getDIO();
    run = dio & STOP_BIT;
    dio = dio | (i & 0xff);
    setDIO(dio);
    i = i + 1;
}

The repeat loop is a simplified version of the for loop. It repeats the contents of the loop a fixed number of times. In contrast to the for loop, the repetition number of the repeat loop must be known at compile time, i.e., const-expression can only depend on constants and not on variables. Unlike the for and the while loop, this loop comes only in a run-time version. Thus, no cvar data types may be modified in the loop body.

// Repeat loop syntax
repeat (constant-expression) {
    // Statements to execute
}

// Repeat loop example
repeat (100) {
    setDIO(0x1);
    wait(10);
    setDIO(0x0);
    wait(10);
}

Waveform Memory

The Waveform Memory stores the different complex-valued arbitrary waveforms that are used to readout the qubits. They can be accessed through /dev...​./qachannels/n/generator/waveforms/n/wave and have a maximal length of 4096 samples and a vertical range between -1 and 1 relative to the full scale of the Output Range.

Functional Elements

Table 6: SHFQC+ Readout Pulse Generator: Control sub-tab
Control/Tool Option/Range Description
Start ON/OFF Run the Generator Sequencer.
Rerun ON/OFF Puts the Sequencer into single-shot mode or rerun mode.
Status Display compiler errors and warnings.
Compile Status grey/green/yellow/red Sequence program compilation status. Grey: No compilation started yet. Green: Compilation successful. Yellow: Compiler warnings (see status field). Red: Compilation failed (see status field).
Upload Progress 0% to 100% The percentage of the sequencer program already uploaded to the device.
Upload Status grey/yellow/green Indicates the upload status of the compiled sequence. Grey: Nothing has been uploaded. Yellow: Upload in progress. Green: Compiled sequence has been uploaded.
Register Selector 1 to 16 Select the number of the user register value to be edited.
Register 0 to \(2^{32}\) Integer user register value. The sequencer has reading and writing access to the user register values during run time.
Input File External source code file to be compiled.
Example File Load pre-installed example sequence program.
New Create a new sequence program.
Revert Undo the changes made to the current program and go back to the contents of the original file.
Save (Ctrl+S) Compile and save the current program displayed in the Sequence Editor. Overwrites the original file.
Save As...​ (Ctrl+Shift+S) Compile and save the current program displayed in the Sequence Editor under a new name.
Automatic Upload ON / OFF If enabled, the sequence program is automatically uploaded to the device after clicking Save and if the compilation was successful.
To Device Sequence program will be compiled and, if the compilation was successful, uploaded to the device.
Table 7: SHFQC+ Readout Pulse Generator: Trigger sub-tab
Control/Tool Option/Range Description
Status grey/green/yellow/red Displays the status of the sequence on the Instrument. Off: Ready, not running. Green: Running, not waiting for any trigger event. Yellow: Running, waiting for a trigger event. Red: Not Ready.
Digital Trigger 1 or 2 Choose Digital Trigger 1 or Digital Trigger 2
Signal Selects Digital Trigger source signal. Navigate through the tree view that appears and click on the required signal.
Valid Index Selects the index n of the DIO interface bit (notation DIO[n] in the Specification chapter of the User Manual) to be used as a VALID signal input, i.e. a qualifier indicating that a valid codeword is available on the DIO interface.
Valid Polarity Polarity of the VALID bit that indicates that a codeword is available on the DIO interface.
Low VALID bit must be logical low.
High VALID bit must be logical high.
Both VALID bit may be logical high or logical low.
None VALID bit is ignored.
Table 8: SHFQC+ Readout Pulse Generator: Advanced sub-tab
Control/Tool Option/Range Description
Assembly string Displays the current sequence program in compiled form. Every line corresponds to one hardware instruction and requires one clock cycle (4 ns) for execution.
Status running/idle/waiting Displays the status of the sequencer on the Instrument. Off: Ready, not running. Green: Running, not waiting for any trigger event. Yellow: Running, waiting for a trigger event. Red: Not ready (e.g., pending elf download, no elf downloaded)
Mem Usage 0% to 100% Size of the current sequence program relative to the device cache memory. The cache memory provides space for a maximum of 16384 instructions.