forked from M-Labs/artiq
pdq: get new host driver, adapt
This commit is contained in:
parent
2895448477
commit
2458da1ade
1
artiq/devices/pdq/__init__.py
Normal file
1
artiq/devices/pdq/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from artiq.devices.pdq.mediator import *
|
@ -1,4 +1,19 @@
|
||||
# Copyright (C) 2012-2015 Robert Jordens <jordens@gmail.com>
|
||||
# Copyright 2013-2017 Robert Jordens <jordens@gmail.com>
|
||||
#
|
||||
# This file is part of pdq.
|
||||
#
|
||||
# pdq is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pdq is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pdq. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from math import log, sqrt
|
||||
import logging
|
||||
@ -12,6 +27,65 @@ from artiq.wavesynth.coefficients import discrete_compensate
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def discrete_compensate(c):
|
||||
"""Compensate spline coefficients for discrete accumulators.
|
||||
|
||||
Given continuous-time b-spline coefficients, this function
|
||||
compensates for the effect of discrete time steps in the
|
||||
target devices.
|
||||
|
||||
The compensation is performed in-place.
|
||||
"""
|
||||
l = len(c)
|
||||
if l > 2:
|
||||
c[1] += c[2]/2.
|
||||
if l > 3:
|
||||
c[1] += c[3]/6.
|
||||
c[2] += c[3]
|
||||
if l > 4:
|
||||
raise ValueError("Only splines up to cubic order are supported.")
|
||||
|
||||
|
||||
class CRC:
|
||||
"""Generic and simple table driven CRC calculator.
|
||||
|
||||
This implementation is:
|
||||
|
||||
* MSB first data
|
||||
* "un-reversed" full polynomial (i.e. starts with 0x1)
|
||||
* no initial complement
|
||||
* no final complement
|
||||
|
||||
Handle any variation on those details outside this class.
|
||||
|
||||
>>> r = CRC(0x1814141AB)(b"123456789") # crc-32q
|
||||
>>> assert r == 0x3010BF7F, hex(r)
|
||||
"""
|
||||
def __init__(self, poly, data_width=8):
|
||||
self.poly = poly
|
||||
self.crc_width = poly.bit_length() - 1
|
||||
self.data_width = data_width
|
||||
self._table = [self._one(i << self.crc_width - data_width)
|
||||
for i in range(1 << data_width)]
|
||||
|
||||
def _one(self, i):
|
||||
for j in range(self.data_width):
|
||||
i <<= 1
|
||||
if i & 1 << self.crc_width:
|
||||
i ^= self.poly
|
||||
return i
|
||||
|
||||
def __call__(self, msg, crc=0):
|
||||
for data in msg:
|
||||
p = data ^ crc >> self.crc_width - self.data_width
|
||||
q = crc << self.data_width & (1 << self.crc_width) - 1
|
||||
crc = self._table[p] ^ q
|
||||
return crc
|
||||
|
||||
|
||||
crc8 = CRC(0x107)
|
||||
|
||||
|
||||
class Segment:
|
||||
"""Serialize the lines for a single Segment.
|
||||
|
||||
@ -49,6 +123,8 @@ class Segment:
|
||||
this line.
|
||||
silence (bool): Disable DAC clocks for the duration of this line.
|
||||
aux (bool): Assert the AUX (F5 TTL) output during this line.
|
||||
The corresponding global AUX routing setting determines which
|
||||
channels control AUX.
|
||||
shift (int): Duration and spline evolution exponent.
|
||||
jump (bool): Return to the frame address table after this line.
|
||||
clear (bool): Clear the DDS phase accumulator when starting to
|
||||
@ -134,17 +210,16 @@ class Segment:
|
||||
|
||||
|
||||
class Channel:
|
||||
"""PDQ2 Channel.
|
||||
"""PDQ Channel.
|
||||
|
||||
Attributes:
|
||||
num_frames (int): Number of frames supported.
|
||||
max_data (int): Number of 16 bit data words per channel.
|
||||
segments (list[Segment]): Segments added to this channel.
|
||||
"""
|
||||
num_frames = 8
|
||||
max_data = 4*(1 << 10) # 8kx16 8kx16 4kx16
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, max_data, num_frames):
|
||||
self.max_data = max_data
|
||||
self.num_frames = num_frames
|
||||
self.segments = []
|
||||
|
||||
def clear(self):
|
||||
@ -220,38 +295,39 @@ class Channel:
|
||||
return self.table(entry) + data
|
||||
|
||||
|
||||
class Pdq2:
|
||||
class PdqBase:
|
||||
"""
|
||||
PDQ stack.
|
||||
|
||||
Args:
|
||||
url (str): Pyserial device URL. Can be ``hwgrep://`` style
|
||||
(search for serial number, bus topology, USB VID:PID combination),
|
||||
``COM15`` for a Windows COM port number,
|
||||
``/dev/ttyUSB0`` for a Linux serial port.
|
||||
dev (file-like): File handle to use as device. If passed, ``url`` is
|
||||
ignored.
|
||||
num_boards (int): Number of boards in this stack.
|
||||
|
||||
Attributes:
|
||||
num_dacs (int): Number of DAC outputs per board.
|
||||
checksum (int): Running checksum of data written.
|
||||
num_channels (int): Number of channels in this stack.
|
||||
num_boards (int): Number of boards in this stack.
|
||||
num_dacs (int): Number of DAC outputs per board.
|
||||
num_frames (int): Number of frames supported.
|
||||
channels (list[Channel]): List of :class:`Channel` in this stack.
|
||||
"""
|
||||
num_dacs = 3
|
||||
freq = 50e6
|
||||
|
||||
_escape = b"\xa5"
|
||||
_commands = "RESET TRIGGER ARM DCM START".split()
|
||||
_mem_sizes = [None, (20,), (10, 10), (8, 6, 6)] # 10kx16 units
|
||||
|
||||
def __init__(self, url=None, dev=None, num_boards=3):
|
||||
if dev is None:
|
||||
dev = serial.serial_for_url(url)
|
||||
self.dev = dev
|
||||
def __init__(self, num_boards=3, num_dacs=3, num_frames=32):
|
||||
"""Initialize PDQ stack.
|
||||
|
||||
Args:
|
||||
num_boards (int): Number of boards in this stack.
|
||||
num_dacs (int): Number of DAC outputs per board.
|
||||
num_frames (int): Number of frames supported.
|
||||
"""
|
||||
self.checksum = 0
|
||||
self.num_boards = num_boards
|
||||
self.num_dacs = num_dacs
|
||||
self.num_frames = num_frames
|
||||
self.num_channels = self.num_dacs * self.num_boards
|
||||
self.channels = [Channel() for i in range(self.num_channels)]
|
||||
m = self._mem_sizes[num_dacs]
|
||||
self.channels = [Channel(m[j] << 11, num_frames)
|
||||
for i in range(num_boards)
|
||||
for j in range(num_dacs)]
|
||||
|
||||
def get_num_boards(self):
|
||||
return self.num_boards
|
||||
@ -259,41 +335,71 @@ class Pdq2:
|
||||
def get_num_channels(self):
|
||||
return self.num_channels
|
||||
|
||||
def get_num_frames(self):
|
||||
return self.num_frames
|
||||
|
||||
def get_freq(self):
|
||||
return self.freq
|
||||
|
||||
def set_freq(self, freq):
|
||||
self.freq = float(freq)
|
||||
|
||||
def close(self):
|
||||
"""Close the USB device handle."""
|
||||
self.dev.close()
|
||||
del self.dev
|
||||
def _cmd(self, board, is_mem, adr, we):
|
||||
return (adr << 0) | (is_mem << 2) | (board << 3) | (we << 7)
|
||||
|
||||
def write(self, data):
|
||||
"""Write data to the PDQ2 board.
|
||||
raise NotImplementedError
|
||||
|
||||
def write_reg(self, board, adr, data):
|
||||
"""Write to a configuration register.
|
||||
|
||||
Args:
|
||||
data (bytes): Data to write.
|
||||
board (int): Board to write to (0-0xe), 0xf for all boards.
|
||||
adr (int): Register address to write to (0-3).
|
||||
data (int): Data to write (1 byte)
|
||||
"""
|
||||
logger.debug("> %r", data)
|
||||
written = self.dev.write(data)
|
||||
if isinstance(written, int):
|
||||
assert written == len(data)
|
||||
self.write(struct.pack(
|
||||
"<BB", self._cmd(board, False, adr, True), data))
|
||||
|
||||
def cmd(self, cmd, enable):
|
||||
"""Execute a command.
|
||||
def set_config(self, reset=False, clk2x=False, enable=True,
|
||||
trigger=False, aux_miso=False, aux_dac=0b111, board=0xf):
|
||||
"""Set the configuration register.
|
||||
|
||||
Args:
|
||||
cmd (str): Command to execute. One of (``RESET``, ``TRIGGER``,
|
||||
``ARM``, ``DCM``, ``START``).
|
||||
enable (bool): Enable (``True``) or disable (``False``) the
|
||||
feature.
|
||||
reset (bool): Reset the board. Memory is not reset. Self-clearing.
|
||||
clk2x (bool): Enable the clock multiplier (100 MHz instead of 50
|
||||
MHz)
|
||||
enable (bool): Enable the channel data parsers and spline
|
||||
interpolators.
|
||||
trigger (bool): Soft trigger. Logical or with the hardware trigger.
|
||||
aux_miso (bool): Drive SPI MISO on the AUX/F5 ttl port of each
|
||||
board. If `False`, drive the masked logical or of the DAC
|
||||
channels' aux data.
|
||||
aux_dac (int): Mask for AUX/F5. Each bit represents one channel.
|
||||
AUX/F5 is: `aux_miso ? spi_miso :
|
||||
(aux_dac & Cat(_.aux for _ in channels) != 0)`
|
||||
board (int): Board to write to (0-0xe), 0xf for all boards.
|
||||
"""
|
||||
cmd = self._commands.index(cmd) << 1
|
||||
if not enable:
|
||||
cmd |= 1
|
||||
self.write(struct.pack("cb", self._escape, cmd))
|
||||
self.write_reg(board, 0, (reset << 0) | (clk2x << 1) | (enable << 2) |
|
||||
(trigger << 3) | (aux_miso << 4) | (aux_dac << 5))
|
||||
|
||||
def set_checksum(self, crc=0, board=0xf):
|
||||
"""Set/reset the checksum register.
|
||||
|
||||
Args:
|
||||
crc (int): Checksum value to write.
|
||||
board (int): Board to write to (0-0xe), 0xf for all boards.
|
||||
"""
|
||||
self.write_reg(board, 1, crc)
|
||||
|
||||
def set_frame(self, frame, board=0xf):
|
||||
"""Set the current frame.
|
||||
|
||||
Args:
|
||||
frame (int): Frame to select.
|
||||
board (int): Board to write to (0-0xe), 0xf for all boards.
|
||||
"""
|
||||
self.write_reg(board, 2, frame)
|
||||
|
||||
def write_mem(self, channel, data, start_addr=0):
|
||||
"""Write to channel memory.
|
||||
@ -305,10 +411,8 @@ class Pdq2:
|
||||
start_addr (int): Start address to write data to.
|
||||
"""
|
||||
board, dac = divmod(channel, self.num_dacs)
|
||||
data = struct.pack("<HHH", (board << 4) | dac, start_addr,
|
||||
start_addr + len(data)//2 - 1) + data
|
||||
data = data.replace(self._escape, self._escape + self._escape)
|
||||
self.write(data)
|
||||
self.write(struct.pack("<BH", self._cmd(board, True, dac, True),
|
||||
start_addr) + data)
|
||||
|
||||
def program_segments(self, segments, data):
|
||||
"""Append the wavesynth lines to the given segments.
|
||||
@ -372,18 +476,83 @@ class Pdq2:
|
||||
for channel, ch in zip(channels, chs):
|
||||
self.write_mem(channel, ch.serialize())
|
||||
|
||||
def flush(self):
|
||||
self.dev.flush()
|
||||
|
||||
def park(self):
|
||||
self.cmd("START", False)
|
||||
self.cmd("TRIGGER", True)
|
||||
def disable(self, **kwargs):
|
||||
"""Disable the device."""
|
||||
self.set_config(enable=False, **kwargs)
|
||||
self.flush()
|
||||
|
||||
def unpark(self):
|
||||
self.cmd("TRIGGER", False)
|
||||
self.cmd("START", True)
|
||||
def enable(self, **kwargs):
|
||||
"""Enable the device."""
|
||||
self.set_config(enable=True, **kwargs)
|
||||
self.flush()
|
||||
|
||||
def ping(self):
|
||||
"""Ping method returning True. Required for ARTIQ remote
|
||||
controller."""
|
||||
return True
|
||||
|
||||
|
||||
class Pdq(PdqBase):
|
||||
def __init__(self, url=None, dev=None, **kwargs):
|
||||
"""Initialize PDQ USB/Parallel device stack.
|
||||
|
||||
Args:
|
||||
url (str): Pyserial device URL. Can be ``hwgrep://`` style
|
||||
(search for serial number, bus topology, USB VID:PID
|
||||
combination), ``COM15`` for a Windows COM port number,
|
||||
``/dev/ttyUSB0`` for a Linux serial port.
|
||||
dev (file-like): File handle to use as device. If passed, ``url``
|
||||
is ignored.
|
||||
**kwargs: See :class:`PdqBase` .
|
||||
"""
|
||||
if dev is None:
|
||||
dev = serial.serial_for_url(url)
|
||||
self.dev = dev
|
||||
PdqBase.__init__(self, **kwargs)
|
||||
|
||||
def write(self, data):
|
||||
"""Write data to the PDQ board over USB/parallel.
|
||||
|
||||
SOF/EOF control sequences are appended/prepended to
|
||||
the (escaped) data. The running checksum is updated.
|
||||
|
||||
Args:
|
||||
data (bytes): Data to write.
|
||||
"""
|
||||
logger.debug("> %r", data)
|
||||
msg = b"\xa5\x02" + data.replace(b"\xa5", b"\xa5\xa5") + b"\xa5\x03"
|
||||
written = self.dev.write(msg)
|
||||
if isinstance(written, int):
|
||||
assert written == len(msg), (written, len(msg))
|
||||
self.checksum = crc8(data, self.checksum)
|
||||
|
||||
def close(self):
|
||||
"""Close the USB device handle."""
|
||||
self.dev.close()
|
||||
del self.dev
|
||||
|
||||
def flush(self):
|
||||
"""Flush pending data."""
|
||||
self.dev.flush()
|
||||
|
||||
|
||||
class PdqSPI(PdqBase):
|
||||
def __init__(self, dev=None, **kwargs):
|
||||
"""Initialize PDQ SPI device stack."""
|
||||
self.dev = dev
|
||||
PdqBase.__init__(self, **kwargs)
|
||||
|
||||
def write(self, data):
|
||||
"""Write data to the PDQ board over USB/parallel.
|
||||
|
||||
SOF/EOF control sequences are appended/prepended to
|
||||
the (escaped) data. The running checksum is updated.
|
||||
|
||||
Args:
|
||||
data (bytes): Data to write.
|
||||
"""
|
||||
logger.debug("> %r", data)
|
||||
written = self.dev.write(data)
|
||||
if isinstance(written, int):
|
||||
assert written == len(data), (written, len(data))
|
||||
self.checksum = crc8(data, self.checksum)
|
@ -154,10 +154,10 @@ class _Frame:
|
||||
self.pdq.next_segment = -1
|
||||
|
||||
|
||||
class CompoundPDQ2:
|
||||
def __init__(self, dmgr, pdq2_devices, trigger_device, frame_devices):
|
||||
class CompoundPDQ:
|
||||
def __init__(self, dmgr, pdq_devices, trigger_device, frame_devices):
|
||||
self.core = dmgr.get("core")
|
||||
self.pdq2s = [dmgr.get(d) for d in pdq2_devices]
|
||||
self.pdqs = [dmgr.get(d) for d in pdq_devices]
|
||||
self.trigger = dmgr.get(trigger_device)
|
||||
self.frame0 = dmgr.get(frame_devices[0])
|
||||
self.frame1 = dmgr.get(frame_devices[1])
|
||||
@ -172,7 +172,7 @@ class CompoundPDQ2:
|
||||
for frame in self.frames:
|
||||
frame._invalidate()
|
||||
self.frames.clear()
|
||||
for dev in self.pdq2s:
|
||||
for dev in self.pdqs:
|
||||
dev.park()
|
||||
self.armed = False
|
||||
|
||||
@ -187,8 +187,8 @@ class CompoundPDQ2:
|
||||
|
||||
full_program = self.get_program()
|
||||
n = 0
|
||||
for pdq2 in self.pdq2s:
|
||||
dn = pdq2.get_num_channels()
|
||||
for pdq in self.pdqs:
|
||||
dn = pdq.get_num_channels()
|
||||
program = []
|
||||
for full_frame_program in full_program:
|
||||
frame_program = []
|
||||
@ -201,10 +201,10 @@ class CompoundPDQ2:
|
||||
}
|
||||
frame_program.append(line)
|
||||
program.append(frame_program)
|
||||
pdq2.program(program)
|
||||
pdq.program(program)
|
||||
n += dn
|
||||
for pdq2 in self.pdq2s:
|
||||
pdq2.unpark()
|
||||
for pdq in self.pdqs:
|
||||
pdq.unpark()
|
||||
self.armed = True
|
||||
|
||||
def create_frame(self):
|
@ -1 +0,0 @@
|
||||
from artiq.devices.pdq2.mediator import *
|
@ -172,30 +172,30 @@ device_db = {
|
||||
# that it always resolves to a network-visible IP address (see documentation).
|
||||
"host": "::1",
|
||||
"port": 4000,
|
||||
"command": "aqctl_pdq2 -p {port} --bind {bind} --simulation --dump qc_q1_0.bin"
|
||||
"command": "aqctl_pdq -p {port} --bind {bind} --simulation --dump qc_q1_0.bin"
|
||||
},
|
||||
"qc_q1_1": {
|
||||
"type": "controller",
|
||||
"host": "::1",
|
||||
"port": 4001,
|
||||
"command": "aqctl_pdq2 -p {port} --bind {bind} --simulation --dump qc_q1_1.bin"
|
||||
"command": "aqctl_pdq -p {port} --bind {bind} --simulation --dump qc_q1_1.bin"
|
||||
},
|
||||
"qc_q1_2": {
|
||||
"type": "controller",
|
||||
"host": "::1",
|
||||
"port": 4002,
|
||||
"command": "aqctl_pdq2 -p {port} --bind {bind} --simulation --dump qc_q1_2.bin"
|
||||
"command": "aqctl_pdq -p {port} --bind {bind} --simulation --dump qc_q1_2.bin"
|
||||
},
|
||||
"qc_q1_3": {
|
||||
"type": "controller",
|
||||
"host": "::1",
|
||||
"port": 4003,
|
||||
"command": "aqctl_pdq2 -p {port} --bind {bind} --simulation --dump qc_q1_3.bin"
|
||||
"command": "aqctl_pdq -p {port} --bind {bind} --simulation --dump qc_q1_3.bin"
|
||||
},
|
||||
"electrodes": {
|
||||
"type": "local",
|
||||
"module": "artiq.devices.pdq2",
|
||||
"class": "CompoundPDQ2",
|
||||
"module": "artiq.devices.pdq",
|
||||
"class": "CompoundPDQ",
|
||||
"arguments": {
|
||||
"pdq2_devices": ["qc_q1_0", "qc_q1_1", "qc_q1_2", "qc_q1_3"],
|
||||
"trigger_device": "ttl2",
|
||||
|
@ -4,18 +4,18 @@ import argparse
|
||||
import sys
|
||||
import time
|
||||
|
||||
from artiq.devices.pdq2.driver import Pdq2
|
||||
from artiq.devices.pdq.driver import Pdq
|
||||
from artiq.protocols.pc_rpc import simple_server_loop
|
||||
from artiq.tools import *
|
||||
|
||||
|
||||
def get_argparser():
|
||||
parser = argparse.ArgumentParser(description="PDQ2 controller")
|
||||
parser = argparse.ArgumentParser(description="PDQ controller")
|
||||
simple_network_args(parser, 3252)
|
||||
parser.add_argument("-d", "--device", default=None, help="serial port")
|
||||
parser.add_argument("--simulation", action="store_true",
|
||||
help="do not open any device but dump data")
|
||||
parser.add_argument("--dump", default="pdq2_dump.bin",
|
||||
parser.add_argument("--dump", default="pdq_dump.bin",
|
||||
help="file to dump simulation data into")
|
||||
parser.add_argument("-r", "--reset", default=False,
|
||||
action="store_true", help="reset device [%(default)s]")
|
||||
@ -37,16 +37,17 @@ def main():
|
||||
|
||||
if args.simulation:
|
||||
port = open(args.dump, "wb")
|
||||
dev = Pdq2(url=args.device, dev=port, num_boards=args.boards)
|
||||
dev = Pdq(url=args.device, dev=port, num_boards=args.boards)
|
||||
try:
|
||||
if args.reset:
|
||||
dev.write(b"\x00\x00") # flush any escape
|
||||
dev.cmd("RESET", True)
|
||||
dev.flush()
|
||||
dev.write(b"") # flush eop
|
||||
dev.set_config(reset=True)
|
||||
time.sleep(.1)
|
||||
dev.cmd("ARM", True)
|
||||
dev.park()
|
||||
simple_server_loop({"pdq2": dev}, bind_address_from_args(args),
|
||||
|
||||
dev.set_checksum(0)
|
||||
dev.checksum = 0
|
||||
|
||||
simple_server_loop({"pdq": dev}, bind_address_from_args(args),
|
||||
args.port, description="device=" + str(args.device))
|
||||
finally:
|
||||
dev.close()
|
||||
|
@ -4,34 +4,31 @@ import unittest
|
||||
import os
|
||||
import io
|
||||
|
||||
from artiq.devices.pdq2.driver import Pdq2
|
||||
from artiq.devices.pdq.driver import Pdq
|
||||
from artiq.wavesynth.compute_samples import Synthesizer
|
||||
|
||||
|
||||
pdq2_gateware = os.getenv("ARTIQ_PDQ2_GATEWARE")
|
||||
pdq_gateware = os.getenv("ARTIQ_PDQ_GATEWARE")
|
||||
|
||||
|
||||
class TestPdq2(unittest.TestCase):
|
||||
class TestPdq(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.dev = Pdq2(dev=io.BytesIO())
|
||||
self.dev = Pdq(dev=io.BytesIO())
|
||||
self.synth = Synthesizer(3, _test_program)
|
||||
|
||||
def test_reset(self):
|
||||
self.dev.cmd("RESET", True)
|
||||
self.dev.set_config(reset=True)
|
||||
buf = self.dev.dev.getvalue()
|
||||
self.assertEqual(buf, b"\xa5\x00")
|
||||
self.assertEqual(buf, b"\xa5\x02\xf8\xe5\xa5\x03")
|
||||
|
||||
def test_program(self):
|
||||
# about 0.14 ms
|
||||
self.dev.program(_test_program)
|
||||
|
||||
def test_cmd_program(self):
|
||||
self.dev.cmd("ARM", False)
|
||||
self.dev.cmd("START", False)
|
||||
self.dev.set_config(enable=False)
|
||||
self.dev.program(_test_program)
|
||||
self.dev.cmd("START", True)
|
||||
self.dev.cmd("ARM", True)
|
||||
# self.dev.cmd("TRIGGER", True)
|
||||
self.dev.set_config(enable=True, trigger=True)
|
||||
return self.dev.dev.getvalue()
|
||||
|
||||
def test_synth(self):
|
||||
@ -42,12 +39,12 @@ class TestPdq2(unittest.TestCase):
|
||||
|
||||
def run_gateware(self):
|
||||
import sys
|
||||
sys.path.append(pdq2_gateware)
|
||||
from gateware.pdq2 import Pdq2Sim
|
||||
from migen.sim.generic import run_simulation
|
||||
sys.path.append(pdq_gateware)
|
||||
from gateware.pdq import PdqSim
|
||||
from migen import run_simulation
|
||||
|
||||
buf = self.test_cmd_program()
|
||||
tb = Pdq2Sim(buf)
|
||||
tb = PdqSim()
|
||||
tb.ctrl_pads.trigger.reset = 1
|
||||
run_simulation(tb, ncycles=len(buf) + 250)
|
||||
delays = 7, 10, 30
|
||||
@ -57,7 +54,7 @@ class TestPdq2(unittest.TestCase):
|
||||
self.assertEqual(len(y[0]), 3)
|
||||
return y
|
||||
|
||||
@unittest.skipUnless(pdq2_gateware, "no pdq2 gateware")
|
||||
@unittest.skipUnless(pdq_gateware, "no PDQ gateware")
|
||||
def test_run_compare(self):
|
||||
y_ref = self.test_synth()
|
||||
y = self.run_gateware()
|
||||
@ -70,7 +67,7 @@ class TestPdq2(unittest.TestCase):
|
||||
self.assertAlmostEqual(yij, yij_ref, 2, "disagreement at "
|
||||
"t={}, c={}".format(i, j))
|
||||
|
||||
@unittest.skipUnless(pdq2_gateware, "no pdq2 gateware")
|
||||
@unittest.skipUnless(pdq_gateware, "no PDQ gateware")
|
||||
@unittest.skip("manual/visual test")
|
||||
def test_run_plot(self):
|
||||
from matplotlib import pyplot as plt
|
2
setup.py
2
setup.py
@ -39,7 +39,7 @@ console_scripts = [
|
||||
"aqctl_lda=artiq.frontend.aqctl_lda:main",
|
||||
"aqctl_novatech409b=artiq.frontend.aqctl_novatech409b:main",
|
||||
"aqctl_korad_ka3005p=artiq.frontend.aqctl_korad_ka3005p:main",
|
||||
"aqctl_pdq2=artiq.frontend.aqctl_pdq2:main",
|
||||
"aqctl_pdq=artiq.frontend.aqctl_pdq:main",
|
||||
"aqctl_thorlabs_tcube=artiq.frontend.aqctl_thorlabs_tcube:main",
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user