qick.qick_asm

The interface for writing QICK programs. This contains tools for managing the board configuration and the base class for QICK programs. The assembly language for QICK programs is defined separately for the v1 and v2 tProcessors.

Classes

AbsQickProgram(soccfg)

Generic QICK program, including support for generator and readout configuration but excluding tProc-specific code.

AcquireMixin(*args, **kwargs)

Adds acquire() and acquire_decimated() methods for acquiring readout data, and run_rounds() for running repeatedly without acquisition.

DummyIp(iptype, fullpath)

Stores the configuration constants for a firmware IP block.

QickConfig([cfg])

Uses the QICK configuration to convert frequencies and clock delays.

class qick.qick_asm.QickConfig(cfg=None)[source]

Bases: object

Uses the QICK configuration to convert frequencies and clock delays. If running on the QICK, you don’t need to use this class - the QickSoc class has all of the same methods. If running remotely, you may want to initialize a QickConfig from a JSON file.

Parameters:

cfg (dict or str) – config dictionary, or path to JSON file

description()[source]

Generate a printable description of the QICK configuration.

Returns:

description

Return type:

str

get_cfg()[source]

Return the QICK configuration dictionary. This contains everything you need to recreate the QickConfig.

Returns:

configuration dictionary

Return type:

dict

dump_cfg()[source]

Generate a JSON description of the QICK configuration. You can save this string to a file and load it to recreate the QickConfig.

Returns:

configuration in JSON format

Return type:

str

calc_fstep_int(dict1, other_dicts)[source]

Finds the multiplier that needs to be applied to a channel’s frequency step size to allow this channel to be frequency-matched with another channel.

Parameters:
  • dict1 (dict) – config dict for this channel

  • other_dicts (list of dict) – config dict for the other channel(s)

Returns:

frequency step multiplier for the first channel

Return type:

int

ch_fstep(dict1)[source]

Finds the frequency step size of a single channel (generator or readout).

Parameters:

dict1 (dict) – config dict for one channel

Returns:

frequency step for this channel

Return type:

float

calc_fstep(dicts)[source]

Finds the least common multiple of the frequency steps of one or more channels (typically two, a generator and a readout) For proper frequency matching, you should only use frequencies that are evenly divisible by this value. The order of the parameters does not matter.

Parameters:

dicts (list of dict) – config dict for the channels

Returns:

frequency step common to all channels

Return type:

float

roundfreq(f, dicts)[source]

Round a frequency to the LCM of the frequency steps of one or more channels (typically two, a generator and a readout).

Parameters:
  • f (float or array) – frequency (MHz)

  • dicts (list of dict) – config dict for the channels

Returns:

rounded frequency (MHz)

Return type:

float or array

freq2int(f, thisch, otherch=None)[source]

Converts frequency in MHz to integer value suitable for writing to a register. This method works for both generators and readouts. If a gen will be connected to an RO, the two channels must have exactly the same frequency, and you must supply the config for the other channel.

Parameters:
  • f (float) – frequency (MHz)

  • thisch (dict) – config dict for the channel you’re configuring

  • otherch (dict) – config dict for a channel you will set to the same frequency

Returns:

Re-formatted frequency

Return type:

int

int2freq(r, thisch)[source]

Converts register value to MHz. This method works for both generators and readouts.

Parameters:
  • r (int) – register value

  • thisch (dict) – config dict for the channel you’re configuring

Returns:

Re-formatted frequency (MHz)

Return type:

float

freq2reg(f, gen_ch=0, ro_ch=None)[source]

Converts frequency in MHz to tProc generator register value.

Parameters:
  • f (float) – frequency (MHz)

  • gen_ch (int) – generator channel

  • ro_ch (int) – readout channel (use None if you don’t want to frequency-match to a readout)

Returns:

Re-formatted frequency

Return type:

int

freq2reg_adc(f, ro_ch=0, gen_ch=None)[source]

Converts frequency in MHz to readout register value.

Parameters:
  • f (float) – frequency (MHz)

  • ro_ch (int) – readout channel

  • gen_ch (int) – generator channel (use None if you don’t want to frequency-match to a generator)

Returns:

Re-formatted frequency

Return type:

int

reg2freq(r, gen_ch=0)[source]

Converts frequency from format readable by generator to MHz.

Parameters:
  • r (int) – frequency in generator format

  • gen_ch (int) – generator channel

Returns:

Re-formatted frequency in MHz

Return type:

float

reg2freq_adc(r, ro_ch=0)[source]

Converts frequency from format readable by readout to MHz.

Parameters:
  • r (int) – frequency in readout format

  • ro_ch (int) – readout channel

Returns:

Re-formatted frequency in MHz

Return type:

float

adcfreq(f, gen_ch=0, ro_ch=0)[source]

Takes a frequency and trims it to the closest DDS frequency valid for both channels.

Parameters:
  • f (float) – frequency (MHz)

  • gen_ch (int) – generator channel

  • ro_ch (int) – readout channel

Returns:

Re-formatted frequency

Return type:

float

deg2int(deg, thisch)[source]

Converts phase in degrees to integer value suitable for writing to a register. This method works for both generators and readouts.

Parameters:
  • deg (float) – phase (degrees)

  • thisch (dict) – config dict for the channel you’re configuring

Returns:

Re-formatted phase

Return type:

int

int2deg(r, thisch)[source]

Converts register value to degrees. This method works for both generators and readouts.

Parameters:
  • r (int) – register value

  • thisch (dict) – config dict for the channel you’re configuring

Returns:

Re-formatted phase (degrees)

Return type:

float

deg2reg(deg, gen_ch=0, ro_ch=None)[source]

Converts degrees into phase register values; numbers greater than 360 will effectively be wrapped.

Parameters:
  • deg (float) – Number of degrees

  • gen_ch (int) – generator channel (index in ‘gens’ list)

  • ro_ch (int) – readout channel (index in ‘readouts’ list)

Returns:

Re-formatted number of degrees

Return type:

int

reg2deg(r, gen_ch=0, ro_ch=None)[source]

Converts phase register values into degrees.

Parameters:
  • reg (int) – Re-formatted number of degrees

  • gen_ch (int) – generator channel (index in ‘gens’ list)

  • ro_ch (int) – readout channel (index in ‘readouts’ list)

Returns:

Number of degrees

Return type:

float

cycles2us(cycles, gen_ch=None, ro_ch=None)[source]

Converts clock cycles to microseconds. Uses tProc clock frequency by default. If gen_ch or ro_ch is specified, uses that generator/readout channel’s fabric clock.

Parameters:
  • cycles (int) – Number of clock cycles

  • gen_ch (int) – generator channel (index in ‘gens’ list)

  • ro_ch (int) – readout channel (index in ‘readouts’ list)

Returns:

Number of microseconds

Return type:

float

us2cycles(us, gen_ch=None, ro_ch=None)[source]

Converts microseconds to integer number of clock cycles. Uses tProc clock frequency by default. If gen_ch or ro_ch is specified, uses that generator/readout channel’s fabric clock.

Parameters:
  • us (float) – Number of microseconds

  • gen_ch (int) – generator channel (index in ‘gens’ list)

  • ro_ch (int) – readout channel (index in ‘readouts’ list)

Returns:

Number of clock cycles

Return type:

int

calc_mixer_freq(gen_ch, mixer_freq, nqz, ro_ch)[source]

Set the NCO frequency that will be mixed with the generator output.

The RFdc driver does its own math to convert a frequency to a register value. (see XRFdc_SetMixerSettings in xrfdc_mixer.c, and “NCO Frequency Conversion” in PG269) This is what it does: 1. Add/subtract fs to get the frequency in the range of [-fs/2, fs/2]. 2. If the original frequency was not in [-fs/2, fs/2] and the DAC is configured for 2nd Nyquist zone, multiply by -1. 3. Convert to a 48-bit register value, rounding using C integer casting (i.e. round towards 0).

Step 2 is not desirable for us, so we must undo it.

The rounding gives unexpected results sometimes: it’s hard to tell if a freq will get rounded up or down. This is important if the demanded frequency was rounded to a valid frequency for frequency matching. The safest way to get consistent behavior is to always round to a valid NCO frequency. We are trusting that the floating-point math is exact and a number we rounded here is still a round number in the RFdc driver.

calc_muxgen_regs(gen_ch, freqs, gains, phases, ro_ch)[source]

Calculate the register values to program into a multiplexed generator.

calc_ro_regs(rocfg, phase, sel)[source]

Calculate the settings to configure a readout.

Returns:

settings for QickSoc.config_readout()

Return type:

dict

calc_ro_freq(rocfg, ro_pars, ro_regs, mixer_freq)[source]

Calculate the readout frequency and registers.

check_pfb_collisions(rocfg, cfg1, cfgs)[source]

Check whether the specified PFB config collides or interefers with any others. If this PFB block can’t put two readouts on the same channel, this method will raise an error on collisions. Possible crosstalk will be identified in warnings.

Parameters:
  • rocfg (dict) – firmware config dictionary for the PFB or the readout chain

  • cfg1 (dict) – PFB config to check

  • cfgs (list of dict) – PFB configs to check cfg1 against

class qick.qick_asm.DummyIp(iptype, fullpath)[source]

Bases: object

Stores the configuration constants for a firmware IP block.

class qick.qick_asm.AbsQickProgram(soccfg)[source]

Bases: object

Generic QICK program, including support for generator and readout configuration but excluding tProc-specific code. QickProgram/QickProgramV2 are the concrete subclasses for tProc v1/v2.

The tProc executes binary machine code; you write declarations and ASM code (or macros that get expanded to ASM). So before a program gets run, you need to fill it with declarations and ASM, and they need to get compiled (converted to machine code). There are three ways to prepare a QickProgram for running:

1. External initialization: Create an empty program object. Write the program by calling declaration and ASM methods of the program object. The program will be compiled when you try to run, dump, or print it.

2. Internal initialization: Create a subclass which calls declaration and ASM methods as part of __init__(). When you create an instance of the subclass, it will automatically fill itself. Typically you won’t subclass QickProgram directly, you will subclass something like AveragerProgram which does a lot of the work for you. The program will be compiled when you try to run, dump, or print.

3. Loading a dump: Create an empty program object. Call QickProgram.load_prog() to load the program definition from a dump. The program will be compiled as part of load_prog().

abstract compile()[source]

Fills self.binprog with a binary representation of the program.

dump_prog()[source]

Dump the program to a dictionary. This output contains all the information necessary to run the program. In other words, it will have the low-level ASM and pulse+envelope data, but not higher-level structures. Caution: don’t modify the sub-dictionaries of this dict! You will be modifying the original program (this is not a deep copy).

load_prog(progdict)[source]

Load the program from a dictionary.

config_all(soc, load_pulses=True, reset=False)[source]

Load the waveform memory, gens, ROs, and program memory as specified for this program. The decimated+accumulated buffers are not configured, since those should be re-configured for each acquisition. The tProc is set to internal start before any other configuration is done, to prevent spurious external starts.

Parameters:

reset (bool) – Force-stop the tProc before loading the program. This option only affects tProc v1, where the reset takes several ms. For tProc v2, where reset is easy, we always do the reset.

run(soc, load_prog=True, load_pulses=True, start_src='internal')[source]

Load the program into the tProcessor and start it. Because there is in general no way to tell when a program is done running, there is no guarantee that the program will be done before this method returns. If you want that guarantee, use run_rounds().

Parameters:
  • soc (QickSoc) – The QickSoc that will execute this program.

  • load_prog (bool) – Load the program before starting the tProc.

  • load_pulses (bool) – Load the generator envelopes before starting the tProc. If load_prog is False, load_pulses is ignored.

  • start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger).

declare_readout(ch, length, freq=None, phase=0, sel='product', gen_ch=None)[source]

Add a channel to the program’s list of readouts. Duration units depend on the program type: tProc v1 programs use integer number of samples, tProc v2 programs use float us.

Parameters:
  • ch (int) – readout channel number (index in ‘readouts’ list)

  • freq (float) – downconverting frequency (MHz)

  • phase (float) – phase (degrees)

  • length (int or float) – readout length (number of decimated samples for tProc v1, us for tProc v2)

  • sel (str) – output select (‘product’, ‘dds’, ‘input’)

  • gen_ch (int) – generator channel (use None if you don’t want the downconversion frequency to be rounded to a valid DAC frequency or be offset by the DAC mixer frequency)

config_readouts(soc)[source]

Configure the readout channels specified in this program. This is usually called as part of an acquire() method.

Parameters:

soc (QickSoc) – the QickSoc that will execute this program

config_bufs(soc, enable_avg=True, enable_buf=True)[source]

Configure the readout buffers specified in this program. This is usually called as part of an acquire() method.

Parameters:
  • soc (QickSoc) – the QickSoc that will execute this program

  • enable_avg (bool) – enable the accumulated (averaging) buffer

  • enable_buf (bool) – enable the decimated (waveform) buffer

declare_gen(ch, nqz=1, mixer_freq=None, mux_freqs=None, mux_gains=None, mux_phases=None, ro_ch=None)[source]

Add a channel to the program’s list of signal generators.

If this is a generator with a mixer (interpolated or muxed generator), you may define a mixer frequency.

If this is a muxed generator, the mux_freqs list must be long enough to define all the tones you will play. (in other words, if your mask list ever enables tone 2 you must define at least 3 freqs+gains) If your mux gen supports gains and/or phases and you define them, those lists must be the same length. If you don’t define gains or phases, they will be set to defaults (max positive gain, zero phase).

Parameters:
  • ch (int) – generator channel (index in ‘gens’ list)

  • nqz (int, optional) – Nyquist zone (must be 1 or 2). Setting the NQZ to 2 increases output power in the 2nd/3rd Nyquist zones.

  • mixer_freq (float, optional) – Mixer frequency (in MHz)

  • mux_freqs (list of float, optional) – Tone frequencies for the muxed generator (in MHz). Positive and negative values are allowed.

  • mux_gains (list of float, optional) – Tone amplitudes for the muxed generator (in range -1 to 1).

  • mux_phases (list of float, optional) – Phases for the muxed generator (in degrees).

  • ro_ch (int, optional) – readout channel for frequency-matching mixer and mux freqs

config_gens(soc)[source]

Configure the signal generators specified in this program. This is usually called as part of an acquire() method.

Parameters:

soc (QickSoc) – the QickSoc that will execute this program

add_envelope(ch, name, idata=None, qdata=None)[source]

Adds a waveform to the list of envelope waveforms available for this channel. The I and Q arrays must be of equal length, and the length must be divisible by the samples-per-clock of this generator.

Parameters:
  • ch (int) – generator channel (index in ‘gens’ list)

  • name (str) – Name of the pulse

  • idata (array) – I data Numpy array

  • qdata (array) – Q data Numpy array

add_cosine(ch, name, length, maxv=None, even_length=False)[source]

Adds a cosine to the envelope library. The envelope will peak at length/2. Duration units depend on the program type: tProc v1 programs use integer number of fabric clocks, tProc v2 programs use float us.

Parameters:
  • ch (int) – generator channel (index in ‘gens’ list)

  • name (str) – Name of the envelope

  • length (int) – Total envelope length (in fabric clocks or us)

  • maxv (float) – Value at the peak (if None, the max value for this generator will be used)

  • even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.

add_gauss(ch, name, sigma, length, maxv=None, even_length=False)[source]

Adds a Gaussian to the envelope library. The envelope will peak at length/2. Duration units depend on the program type: tProc v1 programs use integer number of fabric clocks, tProc v2 programs use float us.

Parameters:
  • ch (int) – generator channel (index in ‘gens’ list)

  • name (str) – Name of the envelope

  • sigma (float) – Standard deviation of the Gaussian (in fabric clocks or us)

  • length (int or float) – Total envelope length (in fabric clocks or us)

  • maxv (float) – Value at the peak (if None, the max value for this generator will be used)

  • even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.

add_DRAG(ch, name, sigma, length, delta, alpha=0.5, maxv=None, even_length=False)[source]

Adds a DRAG to the envelope library. The envelope will peak at length/2.

Parameters:
  • ch (int) – generator channel (index in ‘gens’ list)

  • name (str) – Name of the envelope

  • sigma (float or float) – Standard deviation of the Gaussian (in fabric clocks or us)

  • length (int or float) – Total envelope length (in fabric clocks or us)

  • maxv (float) – Value at the peak (if None, the max value for this generator will be used)

  • delta (float) – anharmonicity of the qubit (units of MHz)

  • alpha (float) – alpha parameter of DRAG (order-1 scale factor)

  • even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.

add_triangle(ch, name, length, maxv=None, even_length=False)[source]

Adds a triangle to the envelope library. The envelope will peak at length/2. Duration units depend on the program type: tProc v1 programs use integer number of fabric clocks, tProc v2 programs use float us.

Parameters:
  • ch (int) – generator channel (index in ‘gens’ list)

  • name (str) – Name of the envelope

  • length (int or float) – Total envelope length (in fabric clocks or us)

  • maxv (float) – Value at the peak (if None, the max value for this generator will be used)

  • even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.

load_pulses(soc)[source]

Loads pulses that were added using add_envelope into the SoC’s signal generator memories.

Parameters:

soc (Qick object) – Qick object

class qick.qick_asm.AcquireMixin(*args, **kwargs)[source]

Bases: object

Adds acquire() and acquire_decimated() methods for acquiring readout data, and run_rounds() for running repeatedly without acquisition. Program classes that use this mixin must call setup_acquire() after _init_prog() and before acquire()/acquire_decimated().

setup_counter(counter_addr, loop_dims)[source]

Set the parameters needed to track the progress of the program. This is a subset of setup_acquire(), appropriate for programs where you have no readouts. You should use this if you’re updating a tProc counter and want to use it to track program progress.

Parameters:
  • counter_addr (int) – The special tProc address holding the number of shots read out thus far.

  • loop_dims (list of int) – List of loop dimensions, outermost loop first.

setup_acquire(counter_addr, loop_dims, avg_level)[source]

Set the parameters needed to define the data acquisition. Since the number of readouts per shot is set based on calls to trigger(), this should be called after the program has been fully defined.

Parameters:
  • counter_addr (int) – The special tProc address holding the number of shots read out thus far.

  • loop_dims (list of int) – List of loop dimensions, outermost loop first.

  • avg_level (int) – Which loop level to average over (0 is outermost).

set_reads_per_shot(reads_per_shot)[source]

Override the default count of readout triggers per shot. This should be called after setup_acquire(). You probably shouldn’t be using this method; the default value is usually correct.

Parameters:

reads_per_shot (int or list of int) – Number of readout triggers per shot. If int, all declared readout channels use this value.

get_raw()[source]

Get the raw integer I/Q values (before normalizing to the readout window, averaging across reps, removing the readout offset, or thresholding).

Returns:

Array of I/Q values for each readout channel.

Return type:

list of ndarray

get_shots()[source]

Get the shot-by-shot threshold decisions.

Returns:

Array of shots for each readout channel.

Return type:

list of ndarray

acquire(soc, soft_avgs=1, load_pulses=True, start_src='internal', threshold=None, angle=None, progress=True, remove_offset=True)[source]

Acquire data using the accumulated readout.

Parameters:
  • soc (QickSoc) – Qick object

  • soft_avgs (int) – number of times to rerun the program, averaging results in software (aka “rounds”)

  • load_pulses (bool) – if True, load pulse envelopes

  • start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger)

  • threshold (float or list of float) – The threshold(s) to apply to the I values after rotation. Length-normalized units (same units as the output of acquire()). If scalar, the same threshold will be applied to all readout channels. A list must have length equal to the number of declared readout channels.

  • angle (float or list of float) – The angle to rotate the I/Q values by before applying the threshold. Units of radians. If scalar, the same angle will be applied to all readout channels. A list must have length equal to the number of declared readout channels.

  • progress (bool) – if true, displays progress bar

  • remove_offset (bool) – Some readouts (muxed and tProc-configured) introduce a small fixed offset to the I and Q values of every decimated sample. This subtracts that offset, if any, before returning the averaged IQ values or rotating to apply software thresholding.

Returns:

averaged IQ values (float) divided by the length of the RO window, and averaged over reps and rounds if threshold is defined, the I values will be the fraction of points over threshold dimensions for a simple averaging program: (n_ch, n_reads, 2) dimensions for a program with multiple expts/steps: (n_ch, n_reads, n_expts, 2)

Return type:

ndarray

get_time_axis(ro_index)[source]

Get an array usable as the time axis for plotting decimated data.

Parameters:

ro_index (int) – Index of the readout channel in this program. The first readout declared in your program has index 0 and it will have index 0 in the output array, etc.

Returns:

An array starting at 0 and spaced by the time (in us) per decimated sample.

Return type:

ndarray of float

get_time_axis_ddr4(ro_ch, data)[source]

Get an array usable as the time axis for plotting DDR4 data.

Parameters:
  • ro_ch (int) – readout channel (index in ‘readouts’ list)

  • data (ndarray) – DDR4 data array, the returned array will have the same length.

Returns:

An array starting at 0 and spaced by the time (in us) per decimated sample.

Return type:

ndarray of float

get_time_axis_mr(ro_ch, data)[source]

Get an array usable as the time axis for plotting MR data.

Parameters:
  • ro_ch (int) – readout channel (index in ‘readouts’ list)

  • data (ndarray) – MR data array, the returned array will have the same length.

Returns:

An array starting at 0 and spaced by the time (in us) per MR sample.

Return type:

ndarray of float

run_rounds(soc, rounds=1, load_pulses=True, start_src='internal', progress=True)[source]

Run the program and wait until it completes, once or multiple times. No data will be saved.

Parameters:
  • soc (QickSoc) – Qick object

  • rounds (int) – number of times to rerun the program

  • load_pulses (bool) – if True, load pulse envelopes

  • start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger)

  • progress (bool) – if true, displays progress bar

acquire_decimated(soc, soft_avgs, load_pulses=True, start_src='internal', progress=True, remove_offset=True)[source]

Acquire data using the decimating readout.

Parameters:
  • soc (QickSoc) – Qick object

  • soft_avgs (int) – number of times to rerun the program, averaging results in software (aka “rounds”)

  • load_pulses (bool) – if True, load pulse envelopes

  • start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger)

  • progress (bool) – if true, displays progress bar

  • remove_offset (bool) – Subtract the readout’s IQ offset, if any.

Returns:

decimated values, averaged over rounds (float) dimensions for a single-rep, single-read program : (length, 2) multi-rep or multi-read: (n_reps*n_reads, length, 2) multi-rep and multi-read: (n_reps, n_reads, length, 2)

Return type:

list of ndarray