2015-09-07 06:08:57 +08:00
|
|
|
# Copyright (C) 2014, 2015 M-Labs Limited
|
|
|
|
# Copyright (C) 2014, 2015 Robert Jordens <jordens@gmail.com>
|
|
|
|
|
2015-06-29 10:08:39 +08:00
|
|
|
from math import sqrt
|
|
|
|
|
|
|
|
from artiq.language import *
|
|
|
|
from artiq.test.hardware_testbench import ExperimentCase
|
2015-09-01 13:34:28 +08:00
|
|
|
from artiq.coredevice.exceptions import RTIOUnderflow, RTIOSequenceError
|
2015-06-26 12:19:11 +08:00
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class RTT(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("ttl_inout")
|
2015-06-29 10:08:39 +08:00
|
|
|
|
2015-07-14 04:22:26 +08:00
|
|
|
def set_rtt(self, rtt):
|
2015-10-12 19:20:04 +08:00
|
|
|
self.set_dataset("rtt", rtt)
|
2015-06-29 10:08:39 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
|
|
|
self.ttl_inout.output()
|
|
|
|
delay(1*us)
|
|
|
|
with parallel:
|
2015-07-02 16:26:00 +08:00
|
|
|
# make sure not to send two commands into the same RTIO
|
|
|
|
# channel with the same timestamp
|
|
|
|
self.ttl_inout.gate_rising(5*us)
|
2015-06-29 10:08:39 +08:00
|
|
|
with sequential:
|
|
|
|
delay(1*us)
|
2015-07-02 04:34:49 +08:00
|
|
|
t0 = now_mu()
|
2015-06-26 12:19:11 +08:00
|
|
|
self.ttl_inout.pulse(1*us)
|
2015-12-16 19:45:57 +08:00
|
|
|
self.set_dataset("rtt", mu_to_seconds(self.ttl_inout.timestamp_mu() - t0))
|
2015-06-29 10:08:39 +08:00
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class Loopback(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("loop_in")
|
|
|
|
self.setattr_device("loop_out")
|
2015-06-29 10:08:39 +08:00
|
|
|
|
2015-07-14 04:22:26 +08:00
|
|
|
def set_rtt(self, rtt):
|
2015-10-12 19:20:04 +08:00
|
|
|
self.set_dataset("rtt", rtt)
|
2015-06-29 10:08:39 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
2015-07-05 00:35:11 +08:00
|
|
|
self.loop_in.input()
|
|
|
|
delay(1*us)
|
2015-06-29 10:08:39 +08:00
|
|
|
with parallel:
|
|
|
|
self.loop_in.gate_rising(2*us)
|
|
|
|
with sequential:
|
|
|
|
delay(1*us)
|
2015-07-02 04:34:49 +08:00
|
|
|
t0 = now_mu()
|
2015-06-29 10:08:39 +08:00
|
|
|
self.loop_out.pulse(1*us)
|
2015-12-16 19:45:57 +08:00
|
|
|
self.set_dataset("rtt", mu_to_seconds(self.loop_in.timestamp_mu() - t0))
|
2015-06-29 10:08:39 +08:00
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class ClockGeneratorLoopback(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("loop_clock_in")
|
|
|
|
self.setattr_device("loop_clock_out")
|
2015-07-05 00:36:01 +08:00
|
|
|
|
2015-07-14 04:22:26 +08:00
|
|
|
def set_count(self, count):
|
2015-10-12 19:20:04 +08:00
|
|
|
self.set_dataset("count", count)
|
2015-07-05 00:36:01 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
|
|
|
self.loop_clock_in.input()
|
|
|
|
self.loop_clock_out.stop()
|
|
|
|
delay(1*us)
|
|
|
|
with parallel:
|
|
|
|
self.loop_clock_in.gate_rising(10*us)
|
|
|
|
with sequential:
|
|
|
|
delay(200*ns)
|
|
|
|
self.loop_clock_out.set(1*MHz)
|
2015-12-16 19:45:57 +08:00
|
|
|
self.set_dataset("count", self.loop_clock_in.count())
|
2015-07-05 00:36:01 +08:00
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class PulseRate(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("ttl_out")
|
2015-06-29 10:08:39 +08:00
|
|
|
|
2015-07-14 04:22:26 +08:00
|
|
|
def set_pulse_rate(self, pulse_rate):
|
2015-10-12 19:20:04 +08:00
|
|
|
self.set_dataset("pulse_rate", pulse_rate)
|
2015-06-29 10:08:39 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
2015-07-02 04:34:49 +08:00
|
|
|
dt = seconds_to_mu(1000*ns)
|
2015-06-29 10:08:39 +08:00
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
for i in range(1000):
|
2015-07-29 19:42:43 +08:00
|
|
|
self.ttl_out.pulse_mu(dt)
|
2015-07-02 04:34:49 +08:00
|
|
|
delay_mu(dt)
|
2015-06-29 10:08:39 +08:00
|
|
|
except RTIOUnderflow:
|
|
|
|
dt += 1
|
|
|
|
self.core.break_realtime()
|
|
|
|
else:
|
2015-12-16 19:45:57 +08:00
|
|
|
self.set_dataset("pulse_rate", mu_to_seconds(2*dt))
|
2015-06-29 10:08:39 +08:00
|
|
|
break
|
|
|
|
|
2015-06-26 12:19:11 +08:00
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class Watchdog(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
2015-07-05 10:35:02 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
|
|
|
with watchdog(50*ms):
|
|
|
|
while True:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class LoopbackCount(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("ttl_inout")
|
|
|
|
self.setattr_argument("npulses")
|
2015-07-05 10:35:02 +08:00
|
|
|
|
2015-07-14 04:22:26 +08:00
|
|
|
def set_count(self, count):
|
2015-10-12 19:20:04 +08:00
|
|
|
self.set_dataset("count", count)
|
2015-07-05 10:35:02 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
|
|
|
self.ttl_inout.output()
|
2015-07-29 06:17:23 +08:00
|
|
|
delay(5*us)
|
2015-07-05 10:35:02 +08:00
|
|
|
with parallel:
|
|
|
|
self.ttl_inout.gate_rising(10*us)
|
|
|
|
with sequential:
|
|
|
|
for i in range(self.npulses):
|
|
|
|
delay(25*ns)
|
|
|
|
self.ttl_inout.pulse(25*ns)
|
2015-12-16 19:45:57 +08:00
|
|
|
self.set_dataset("count", self.ttl_inout.count())
|
2015-07-05 10:35:02 +08:00
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class Underflow(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("ttl_out")
|
2015-07-05 10:35:02 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
|
|
|
while True:
|
|
|
|
delay(25*ns)
|
|
|
|
self.ttl_out.pulse(25*ns)
|
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class SequenceError(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("ttl_out")
|
2015-07-05 10:35:02 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
|
|
|
t = now_mu()
|
|
|
|
self.ttl_out.pulse(25*us)
|
|
|
|
at_mu(t)
|
|
|
|
self.ttl_out.pulse(25*us)
|
|
|
|
|
|
|
|
|
2015-07-29 19:43:35 +08:00
|
|
|
class CollisionError(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
|
|
|
self.setattr_device("ttl_out_serdes")
|
2015-07-29 19:43:35 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
|
|
|
delay(5*ms) # make sure we won't get underflow
|
|
|
|
for i in range(16):
|
|
|
|
self.ttl_out_serdes.pulse_mu(1)
|
|
|
|
delay_mu(1)
|
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class TimeKeepsRunning(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
2015-07-07 21:29:38 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def run(self):
|
2015-12-16 19:45:57 +08:00
|
|
|
self.set_dataset("time_at_start", now_mu())
|
2015-07-07 21:29:38 +08:00
|
|
|
|
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class Handover(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
2015-07-07 21:29:38 +08:00
|
|
|
|
|
|
|
@kernel
|
2015-12-16 19:45:57 +08:00
|
|
|
def k(self, var):
|
|
|
|
self.set_dataset(var, now_mu())
|
|
|
|
delay_mu(1234)
|
2015-07-07 21:29:38 +08:00
|
|
|
|
|
|
|
def run(self):
|
2015-12-16 19:45:57 +08:00
|
|
|
self.k("t1")
|
|
|
|
self.k("t2")
|
2015-07-07 21:29:38 +08:00
|
|
|
|
|
|
|
|
2015-06-29 10:08:39 +08:00
|
|
|
class CoredeviceTest(ExperimentCase):
|
2015-06-26 12:19:11 +08:00
|
|
|
def test_rtt(self):
|
2015-07-05 10:05:11 +08:00
|
|
|
self.execute(RTT)
|
2015-10-12 19:20:04 +08:00
|
|
|
rtt = self.dataset_mgr.get("rtt")
|
2015-06-29 10:08:39 +08:00
|
|
|
print(rtt)
|
2015-06-26 12:19:11 +08:00
|
|
|
self.assertGreater(rtt, 0*ns)
|
2015-06-29 10:08:39 +08:00
|
|
|
self.assertLess(rtt, 100*ns)
|
2015-06-26 12:19:11 +08:00
|
|
|
|
2015-06-29 10:08:39 +08:00
|
|
|
def test_loopback(self):
|
2015-07-05 10:05:11 +08:00
|
|
|
self.execute(Loopback)
|
2015-10-12 19:20:04 +08:00
|
|
|
rtt = self.dataset_mgr.get("rtt")
|
2015-06-29 10:08:39 +08:00
|
|
|
print(rtt)
|
|
|
|
self.assertGreater(rtt, 0*ns)
|
2015-07-05 00:35:11 +08:00
|
|
|
self.assertLess(rtt, 50*ns)
|
2015-06-26 12:19:11 +08:00
|
|
|
|
2015-07-05 00:36:01 +08:00
|
|
|
def test_clock_generator_loopback(self):
|
2015-07-05 10:05:11 +08:00
|
|
|
self.execute(ClockGeneratorLoopback)
|
2015-10-12 19:20:04 +08:00
|
|
|
count = self.dataset_mgr.get("count")
|
2015-07-05 00:36:01 +08:00
|
|
|
self.assertEqual(count, 10)
|
|
|
|
|
2015-06-29 10:08:39 +08:00
|
|
|
def test_pulse_rate(self):
|
2015-07-05 10:05:11 +08:00
|
|
|
self.execute(PulseRate)
|
2015-10-12 19:20:04 +08:00
|
|
|
rate = self.dataset_mgr.get("pulse_rate")
|
2015-06-29 10:08:39 +08:00
|
|
|
print(rate)
|
2015-06-26 12:19:11 +08:00
|
|
|
self.assertGreater(rate, 100*ns)
|
2015-06-29 10:08:39 +08:00
|
|
|
self.assertLess(rate, 2500*ns)
|
|
|
|
|
2015-07-05 10:35:02 +08:00
|
|
|
def test_loopback_count(self):
|
|
|
|
npulses = 2
|
2015-07-29 19:43:35 +08:00
|
|
|
self.execute(LoopbackCount, npulses=npulses)
|
2015-10-12 19:20:04 +08:00
|
|
|
count = self.dataset_mgr.get("count")
|
2015-07-14 04:08:20 +08:00
|
|
|
self.assertEqual(count, npulses)
|
2015-07-05 10:35:02 +08:00
|
|
|
|
|
|
|
def test_underflow(self):
|
2015-09-01 13:34:28 +08:00
|
|
|
with self.assertRaises(RTIOUnderflow):
|
2015-07-05 10:35:02 +08:00
|
|
|
self.execute(Underflow)
|
|
|
|
|
|
|
|
def test_sequence_error(self):
|
2015-09-01 13:34:28 +08:00
|
|
|
with self.assertRaises(RTIOSequenceError):
|
2015-07-05 10:35:02 +08:00
|
|
|
self.execute(SequenceError)
|
|
|
|
|
2015-07-29 19:43:35 +08:00
|
|
|
def test_collision_error(self):
|
|
|
|
with self.assertRaises(runtime_exceptions.RTIOCollisionError):
|
|
|
|
self.execute(CollisionError)
|
|
|
|
|
2015-07-05 10:35:02 +08:00
|
|
|
def test_watchdog(self):
|
|
|
|
# watchdog only works on the device
|
|
|
|
with self.assertRaises(IOError):
|
|
|
|
self.execute(Watchdog)
|
|
|
|
|
2015-07-07 21:29:38 +08:00
|
|
|
def test_time_keeps_running(self):
|
|
|
|
self.execute(TimeKeepsRunning)
|
2015-10-12 19:20:04 +08:00
|
|
|
t1 = self.dataset_mgr.get("time_at_start")
|
2015-07-07 21:29:38 +08:00
|
|
|
self.execute(TimeKeepsRunning)
|
2015-10-12 19:20:04 +08:00
|
|
|
t2 = self.dataset_mgr.get("time_at_start")
|
|
|
|
dead_time = mu_to_seconds(t2 - t1, self.device_mgr.get("core"))
|
2015-07-07 21:48:47 +08:00
|
|
|
print(dead_time)
|
|
|
|
self.assertGreater(dead_time, 1*ms)
|
2015-09-01 13:34:28 +08:00
|
|
|
self.assertLess(dead_time, 500*ms)
|
2015-07-07 21:29:38 +08:00
|
|
|
|
|
|
|
def test_handover(self):
|
|
|
|
self.execute(Handover)
|
2015-12-16 19:45:57 +08:00
|
|
|
self.assertEqual(self.dataset_mgr.get("t1") + 1234,
|
2015-10-12 19:20:04 +08:00
|
|
|
self.dataset_mgr.get("t2"))
|
2015-07-07 21:29:38 +08:00
|
|
|
|
2015-06-29 10:08:39 +08:00
|
|
|
|
2015-07-14 04:08:20 +08:00
|
|
|
class RPCTiming(EnvExperiment):
|
|
|
|
def build(self):
|
2015-10-04 00:18:21 +08:00
|
|
|
self.setattr_device("core")
|
2015-12-16 19:45:57 +08:00
|
|
|
self.setattr_argument("repeats", PYONValue(100))
|
2015-06-29 10:08:39 +08:00
|
|
|
|
2015-09-01 22:38:53 +08:00
|
|
|
def nop(self):
|
2015-06-29 10:08:39 +08:00
|
|
|
pass
|
|
|
|
|
|
|
|
@kernel
|
|
|
|
def bench(self):
|
|
|
|
for i in range(self.repeats):
|
2015-07-02 04:34:49 +08:00
|
|
|
t1 = self.core.get_rtio_counter_mu()
|
2015-09-01 22:38:53 +08:00
|
|
|
self.nop()
|
2015-07-02 04:34:49 +08:00
|
|
|
t2 = self.core.get_rtio_counter_mu()
|
|
|
|
self.ts[i] = mu_to_seconds(t2 - t1)
|
2015-06-29 10:08:39 +08:00
|
|
|
|
|
|
|
def run(self):
|
2015-09-01 13:34:28 +08:00
|
|
|
self.ts = [0. for _ in range(self.repeats)]
|
2015-06-29 10:08:39 +08:00
|
|
|
self.bench()
|
|
|
|
mean = sum(self.ts)/self.repeats
|
2015-10-12 19:20:04 +08:00
|
|
|
self.set_dataset("rpc_time_stddev", sqrt(
|
2015-07-14 04:08:20 +08:00
|
|
|
sum([(t - mean)**2 for t in self.ts])/self.repeats))
|
2015-10-12 19:20:04 +08:00
|
|
|
self.set_dataset("rpc_time_mean", mean)
|
2015-06-26 12:19:11 +08:00
|
|
|
|
|
|
|
|
2015-06-29 10:08:39 +08:00
|
|
|
class RPCTest(ExperimentCase):
|
|
|
|
def test_rpc_timing(self):
|
2015-07-05 10:05:11 +08:00
|
|
|
self.execute(RPCTiming)
|
2015-10-12 19:20:04 +08:00
|
|
|
self.assertGreater(self.dataset_mgr.get("rpc_time_mean"), 100*ns)
|
|
|
|
self.assertLess(self.dataset_mgr.get("rpc_time_mean"), 15*ms)
|
|
|
|
self.assertLess(self.dataset_mgr.get("rpc_time_stddev"), 1*ms)
|